BLOG
Enjoy when you can, and endure when you must.
APR 10, 2018/后端开发与架构
uwsgi 与 rabbitmq 的恩恩怨怨
故事从这里开始
---
 
在一个平静的夜晚,正当在沙发上坐下来享受短暂的夜间时光时,急促而连续的报警声响了。于是发现 uwsgi 和 rabbitmq 在激烈地纠缠中:
 
“原话版”:
uwsgi worker-1:Hi rabbitmq,我消息发过来了,快接一下。
rabbitmq:Ummm…等会儿等会儿,我有点忙不过来了,排个队。
uwsgi worker-1:搞啥啊,再不快点儿包工头就要我命了。
rabbitmq:…
n 秒之后,uwsgi worker-1 被包工头责令下课…
---
uwsgi worker-2 启动,连接 rabbitmq…
uwsgi worker-2:Hi rabbitmq,我消息发过来了,快接一下。
rabbitmq:Ha?又来一个?什么鬼,排队排队。
uwsgi worker-2:搞啥啊,再不快点儿包工头就要我命了。
rabbitmq:…
n 秒之后,uwsgi worker-2 被包工头责令下课…
---
repeat thousands times…
“译文版”:
uwsgi worker-1:发送 mq 消息
rabbitmq:connection blocked 状态,阻塞客户端发送消息
uwsgi worker-1:持续等待 recv
n 秒之后,触发 harakiri,uwsgi worker-1 被回收
---
repeat thousands times…
 
 
关键字解剖
---
 
rabbitmq:connection blocked
 
这是 rabbitmq 的自我保护机制,当 rabbitmq 所在机器内存、磁盘等达到了水位线,即会触发流控甚至完全阻塞消息发布,而带给客户端的即是上面 uwsgi 所遇到的等待(假死)。这里特别注意内存的水位线,默认是总内存的 40% 即触发。
 
uwsgi:harakiri
 
这是 uwsgi 所提供的一个功能,相当于为 worker 设置一个请求处理的超时时间,如果 worker 在处理一个请求时达到了设置的 harakiri 时间,则会导致该 worker 被回收(be killed with no mercy),然后启动新的 worker 来顶替。这算是 uwsgi 的保护机制,可以理解为是一种“熔断”。
 
 
 
回到现场
---
 
从前面的关键字解剖中,其实已经大概知晓了问题发生的原因。具体过程如下:
 
  1. rabbitmq 因为各种不当原因,在事故前达到了内存水位线,从而触发了流控;
  2. uwsgi worker 因为流控而导致部分 worker 的响应延迟飘高,甚至部分达到 harakiri 的阈值而发生回收;
  3. 大量重启的 worker 持续连接 rabbitmq,进一步加重了 rabbitmq 的负担,使情况进一步恶化;
  4. 继续恶性循环,且愈演愈烈…
 
 
重要的一课
---
 
其实很多时候,灾难都源于考虑问题的片面化、疏忽以及对工具的不当使用。还是从这里的两个主角说起。
 
首先是 rabbitmq,它可以很方便的为我们提供功能丰富的消息队列。rabbitmq 很老牌,性能不算太高,但在不算非常大型的应用场景下,它依然是不错的选择,并且在 python third packages 里也对 rabbitmq 的支持很成熟。平常使用,甚至在压测的场景下,我们总是将重心放在了 rabbitmq 的吞吐上,却疏忽了其对于磁盘、内存等的要求与使用的“姿势”。对工具的全方位了解,有时也是非常关键的。 
 
而 uwsgi,对于从事 python web 开发的同学来说一定再熟悉不过。一个不太妥的说法,它算是一个壳儿,而如何与应用正确的结合是非常重要的。
在上面,我们用到了 harakiri 这个功能,意在某些异常情况或接口偶尔响应缓慢的时候加一层保护,以防 worker 卡死导致整体异常。但 harakiri 本身是非常极端的,它会直接 kill worker,这就会导致与 db 等的连接不会正常关闭。如果短时间内出现大量的 worker 被 kill 然后重启,就可能瞬间冲击底层的服务,造成更大的麻烦。
但一般来讲,即使使用 harakiri,其充当的也应仅是最后一道防线,应用理应防止触及这条线。所以反观应用本身,对于可能发生响应抖动的点要重点关注,特别是 I/O 层面的处理,应更做到更细致地考虑。在我们的应用中,对于 rabbitmq 请求超时时间的设置就远大于 harakiri 所设置的时间,固然在异常情况下容易引发问题。
 
 
结局
---
 
Oops,是时候做优化了
COMMENTS
18/06From 1wen

好想看看这个Django框架的源码,做的很不错

20/04From 狠会玩

狠会玩哦

24/09From admin

真心不错

24/08From 测试

测试

LEAVE COMMNT