Flask 程序部署在三个 Pod 的 Deployment 里,业务需要向三个 Pod 各发一条消息通知。暂时不想引入消息队列,于是用 Kubernetes Python 库取出三个 Pod IP,直接 requests.post 三遍——方法粗糙,但轻量地解决了问题。
1 | resp = requests.post( |
现象
调试时发现:一旦在某个 API 里发起新的 request 请求,整个系统直接卡住,甚至所有 Pod IP 都无法访问了。
一开始以为是循环调用 API 导致的无限递归,但加了 debug log 后一条都没打出来,排除。
根因
突然想起之前把 Flask 的启动方式换成了 gevent.pywsgi.WSGIServer,会不会是协程阻塞了 IO?
查了一下 gevent 的文档:
1 | gevent is a coroutine-based Python networking library that uses greenlet to provide |
gevent 是协程级别的,标准库的阻塞式 IO(包括 requests)会卡住整个事件循环。
解决办法
官方提供了 monkey patch 工具。monkey.patch_all() 会对 socket、threading、time 等标准库做补丁,让阻塞 IO 发生时自动切换到其他协程。
在 Flask 应用最开头加上:
1 | # noinspection PyUnresolvedReferences |
问题就解决了。
顺带复习
借这个机会重温了一下进程(Process)、线程(Thread)和协程(Coroutine),这篇文章讲得挺好。两个要点:
- 线程是程序执行流的最小单元,是处理器调度和分派的基本单位。
- 协程做阻塞操作(如 IO)时,会阻塞掉整个程序——除非做了 monkey patch。