过去两年我一直在Kubernetes上部署应用程序。在我的组织中,我们所有的应用程序(尤其是无状态应用程序)都在Kubernetes上运行。我仍然有一个基本的问题,因为最近我们发现了一些与我们的几个python应用程序有关的问题。
最初部署时,我们的python应用程序(用Flask和Django编写),我们使用python app.py
运行它。众所周知,由于GIL的原因,python实际上不支持系统线程,并且它一次只能服务一个请求,但如果一个请求占用大量CPU,它将无法处理进一步的请求。这有时会导致健康API无法工作。我们观察到,此时,如果有一个不是IO的请求正在执行某些操作,我们将占用CPU,无法并行处理另一个请求。由于它只执行较少的操作,我们观察到CPU利用率也没有增加。这对HorizontalPodAutoscaler
的工作方式有影响,它无法攀登吊舱。
正因为如此,我们开始在pod中使用uWSGI
。所以基本上uWSGI
可以在引擎盖下运行多个pod,并行处理多个请求,并根据需要自动旋转新的进程。但是这里出现了另一个问题,我们已经看到,uwsgi
在自动缩放进程以正确服务请求方面速度不足,这导致了HTTP 503
错误。正因为如此,我们无法以100%的可用性提供我们的几个API。
与此同时,我们所有其他的应用程序,写在nodejs
,java
和golang
,是提供100%的可用性。
我正在考虑在Kubernetes中以100%(99.99)可用性运行python应用程序的最佳方法,如下所示
1.应用程序提供健康API和活跃API
1.在Kubernetes中运行的应用程序
1.如果可能,不使用uwsgi(每个pod的单个进程是基本的Docker概念)
1.如果使用uwsgi,我们是否可以为k8s环境应用任何特定配置
2条答案
按热度按时间mcdcgff01#
我们使用Twisted的WSGI服务器,它有30个线程,这对于我们的Django应用程序来说是很稳定的。正如你提到的,保持每个pod模型一个进程,这更接近Kubernetes的期望。是的,GIL意味着这30个线程中只有一个可以运行Python代码,但与大多数Web应用程序一样,这些线程中的大多数在I/O上阻塞(通常是等待数据库的响应),然后在此基础上运行多个副本,以实现冗余,并在任何需要的级别上给予真正的并发性(我们通常使用4-8取决于网站流量,一些大的达到16)。
41zrol4v2#
我在运行Flask应用程序的python部署中遇到了同样的问题,大多数API调用在几秒钟内就能处理完毕,但也有一些CPU密集型请求需要2分钟才能获得GIL a a.... pod继续接受请求,忽略配置的超时,忽略用户关闭的连接;然后,在活动探测失败1分钟之后,由Kubelet重新启动POD。
因此,1个胖请求会显著降低可用性。
我看到两种不同的解决方案:
1.具有将仅托管长时间运行的API调用的单独部署;配置入口以在这两个部署之间路由请求;
1.在主进程中使用多处理句柄活动性/就绪性探测器时,必须在子进程中处理每隔一个请求;
每个解决方案都有优点和缺点,也许我需要两者的结合,而且如果我需要稳定的prometheus指标流,我可能需要在应用层创建一个代理服务器(同一个pod上还有1个容器)。还需要配置入口,使其具有到python pod的单个上游连接,以便长时间运行的请求将排队,而短的将并发处理(是的,Python,并发,好笑话)。不确定它是否能很好地与HPA扩展。
所以,在kubernetes上运行python rest API服务器并不是小菜一碟,Go和java有一个更好的微服务应用生态系统。
PS这里是一篇很好的文章,它表明没有必要在Kubernetes中使用WSGI https://techblog.appnexus.com/beyond-hello-world-modern-asynchronous-python-in-kubernetes-f2c4ecd4a38d运行您的应用
PPS我正在考虑使用prometheus导出器的 flask 。看起来比运行在一个单独的线程Python客户端更好;https://github.com/rycus86/prometheus_flask_exporter