gunicorn uvicorn worker.py cómo respetar la configuración de limit_concurrency
FastAPI usa gunicorn para lanzar trabajadores de uvicorn como se describe en https://www.uvicorn.org/settings/
Sin embargo, gunicorn no permite iniciar uvicorn con configuraciones personalizadas como también se menciona en https://github.com/encode/uvicorn/issues/343
El problema sugirió anular config_kwargs en el archivo fuente como https://github.com/encode/uvicorn/blob/master/uvicorn/workers.py
Lo intentamos, pero uvicorn no respeta la configuración limit_concurrency
en varios archivos uvicorn en la fuente:
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,
}
¿Cómo se puede obligar a uvicorn a respetar este entorno? Seguimos recibiendo errores 503 de FastAPI
------- ACTUALIZAR ----------- la configuración de gunicorn --worker-connections 1000
todavía causa 503 al hacer 100 solicitudes paralelas que se distribuyen a muchos trabajadores.
Sin embargo, creo que es un tema un poco más complicado: nuestro punto final de API realiza una gran carga de trabajo, por lo general tarda 5 segundos en completarse.
Prueba de estrés con 2 núcleos, 2 trabajadores:
- A. Más de 100 solicitudes simultáneas, carga pesada de punto final: conexiones de trabajador 1
- B. Más de 100 solicitudes simultáneas, carga pesada de punto final: conexiones de trabajador 1000
- C. Más de 100 solicitudes simultáneas, carga baja de punto final: conexiones de trabajador 1
- D. Más de 100 solicitudes simultáneas, carga baja de punto final - conexiones de trabajador 1000
Ambos experimentos A y B arrojaron 503 respuestas, por lo que asumiendo que la configuración de conexiones de trabajador funciona, demasiadas conexiones simuladas parecen no causar nuestros errores 503.
Estamos desconcertados por este comportamiento, porque esperamos que gunicorn / uvicorn ponga en cola el trabajo y no arroje errores 503.
Respuestas
Del doctor gunicorn
worker-connections
El número máximo de clientes simultáneos.
y de uvicorn doc
limit-concurrency
Número máximo de conexiones o tareas simultáneas que se deben permitir, antes de emitir respuestas HTTP 503.
Según esta información, ambas configuraciones varían haciendo lo mismo. Entonces
uvicorn --limit-concurrency 100 application:demo_app
es casi igual que
gunicorn --worker-connections 100 -k uvicorn.workers.UvicornWorker application:demo_app
Nota: No he hecho ninguna prueba real sobre esto, corríjame si me equivoco.
Además, puede establecer limit-concurrency
(o limit_concurrency
) subclasificando la uvicorn.workers.UvicornWorker
clase
from uvicorn.workers import UvicornWorker
class CustomUvicornWorker(UvicornWorker):
CONFIG_KWARGS = {
"loop": "uvloop",
"http": "httptools",
"limit_concurrency": 100
}
y ahora usa esto CustomUvicornWorker
con el gunicorn
comando como,
gunicorn -k path.to.custom_worker.CustomUvicornWorker application:demo_app
Nota: puede inspeccionar self.config.limit_concurrency
en CustomUvicornWorker
clase para asegurarse de que el valor se haya establecido correctamente.