60 votes

Docker/Kubernetes + Gunicorn/Celery - Travailleurs multiples ou répliques ?

Je me demandais quelle était la bonne approche pour déployer une application Django conteneurisée en utilisant gunicorn et celery.

Plus précisément, chacun de ces processus dispose d'une méthode intégrée de mise à l'échelle verticale, en utilisant les éléments suivants workers pour gunicorn et concurrency pour le céleri. Et puis il y a l'approche Kubernetes de la mise à l'échelle en utilisant replicas

Il y a aussi cette notion de fixer des travailleurs égaux à une certaine fonction des CPUs. Gunicorn recommande

2-4 travailleurs par noyau

Cependant, je ne sais pas comment cela se traduit sur les K8 où le CPU est une ressource partagée divisible - à moins que j'utilise resoureceQuotas.

Je veux comprendre quelle est la meilleure pratique. Il y a trois options qui me viennent à l'esprit :

  • Avoir des travailleurs uniques pour gunicorn et une concurrence de 1 pour celery, et les faire évoluer en utilisant les répliques ? (mise à l'échelle horizontale)
  • Faites fonctionner gunicorn et celery dans un déploiement unique de répliques avec une mise à l'échelle interne (mise à l'échelle verticale). Cela implique de définir des valeurs assez élevées pour les travailleurs et la concurrence respectivement.
  • Une approche mixte entre 1 et 2, où nous exécutons gunicorn et celery avec une petite valeur pour les travailleurs et la concurrence, (disons 2), puis utilisons les répliques de K8s Deployment pour évoluer horizontalement.

Il y a quelques questions sur SO à ce sujet, mais aucune n'offre une réponse approfondie/réfléchie. J'apprécierais que quelqu'un partage son expérience.

Note : Nous utilisons la classe de travail par défaut. sync pour Gunicorn

35voto

stacksonstacks Points 2053

Ces technologies ne sont pas aussi similaires qu'il n'y paraît. Elles s'adressent à différentes parties de la pile d'applications et sont en fait complémentaires.

Gunicorn est destiné à mettre à l'échelle la concurrence des requêtes web, tandis que celery doit être considéré comme une file d'attente de travailleurs. Nous aborderons bientôt le sujet de Kubernetes.


Gunicorn

La simultanéité des demandes Web est principalement limitée par les entrées/sorties réseau ou "I/O bound". Ces types de tâches peuvent être mis à l'échelle en utilisant l'ordonnancement coopératif fourni par les threads. Si vous trouvez que la simultanéité des requêtes limite votre application, l'augmentation des threads de gunicorn worker pourrait bien être le point de départ.


Céleri

Les tâches lourdes, comme la compression d'une image ou l'exécution d'un algorithme ML, sont des tâches "liées au processeur". Elles ne peuvent pas bénéficier du threading autant que d'autres CPUs. Ces tâches doivent être déchargées et parallélisées par les travailleurs celery.


Kubernetes

Là où Kubernetes est utile, c'est qu'il offre une extensibilité horizontale et une tolérance aux pannes prêtes à l'emploi.

D'un point de vue architectural, j'utiliserais deux déploiements k8s distincts pour représenter les différentes préoccupations d'évolutivité de votre application. Un déploiement pour l'application Django et un autre pour les travailleurs celery. Cela vous permet de faire évoluer indépendamment le débit des requêtes par rapport à la puissance de traitement.

J'exécute les travailleurs de Celery sur un seul cœur par conteneur ( -c 1 ), ce qui simplifie grandement le débogage et respecte la devise de Docker, à savoir "un processus par conteneur". Elle offre également l'avantage de la prévisibilité, car vous pouvez faire évoluer la puissance de traitement sur une base par cœur en augmentant le nombre de répliques.

La mise à l'échelle du déploiement de l'application Django est le domaine dans lequel vous devrez DYOR pour trouver les meilleurs paramètres pour votre application particulière. Encore une fois, utilisez --workers 1 de sorte qu'il n'y a qu'un seul processus par conteneur mais vous devriez expérimenter avec --threads pour trouver la meilleure solution. Encore une fois, laissez la mise à l'échelle horizontale à Kubernetes en modifiant simplement le nombre de répliques.

HTH C'est certainement quelque chose que j'ai dû comprendre en travaillant sur des projets similaires.

0 votes

Si nous n'avons qu'un seul serveur, pouvons-nous dire qu'il est préférable de compter sur les travailleurs gunicorn et de s'en tenir à un ou deux pods (répliques) ? (Pour éviter la charge de gestion des conteneurs) Merci

32voto

Boris Points 341

Nous exécutons un kluster Kubernetes avec Django et Celery, et avons mis en œuvre la première approche. Je vous livre ici quelques-unes de mes réflexions sur ce compromis et les raisons pour lesquelles nous avons opté pour cette approche.

À mon avis, Kubernetes consiste à mettre à l'échelle horizontalement vos répliques (appelées déploiements). À cet égard, il est plus logique de garder vos déploiements aussi uniques que possible, et d'augmenter les déploiements (et les pods si vous en manquez) au fur et à mesure que la demande augmente. L'équilibreur de charge gère donc le trafic vers les déploiements Gunicorn, et la file d'attente Redis gère les tâches vers les travailleurs Celery. Ainsi, les conteneurs docker sous-jacents sont simples et petits, et nous pouvons les faire évoluer individuellement (et automatiquement) comme bon nous semble.

Quant à votre opinion sur le nombre de personnes workers / concurrency dont vous avez besoin par déploiement, cela dépend vraiment du matériel sous-jacent sur lequel vous exécutez votre Kubernetes et nécessite une expérimentation pour y parvenir.

Par exemple, nous exécutons notre cluster sur Amazon EC2 et avons expérimenté différents types d'instances EC2 et workers pour équilibrer les performances et les coûts. Plus le nombre de CPU par instance est élevé, moins vous avez besoin d'instances et plus les coûts sont élevés. workers que vous pouvez déployer par instance. Mais nous avons découvert que le déploiement d'un plus grand nombre d'instances plus petites est dans notre cas plus économique. Nous déployons maintenant plusieurs instances m4.large avec 3 travailleurs par déploiement.

note latérale intéressante : nous avons eu de très mauvaises performances de gunicorn en combinaison avec les répartiteurs de charge d'amazon, nous sommes donc passés à uwsgi avec de grandes augmentations de performance. Mais les principes sont les mêmes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X