gunicorn uvicorn worker.py como respeitar a configuração limit_concurrency
FastAPI usa gunicorn para lançar trabalhadores uvicorn conforme descrito em https://www.uvicorn.org/settings/
No entanto, o gunicorn não permite iniciar o uvicorn com configurações personalizadas, como também mencionado em https://github.com/encode/uvicorn/issues/343
O problema sugeriu substituir o config_kwargs no arquivo de origem, como https://github.com/encode/uvicorn/blob/master/uvicorn/workers.py
Nós tentamos, mas o uvicorn não está honrando a configuração limit_concurrency
de vários arquivos uvicorn na fonte:
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,
}
Como o uvicórnio pode ser forçado a honrar esse cenário? Ainda estamos recebendo erros 503 da FastAPI
------- ATUALIZAÇÃO ----------- a configuração do gunicorn --worker-connections 1000
ainda causa 503 ao fazer 100 solicitações paralelas que são distribuídas para muitos trabalhadores.
No entanto, acredito que seja um problema um pouco mais complicado: nosso endpoint de API faz uma grande carga de trabalho, geralmente leva 5 segundos para ser concluído.
Teste de estresse com 2 núcleos, 2 trabalhadores:
- A. Mais de 100 solicitações simultâneas, carga pesada de endpoint --worker-connections 1
- B. Mais de 100 solicitações simultâneas, carga pesada de endpoint --worker-connections 1000
- C. Mais de 100 solicitações simultâneas, carga baixa de endpoint - conexões de trabalho 1
- D. Mais de 100 solicitações simultâneas, baixa carga de endpoint --worker-connections 1000
Ambos os experimentos A e B produziram 503 respostas, portanto, supondo que a configuração de conexões de trabalho funcione, muitas conexões simultâneas parecem não causar nossos erros 503.
Estamos intrigados com esse comportamento, porque esperamos que gunicorn / uvicorn enfileire o trabalho e não gere erros 503.
Respostas
Do gunicorn doc
worker-connections
O número máximo de clientes simultâneos.
e do uvicorn doc
limit-concurrency
Número máximo de conexões ou tarefas simultâneas permitidas, antes de emitir respostas HTTP 503.
De acordo com esta informação, ambas as configurações variam fazendo a mesma coisa. então
uvicorn --limit-concurrency 100 application:demo_app
é quase igual a
gunicorn --worker-connections 100 -k uvicorn.workers.UvicornWorker application:demo_app
Nota: Eu não fiz nenhum teste real sobre isso, por favor, corrija-me se eu estiver errado.
Além disso, você pode definir limit-concurrency
(ou limit_concurrency
) criando uma subclasse da uvicorn.workers.UvicornWorker
classe
from uvicorn.workers import UvicornWorker
class CustomUvicornWorker(UvicornWorker):
CONFIG_KWARGS = {
"loop": "uvloop",
"http": "httptools",
"limit_concurrency": 100
}
e agora use isso CustomUvicornWorker
com o gunicorn
comando como,
gunicorn -k path.to.custom_worker.CustomUvicornWorker application:demo_app
Observação: você pode inspecionar self.config.limit_concurrency
em CustomUvicornWorker
aula para garantir que o valor foi definido corretamente.