3
2

More than 5 years have passed since last update.

uWSGIでStatsが見られるようにしたい

Last updated at Posted at 2019-05-13

TL;DR

  • uWSGIでサーバーの状態(Stats)を見るには、uWSGI Stats Serverを使えばよい
  • uwsgiの起動オプションとして設定すれば、利用可能
  • データはソケット(HTTP含む)で取得できる
  • ただし、取得できる項目がどういった意味なのかは特にドキュメンテーションされていない様子…
    • ソースコードを見て把握するしかなさそう

モチベーション

uWSGIを使ってアプリケーションをデプロイ、公開する際に、uWSGIからメトリクスを取得したい、というのが動機です。

The uWSGI Stats Server

で、ページを見つけたはいいものの、取得できる項目のサンプルはありますが、それがどういう意味家はドキュメントには見当たらず、日本語情報もなさそうです…。

といって、このページでそれを解説するわけでもないのですが。

そもそも、uWSGIでメトリクスを取得するには?

前述のドキュメントに記載してある、Stats Serverを使う方法と

The uWSGI Stats Server

Metrics subsystemを使ってプラグインを書く方法があるようです。

The Metrics subsystem

たとえば、DatadogはこのMetrics subsystemを使って、取得したメトリクスをDatadogに送信するプラグインを作成しています。

uwsgi-dogstatsd

ええ、C言語で書かれていますね…。

今回は、簡単にメトリクスを取得できるStats Serverを使用します。

環境

今回は、こちらの環境で確認します。

$ python3 -V
Python 3.6.7


$ uwsgi --version
2.0.18

Stats Serverを有効にする

今回のuWSGIのメトリクスを取得するにあたって、特に「処理中のリクエスト数(多重度)」を知りたいという要求があったので、以下のようにちょっとスリープを入れるWSGIスクリプトを用意しました。

app.py

import time

def application(env, start_response):
    print('waiting...')
    time.sleep(10)

    start_response('200 OK', [('Content-Type', 'text/plain')])
    return [b'Hello WSGI!!']

こちらを使って、uWSGIを起動します。

$ uwsgi --http :8000 --stats :9000 --wsgi-file app.py

これで、通常のHTTPリクエストは8000ポートで受け付け、Statsは9000ポートで取得できるようになっています。

ドキュメントを見ていると、他にUnixドメインソケットも利用できそうな感じですね。

--stats 127.0.0.1:1717
--stats /tmp/statsock
--stats :5050
--stats @foobar
# Any of the above socket types can also return stats using HTTP
--stats 127.0.0.1:1717 --stats-http

確認してみましょう。先程の起動方法ではTCP待ち受けるようにStats Serverを起動しているので、ncコマンドで確認します。

$ nc localhost 9000
{
    "version":"2.0.18",
    "listen_queue":0,
    "listen_queue_errors":0,
    "signal_queue":0,
    "load":0,
    "pid":92625,
    "uid":1000,
    "gid":1000,
    "cwd":"/path",
    "locks":[
        {
            "user 0":0
        },
        {
            "signal":0
        },
        {
            "filemon":0
        },
        {
            "timer":0
        },
        {
            "rbtimer":0
        },
        {
            "cron":0
        },
        {
            "rpc":0
        },
        {
            "snmp":0
        }
    ],
    "sockets":[
        {
            "name":"127.0.0.1:46175",
            "proto":"uwsgi",
            "queue":0,
            "max_queue":100,
            "shared":0,
            "can_offload":0
        }
    ],
    "workers":[
        {
            "id":1,
            "pid":92626,
            "accepting":1,
            "requests":0,
            "delta_requests":0,
            "exceptions":0,
            "harakiri_count":0,
            "signals":0,
            "signal_queue":0,
            "status":"idle",
            "rss":0,
            "vsz":0,
            "running_time":0,
            "last_spawn":1557739876,
            "respawn_count":1,
            "tx":0,
            "avg_rt":0,
            "apps":[
                {
                    "id":0,
                    "modifier1":0,
                    "mountpoint":"",
                    "startup_time":0,
                    "requests":0,
                    "exceptions":0,
                    "chdir":""
                }
            ],
            "cores":[
                {
                    "id":0,
                    "requests":0,
                    "static_requests":0,
                    "routed_requests":0,
                    "offloaded_requests":0,
                    "write_errors":0,
                    "read_errors":0,
                    "in_request":0,
                    "vars":[

                    ],
                    "req_info":                 {

                    }
                }
            ]
        }
    ]
}

こんな感じで情報が取得できました。

ちなみに、HTTPで取得したい場合は--stats-httpを付与します。

$ uwsgi --http :8000 --stats :9000 --stats-http --wsgi-file app.py 

これで、curlなどで取得できるようになります。

$ curl localhost:9000
{
    "version":"2.0.18",
    "listen_queue":0,
    "listen_queue_errors":0,
    "signal_queue":0,
    "load":0,
    "pid":92775,
    "uid":1000,
    "gid":1000,
    "cwd":"/home/ippei/projects/charon/IdeaProjects/uwsgi-stats",
    "locks":[
        {
            "user 0":0
        },
        {
            "signal":0
        },
        {
            "filemon":0
        },
        {
            "timer":0
        },
        {
            "rbtimer":0
        },
        {
            "cron":0
        },
        {
            "rpc":0
        },
        {
            "snmp":0
        }
    ],
    "sockets":[
        {
            "name":"127.0.0.1:41235",
            "proto":"uwsgi",
            "queue":0,
            "max_queue":100,
            "shared":0,
            "can_offload":0
        }
    ],
    "workers":[
        {
            "id":1,
            "pid":92776,
            "accepting":1,
            "requests":0,
            "delta_requests":0,
            "exceptions":0,
            "harakiri_count":0,
            "signals":0,
            "signal_queue":0,
            "status":"idle",
            "rss":0,
            "vsz":0,
            "running_time":0,
            "last_spawn":1557740070,
            "respawn_count":1,
            "tx":0,
            "avg_rt":0,
            "apps":[
                {
                    "id":0,
                    "modifier1":0,
                    "mountpoint":"",
                    "startup_time":0,
                    "requests":0,
                    "exceptions":0,
                    "chdir":""
                }
            ],
            "cores":[
                {
                    "id":0,
                    "requests":0,
                    "static_requests":0,
                    $ curl localhost:9000
{
    "version":"2.0.18",
    "listen_queue":0,
    "listen_queue_errors":0,
    "signal_queue":0,
    "load":0,
    "pid":92775,
    "uid":1000,
    "gid":1000,
    "cwd":"/path",
    "locks":[
        {
            "user 0":0
        },
        {
            "signal":0
        },
        {
            "filemon":0
        },
        {
            "timer":0
        },
        {
            "rbtimer":0
        },
        {
            "cron":0
        },
        {
            "rpc":0
        },
        {
            "snmp":0
        }
    ],
    "sockets":[
        {
            "name":"127.0.0.1:41235",
            "proto":"uwsgi",
            "queue":0,
            "max_queue":100,
            "shared":0,
            "can_offload":0
        }
    ],
    "workers":[
        {
            "id":1,
            "pid":92776,
            "accepting":1,
            "requests":0,
            "delta_requests":0,
            "exceptions":0,
            "harakiri_count":0,
            "signals":0,
            "signal_queue":0,
            "status":"idle",
            "rss":0,
            "vsz":0,
            "running_time":0,
            "last_spawn":1557740070,
            "respawn_count":1,
            "tx":0,
            "avg_rt":0,
            "apps":[
                {
                    "id":0,
                    "modifier1":0,
                    "mountpoint":"",
                    "startup_time":0,
                    "requests":0,
                    "exceptions":0,
                    "chdir":""
                }
            ],
            "cores":[
                {
                    "id":0,
                    "requests":0,
                    "static_requests":0,
                    "routed_requests":0,
                    "offloaded_requests":0,
                    "write_errors":0,
                    "read_errors":0,
                    "in_request":0,
                    "vars":[

                    ],
                    "req_info":                 {

                    }
                }
            ]
        }
    ]
}"routed_requests":0,
                    "offloaded_requests":0,
                    "write_errors":0,
                    "read_errors":0,
                    "in_request":0,
                    "vars":[

                    ],
                    "req_info":                 {

                    }
                }
            ]
        }
    ]
}

今回は、このまま--stats-httpを付けたままにしましょう。

ちょっと簡易的に、curlをバックグラウンドで動かして5回連続してリクエストを投げてみます。

$ curl localhost:8000 &
$ curl localhost:8000 &
$ curl localhost:8000 &
$ curl localhost:8000 &
$ curl localhost:8000 &

この待っている間に、Statsを取得してみます。

$ curl localhost:9000
{
    "version":"2.0.18",
    "listen_queue":4,
    "listen_queue_errors":0,
    "signal_queue":0,
    "load":4,
    "pid":92775,
    "uid":1000,
    "gid":1000,
    "cwd":"/path",
    "locks":[
        {
            "user 0":0
        },
        {
            "signal":0
        },
        {
            "filemon":0
        },
        {
            "timer":0
        },
        {
            "rbtimer":0
        },
        {
            "cron":0
        },
        {
            "rpc":0
        },
        {
            "snmp":0
        }
    ],
    "sockets":[
        {
            "name":"127.0.0.1:41235",
            "proto":"uwsgi",
            "queue":4,
            "max_queue":100,
            "shared":0,
            "can_offload":0
        }
    ],
    "workers":[
        {
            "id":1,
            "pid":92776,
            "accepting":1,
            "requests":9,
            "delta_requests":9,
            "exceptions":0,
            "harakiri_count":0,
            "signals":0,
            "signal_queue":0,
            "status":"busy",
            "rss":0,
            "vsz":0,
            "running_time":90069190,
            "last_spawn":1557740070,
            "respawn_count":1,
            "tx":513,
            "avg_rt":9986221,
            "apps":[
                {
                    "id":0,
                    "modifier1":0,
                    "mountpoint":"",
                    "startup_time":0,
                    "requests":10,
                    "exceptions":0,
                    "chdir":""
                }
            ],
            "cores":[
                {
                    "id":0,
                    "requests":9,
                    "static_requests":0,
                    "routed_requests":0,
                    "offloaded_requests":0,
                    "write_errors":0,
                    "read_errors":0,
                    "in_request":1,
                    "vars":[
"REQUEST_METHOD=GET",
"REQUEST_URI=/",
"PATH_INFO=/",
"QUERY_STRING=",
"SERVER_PROTOCOL=HTTP/1.1",
"SCRIPT_NAME=",
"SERVER_NAME=myserver",
"SERVER_PORT=8000",
"UWSGI_ROUTER=http",
"REMOTE_ADDR=127.0.0.1",
"REMOTE_PORT=60051",
"HTTP_HOST=localhost:8000",
"HTTP_USER_AGENT=curl/7.58.0",
"HTTP_ACCEPT=*/*",
""
                    ],
                    "req_info":                 {
                        "request_start":1557740273
                    }
                }
            ]
        }
    ]
}

listen_queueが4で

    "listen_queue":4,

in_requestが1なので

                    "in_request":1,

現在リクエストを処理していて、待っているのが4つということがわかります。

ちなみに、このin_requestの1は、数ではなく意味的にはbooleanっぽいです…。

今回は、スレッド数もなにもチューニングしていないですから、待ちが多いですね…。

ここで、プロセス数を2、スレッド数を2にしてみましょう。

$ uwsgi --http :8000 --stats :9000 --stats-http --master --processes 2 --threads 2 --wsgi-file app.py 

同じように、リクエストを投げてみます。

$ curl localhost:8000 &
$ curl localhost:8000 &
$ curl localhost:8000 &
$ curl localhost:8000 &
$ curl localhost:8000 &

Statsを取得してみましょう。workersと配下のcoresが増え、4つまで同時にリクエストを処理できるようになっています。

$ curl localhost:9000
{
    "version":"2.0.18",
    "listen_queue":1,
    "listen_queue_errors":0,
    "signal_queue":0,
    "load":1,
    "pid":93145,
    "uid":1000,
    "gid":1000,
    "cwd":"/path",
    "locks":[
        {
            "user 0":0
        },
        {
            "signal":0
        },
        {
            "filemon":0
        },
        {
            "timer":0
        },
        {
            "rbtimer":0
        },
        {
            "cron":0
        },
        {
            "rpc":0
        },
        {
            "snmp":0
        }
    ],
    "sockets":[
        {
            "name":"127.0.0.1:43177",
            "proto":"uwsgi",
            "queue":1,
            "max_queue":100,
            "shared":0,
            "can_offload":0
        }
    ],
    "workers":[
        {
            "id":1,
            "pid":93146,
            "accepting":1,
            "requests":0,
            "delta_requests":0,
            "exceptions":0,
            "harakiri_count":0,
            "signals":0,
            "signal_queue":0,
            "status":"busy",
            "rss":0,
            "vsz":0,
            "running_time":0,
            "last_spawn":1557740578,
            "respawn_count":1,
            "tx":0,
            "avg_rt":0,
            "apps":[
                {
                    "id":0,
                    "modifier1":0,
                    "mountpoint":"",
                    "startup_time":0,
                    "requests":2,
                    "exceptions":0,
                    "chdir":""
                }
            ],
            "cores":[
                {
                    "id":0,
                    "requests":0,
                    "static_requests":0,
                    "routed_requests":0,
                    "offloaded_requests":0,
                    "write_errors":0,
                    "read_errors":0,
                    "in_request":1,
                    "vars":[
"REQUEST_METHOD=GET",
"REQUEST_URI=/",
"PATH_INFO=/",
"QUERY_STRING=",
"SERVER_PROTOCOL=HTTP/1.1",
"SCRIPT_NAME=",
"SERVER_NAME=myserver",
"SERVER_PORT=8000",
"UWSGI_ROUTER=http",
"REMOTE_ADDR=127.0.0.1",
"REMOTE_PORT=55956",
"HTTP_HOST=localhost:8000",
"HTTP_USER_AGENT=curl/7.58.0",
"HTTP_ACCEPT=*/*",
""
                    ],
                    "req_info":                 {
                        "request_start":1557740581
                    }
                },
                {
                    "id":1,
                    "requests":0,
                    "static_requests":0,
                    "routed_requests":0,
                    "offloaded_requests":0,
                    "write_errors":0,
                    "read_errors":0,
                    "in_request":1,
                    "vars":[
"REQUEST_METHOD=GET",
"REQUEST_URI=/",
"PATH_INFO=/",
"QUERY_STRING=",
"SERVER_PROTOCOL=HTTP/1.1",
"SCRIPT_NAME=",
"SERVER_NAME=myserver",
"SERVER_PORT=8000",
"UWSGI_ROUTER=http",
"REMOTE_ADDR=127.0.0.1",
"REMOTE_PORT=56980",
"HTTP_HOST=localhost:8000",
"HTTP_USER_AGENT=curl/7.58.0",
"HTTP_ACCEPT=*/*",
""
                    ],
                    "req_info":                 {
                        "request_start":1557740582
                    }
                }
            ]
        },
        {
            "id":2,
            "pid":93147,
            "accepting":1,
            "requests":0,
            "delta_requests":0,
            "exceptions":0,
            "harakiri_count":0,
            "signals":0,
            "signal_queue":0,
            "status":"busy",
            "rss":0,
            "vsz":0,
            "running_time":0,
            "last_spawn":1557740578,
            "respawn_count":1,
            "tx":0,
            "avg_rt":0,
            "apps":[
                {
                    "id":0,
                    "modifier1":0,
                    "mountpoint":"",
                    "startup_time":0,
                    "requests":2,
                    "exceptions":0,
                    "chdir":""
                }
            ],
            "cores":[
                {
                    "id":0,
                    "requests":0,
                    "static_requests":0,
                    "routed_requests":0,
                    "offloaded_requests":0,
                    "write_errors":0,
                    "read_errors":0,
                    "in_request":1,
                    "vars":[
"REQUEST_METHOD=GET",
"REQUEST_URI=/",
"PATH_INFO=/",
"QUERY_STRING=",
"SERVER_PROTOCOL=HTTP/1.1",
"SCRIPT_NAME=",
"SERVER_NAME=myserver",
"SERVER_PORT=8000",
"UWSGI_ROUTER=http",
"REMOTE_ADDR=127.0.0.1",
"REMOTE_PORT=54932",
"HTTP_HOST=localhost:8000",
"HTTP_USER_AGENT=curl/7.58.0",
"HTTP_ACCEPT=*/*",
""
                    ],
                    "req_info":                 {
                        "request_start":1557740581
                    }
                },
                {
                    "id":1,
                    "requests":0,
                    "static_requests":0,
                    "routed_requests":0,
                    "offloaded_requests":0,
                    "write_errors":0,
                    "read_errors":0,
                    "in_request":1,
                    "vars":[
"REQUEST_METHOD=GET",
"REQUEST_URI=/",
"PATH_INFO=/",
"QUERY_STRING=",
"SERVER_PROTOCOL=HTTP/1.1",
"SCRIPT_NAME=",
"SERVER_NAME=myserver",
"SERVER_PORT=8000",
"UWSGI_ROUTER=http",
"REMOTE_ADDR=127.0.0.1",
"REMOTE_PORT=58004",
"HTTP_HOST=localhost:8000",
"HTTP_USER_AGENT=curl/7.58.0",
"HTTP_ACCEPT=*/*",
""
                    ],
                    "req_info":                 {
                        "request_start":1557740582
                    }
                }
            ]
        }
    ]
}

今度は、キューが1になります。

    "listen_queue":1,

こんな感じで挙動を見つつ、ソースコードを見つつ、Statsを把握していくのだと思います。

大変。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2