gunicorn uvicornworker.pylimit_concurrency設定を尊重する方法

Aug 19 2020

FastAPIは、gunicornを使用して、説明されているようにuvicornワーカーを起動します。 https://www.uvicorn.org/settings/

ただし、gunicornでは、カスタム設定でuvicornを起動することもできません。 https://github.com/encode/uvicorn/issues/343

この問題は、次のようなソースファイルのconfig_kwargsをオーバーライドすることを提案しました https://github.com/encode/uvicorn/blob/master/uvicorn/workers.py

私たちはそれを試しましたが、uvicornはlimit_concurrencyソース内の複数のuvicornファイルの設定を尊重していません:

https://github.com/encode/uvicorn/blob/master/uvicorn/workers.py

# fail

        config_kwargs = {
            "app": None,
            "log_config": None,
            "timeout_keep_alive": self.cfg.keepalive,
            "timeout_notify": self.timeout,
            "callback_notify": self.callback_notify,
            "limit_max_requests": self.max_requests, "limit_concurrency": 10000,
            "forwarded_allow_ips": self.cfg.forwarded_allow_ips,
        }

https://github.com/encode/uvicorn/blob/master/uvicorn/main.py

# fail

    kwargs = {
        "app": app,
        "host": host,
        "port": port,
        "uds": uds,
        "fd": fd,
        "loop": loop,
        "http": http,
        "ws": ws,
        "lifespan": lifespan,
        "env_file": env_file,
        "log_config": LOGGING_CONFIG if log_config is None else log_config,
        "log_level": log_level,
        "access_log": access_log,
        "interface": interface,
        "debug": debug,
        "reload": reload,
        "reload_dirs": reload_dirs if reload_dirs else None,
        "workers": workers,
        "proxy_headers": proxy_headers,
        "forwarded_allow_ips": forwarded_allow_ips,
        "root_path": root_path,
        "limit_concurrency": 10000,
        "backlog": backlog,
        "limit_max_requests": limit_max_requests,
        "timeout_keep_alive": timeout_keep_alive,
        "ssl_keyfile": ssl_keyfile,
        "ssl_certfile": ssl_certfile,
        "ssl_version": ssl_version,
        "ssl_cert_reqs": ssl_cert_reqs,
        "ssl_ca_certs": ssl_ca_certs,
        "ssl_ciphers": ssl_ciphers,
        "headers": list([header.split(":") for header in headers]),
        "use_colors": use_colors,
    }

uvicornにこの設定を尊重させるにはどうすればよいですか?FastAPIからまだ503エラーが発生しています

------- UPDATE ----------- gunicornの設定--worker-connections 1000では、多くのワーカーに配布される100個の並列要求を行うときに依然として503が発生します。

ただし、これはもう少し複雑な問題だと思います。APIエンドポイントは多くの重いワークロードを実行し、通常、完了するまでに5秒かかります。

2コア、2ワーカーによるストレステスト:

  • A. 100以上の同時リクエスト、エンドポイントの高負荷--worker-connections 1
  • B. 100以上の同時リクエスト、エンドポイントの高負荷--worker-connections 1000
  • C. 100以上の同時リクエスト、エンドポイントの低負荷--worker-connections 1
  • D. 100以上の同時リクエスト、エンドポイントの低負荷--worker-connections 1000

実験AとBの両方で503応答が得られたため、worker-connections設定が機能すると仮定すると、シミュレートされた接続が多すぎても503エラーは発生しないようです。

gunicorn / uvicornが作業をキューに入れ、503エラーをスローしないことを期待しているため、この動作に戸惑っています。

回答

2 JPG Aug 19 2020 at 11:57

gunicornドキュメントから

worker-connections

同時クライアントの最大数。

およびuvicorndocから

limit-concurrency

HTTP 503応答を発行する前に、許可する同時接続またはタスクの最大数。

この情報によると、両方の設定変数は同じことをします。そう

uvicorn --limit-concurrency 100 application:demo_app

とほぼ同じです

gunicorn --worker-connections 100 -k uvicorn.workers.UvicornWorker application:demo_app

注:私はこれについて実際のテストを行っていません。間違っている場合は修正してください。


また、クラスをサブクラス化して設定limit-concurrency(またはlimit_concurrency)することもできますuvicorn.workers.UvicornWorker

from uvicorn.workers import UvicornWorker


class CustomUvicornWorker(UvicornWorker):
    CONFIG_KWARGS = {
        "loop": "uvloop",
        "http": "httptools",
        "limit_concurrency": 100
    }

そして今、これCustomUvicornWorkergunicornコマンドで使用します。

gunicorn -k path.to.custom_worker.CustomUvicornWorker application:demo_app

注:クラスで検査self.config.limit_concurrencyしてCustomUvicornWorker、値が正しく設定されていることを確認できます。