gunicorn uvicorn worker.py как соблюдать настройку limit_concurrency
FastAPI использует gunicorn для запуска uvicorn worker, как описано в 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 соблюдать эту настройку? Мы все еще получаем 503 ошибки от FastAPI
------- ОБНОВЛЕНИЕ ----------- настройка пулемета по- --worker-connections 1000
прежнему вызывает 503 при выполнении 100 параллельных запросов, которые распределяются между множеством рабочих.
Однако я считаю, что это немного более сложная проблема: наша конечная точка API выполняет много тяжелой рабочей нагрузки, обычно на выполнение требуется 5 секунд.
Стресс-тест с 2 ядрами, 2 рабочими:
- A. 100+ одновременных запросов, большая нагрузка на конечную точку - рабочие-соединения 1
- Б. 100+ одновременных запросов, высокая нагрузка на конечную точку - рабочие-соединения 1000
- C. 100+ одновременных запросов, низкая нагрузка на конечную точку - рабочие-соединения 1
- D. Более 100 одновременных запросов, низкая нагрузка на конечную точку - рабочие-соединения 1000
Оба эксперимента A и B дали 503 ответа, поэтому, если предположить, что настройка рабочих соединений действительно работает, слишком много имитирующих соединений, похоже, не вызывают наших ошибок 503.
Мы озадачены таким поведением, потому что ожидаем, что gunicorn / uvicorn поставит работу в очередь и не выдаст 503 ошибки.
Ответы
Из документа Gunicorn
worker-connections
Максимальное количество одновременных клиентов.
и из uvicorn doc
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
}
и теперь используйте это CustomUvicornWorker
с gunicorn
командой как,
gunicorn -k path.to.custom_worker.CustomUvicornWorker application:demo_app
Примечание: вы можете проверить self.config.limit_concurrency
в CustomUvicornWorker
классе, чтобы убедиться, что значение установлено правильно.