gunicorn uvicorn worker.py comment honorer le paramètre limit_concurrency

Aug 19 2020

FastAPI utilise gunicorn pour lancer des workers uvicorn comme décrit dans https://www.uvicorn.org/settings/

Cependant, gunicorn ne permet pas de lancer uvicorn avec des paramètres personnalisés comme également mentionné dans https://github.com/encode/uvicorn/issues/343

Le problème a suggéré de remplacer les config_kwargs dans le fichier source comme https://github.com/encode/uvicorn/blob/master/uvicorn/workers.py

Nous l'avons essayé mais uvicorn n'honore pas le paramètre limit_concurrencydans plusieurs fichiers uvicorn dans la source:

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

Comment uvicorn peut-il être obligé d'honorer ce paramètre? Nous recevons toujours 503 erreurs de FastAPI

------- MISE À JOUR ----------- le paramètre gunicorn --worker-connections 1000provoque toujours 503 lors de 100 requêtes parallèles qui sont distribuées à de nombreux travailleurs.

Cependant, je pense que c'est un problème un peu plus compliqué: notre point de terminaison d'API fait beaucoup de travail lourd, prend généralement 5 secondes.

Test de résistance avec 2 cœurs, 2 travailleurs:

  • A. Plus de 100 demandes simultanées, forte charge de point final - connexions-travailleurs 1
  • Plus de 100 requêtes simultanées, forte charge de point final - connexions-travailleurs 1000
  • C.Plus de 100 requêtes simultanées, faible charge du point final - connexions-travailleurs 1
  • D.Plus de 100 demandes simultanées, faible charge du point final - connexions-travailleurs 1000

Les deux expériences A et B ont donné 503 réponses, donc en supposant que le paramètre de connexions de travail fonctionne, trop de connexions simulées semblent ne pas causer nos 503 erreurs.

Nous sommes déconcertés par ce comportement, car nous nous attendons à ce que gunicorn / uvicorn fasse la queue le travail et ne génère pas d'erreurs 503.

Réponses

2 JPG Aug 19 2020 at 11:57

De la doc gunicorn

worker-connections

Le nombre maximum de clients simultanés.

et de uvicorn doc

limit-concurrency

Nombre maximum de connexions ou de tâches simultanées à autoriser, avant d'émettre des réponses HTTP 503.

Selon cette information, les deux paramètres variables font la même chose. Alors

uvicorn --limit-concurrency 100 application:demo_app

est presque le même que

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

Remarque: je n'ai pas fait de vrai test à ce sujet, veuillez me corriger si je me trompe.


En outre, vous pouvez définir limit-concurrency(ou limit_concurrency) en sous-classant la uvicorn.workers.UvicornWorkerclasse

from uvicorn.workers import UvicornWorker


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

et utilisez maintenant ceci CustomUvicornWorkeravec la gunicorncommande comme,

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

Remarque: vous pouvez inspecter self.config.limit_concurrencyen CustomUvicornWorkerclasse pour vous assurer que la valeur a été correctement définie.