Docker / Kubernetes + Gunicorn / Celery-多工人vs副本?

时间:2018-07-31 09:36:25

标签: django docker kubernetes celery gunicorn

我想知道使用gunicorn和celery部署容器化Django应用程序的正确方法是什么。

具体来说,这些过程中的每一个都有内置的垂直缩放方式,对于workers来说适用于青i色,对于concurrency而言适用于芹菜色。然后是使用replicas

进行扩展的Kubernetes方法

还有一个概念,就是将worker设置为等于CPU的某些功能。 Gunicorn建议

  

每核心2-4个工人

但是,我对在CPU是可分割的共享资源的K8上的含义感到困惑-除非我使用resoureceQuotas。

我想了解什么是最佳实践。我可以想到三种选择:

  • 是否有单人工作的人吃洋甘菊,并发1人的芹菜,并使用复制品进行缩放? (水平缩放)
  • 在内部副本(垂直缩放)的单个副本部署中运行古尼康和芹菜。这意味着分别设置相当高的worker和并发值。
  • 1到2之间的混合方法,我们在工作人员和并发方面运行具有较低价值的Gunicorn和芹菜(例如2),然后使用K8s部署副本进行水平缩放。

关于SO的一些问题,但没有一个提供深入/周到的答案。如果有人可以分享他们的经验,将不胜感激。

注意:我们对Gunicorn使用默认的worker_class sync

2 个答案:

答案 0 :(得分:12)

这些技术与最初看起来并不相似。 它们处理应用程序堆栈的不同部分,并且实际上是互补的。

Gunicorn用于扩展Web请求并发性,而celery应该被视为一个工作队列。我们将尽快使用kubernetes。


独角兽

Web请求并发主要受网络I / O或“ I / O绑定”的限制。可以使用线程提供的协作调度来缩放这些类型的任务。如果您发现请求并发性限制了您的应用程序,那么增加gunicorn worker线程可能是开始的地方。


芹菜

繁重的起重任务,例如压缩图像,运行一些ML算法是“ CPU绑定”任务。他们无法从尽可能多的CPU中受益。这些任务应由芹菜工人分担和并行处理。


Kubernetes

Kubernetes派上用场的地方是提供开箱即用的水平可伸缩性和容错能力。

在架构上,我将使用两个单独的k8s部署来表示应用程序的不同可扩展性问题。 Django应用程序的一个部署,芹菜工人的另一个部署。 这样,您就可以独立调整请求吞吐量与处理能力之间的比例。

我运行的芹菜工人固定在每个容器(-c 1)的单个核心上,这极大地简化了调试,并遵循Docker的“每个容器一个进程”的口头禅。它还可以为您带来可预测性的额外好处,因为您可以通过增加副本数来按核扩展处理能力。

扩展Django应用部署是您需要DYOR来找到特定应用程序最佳设置的地方。 再次坚持使用--workers 1,以便每个容器只有一个进程,但是您应该尝试使用--threads来找到最佳解决方案。只需更改副本数即可再次将水平缩放留给Kubernetes。

HTH 在进行类似项目时,绝对是我必须全神贯注的事情。

答案 1 :(得分:9)

我们使用Django和Celery运行Kubernetes kluster,并实现了第一种方法。因此,我对这种取舍以及为什么选择这种方法的一些想法。

在我看来,Kubernetes就是要水平扩展副本(称为部署)。在这方面,最明智的做法是使部署尽可能地单次使用,并随着需求的增加而增加部署(如果耗尽则增加Pod)。因此,LoadBalancer管理到Gunicorn部署的流量,而Redis队列管理到Celery工作人员的任务。这样可以确保底层的docker容器既简单又小,我们可以根据需要单独(自动)缩放它们。

关于每个部署需要多少workers / concurrency的想法,这实际上取决于您正在运行Kubernetes的基础硬件,并且需要进行实验才能正确。

例如,我们在Amazon EC2上运行集群,并尝试了不同的EC2实例类型和workers,以平衡性能和成本。每个实例拥有的CPU越多,所需实例就越少,每个实例可以部署的workers就越多。但是我们发现,部署更多的小型实例对我们而言更便宜。现在,我们部署了多个m4.large实例,每个部署有3个工作程序。

有趣的旁注:与亚马逊负载均衡器结合使用时,我们的gunicorn的性能确实很差,因此我们切换到uwsgi时性能有了很大提高。但是原理是一样的。