Gunicorn uvicorn worker.py 如何遵守 limit_concurrency 设置

use*_*186 13 concurrency gunicorn fastapi uvicorn concurrency-limits

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

limit_concurrency我们尝试过,但 uvicorn 不遵守源中多个 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,
        }

Run Code Online (Sandbox Code Playgroud)

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,
    }

Run Code Online (Sandbox Code Playgroud)

uvicorn 如何才能被迫遵守这一设置?我们仍然从 FastAPI 收到 503 错误

--worker-connections 1000--------更新----------当发出 100 个分发给许多工作人员的并行请求时,gunicorn 设置仍然会导致 503。

然而,我认为这是一个更复杂的问题:我们的 API 端点会做很多繁重的工作,通常需要 5 秒才能完成。

2核2worker压力测试:

  • A. 100+并发请求,端点负载重 --worker-connections 1
  • B. 100+并发请求,端点负载重 --worker-connections 1000
  • C. 100+并发请求,端点低负载 --worker-connections 1
  • D. 100+并发请求,端点低负载--worker-connections 1000

实验 A 和 B 都产生了 503 响应,因此假设工作连接设置确实有效,太多的模拟连接似乎不会导致我们的 503 错误。

我们对这种行为感到困惑,因为我们希望gunicorn/uvicorn 能够对工作进行排队并且不会抛出 503 错误。

JPG*_*JPG 10

来自Gunicorn 文档

worker-connections

同时客户端的最大数量。

和来自uvicorn 文档

limit-concurrency

在发出 HTTP 503 响应之前允许的最大并发连接或任务数。

根据此信息,这两个设置变量执行相同的操作。所以

uvicorn --limit-concurrency 100 application:demo_app
Run Code Online (Sandbox Code Playgroud)

几乎与

gunicorn --worker-connections 100 -k uvicorn.workers.UvicornWorker application:demo_app
Run Code Online (Sandbox Code Playgroud)

注:我没有对此做过任何实际测试,如果我错了,请纠正我。


另外,您可以通过对类进行子类化来设置limit-concurrency(或limit_concurrencyuvicorn.workers.UvicornWorker

from uvicorn.workers import UvicornWorker


class CustomUvicornWorker(UvicornWorker):
    CONFIG_KWARGS = {
        "loop": "uvloop",
        "http": "httptools",
        "limit_concurrency": 100
    }
Run Code Online (Sandbox Code Playgroud)

现在将其CustomUvicornWorkergunicorn命令一起使用,

gunicorn -k path.to.custom_worker.CustomUvicornWorker application:demo_app
Run Code Online (Sandbox Code Playgroud)

注意:您可以self.config.limit_concurrencyCustomUvicornWorker课堂上检查以确保该值已正确设置。

  • 你解决了吗? (4认同)
  • 对于具有 uvicorn 类的 Gunicorn,worker-connections 对每个文档没有影响 https://docs.gunicorn.org/en/stable/settings.html#worker-connections 同时客户端的最大数量。此设置仅影响 gthread、eventlet 和 gevent 工作线程类型。 (3认同)