502 Bad Gateway主因是Gunicorn worker超时或阻塞:同步模型下IO等待导致worker全卡死;gevent未正确monkey patch或存在阻塞调用;timeout与graceful_timeout配置冲突;worker数与worker_connections失衡;文件描述符或backlog限制不足。

502 Bad Gateway 通常不是 Python 应用本身挂了,而是 Gunicorn 的 worker 进程没在规定时间内响应 Nginx —— 根本原因八成是 worker 被堵死、超时被杀,或根本没空处理新请求。
worker 被卡住:IO 等待没释放进程
同步 worker(sync)模型下,每个请求独占一个 worker 进程。如果应用里有数据库查询、HTTP 调用、文件读写等 IO 操作,进程就会原地等待,无法处理其他请求。流量一上来,所有 worker 全在等,Nginx 发来的请求全积压,最终触发 timeout,返回 502。
- 典型现象:
gunicorn.error日志里反复出现Worker timeout (pid:xxx) - 适用场景:纯 CPU 计算型任务(极少);否则不建议生产环境用
sync - 验证方式:用
ps aux | grep gunicorn查看 worker 进程状态,大量处于S(sleep)而非R(running) - 解决方向:换异步 worker 类,让单个进程能并发处理多个请求
gevent worker 配置不当:补丁漏了或阻塞调用未适配
用 gevent 是最常见解法,但光加 -k gevent 不够。gevent 依赖 monkey patch 把标准库的阻塞调用(如 socket、ssl、threading)替换成协程友好的版本。漏掉 patch,IO 仍会阻塞整个 worker。
- 必须在应用入口最顶部执行:
from gevent import monkey; monkey.patch_all() - 某些 C 扩展(如旧版
psycopg2)需额外 patch:monkey.patch_psycopg() - 避免在协程中执行耗时 CPU 操作(比如大数组排序、图像处理),会拖垮整个 worker
- 检查是否误用了线程/进程(
threading.Thread或multiprocessing.Process),它们不兼容 gevent
超时参数设置冲突:timeout 和 graceful_timeout 差太小
--timeout 控制单个请求最长处理时间,--graceful-timeout 控制 worker 收到退出信号后最多还能干多久。Kubernetes 滚动更新或手动 reload 时,如果 graceful-timeout 小于 timeout,正在处理长请求的 worker 可能被强制 kill,导致该请求直接中断并返回 502。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
- 安全组合示例:
--timeout 120 --graceful-timeout 30(前者 ≥ 后者 × 2 更稳妥) - 特别注意:
--worker-timeout是空闲超时,和 502 关系不大,别把它和--timeout搞混 - 若业务含大文件上传或报表导出,
--timeout必须显式加大,不能依赖默认 30 秒
worker 数量与连接数失衡:并发能力虚高
设了 8 个 worker,却没配 worker_connections,Gunicorn 默认只允许每个 worker 处理 1000 个连接(对 gevent 有效)。实际最大并发 = workers × worker_connections。如果这个值远低于 Nginx 的 worker_connections,请求会在 Nginx 层排队,超时后照样 502。
- gevent 场景下务必配:
worker_class = "gevent"+worker_connections = 2000(根据内存调整) - 同步模式下
worker_connections无效,别乱设 - Linux 文件描述符限制常是隐形瓶颈:
ulimit -n至少要 >workers × worker_connections × 2 - backlog 参数(默认 2048)也要同步调大,否则连接队列溢出直接拒绝
真正容易被忽略的是:gevent 的并发能力高度依赖应用代码是否“协程友好”。哪怕配置全对,只要某处调用了未 patch 的阻塞函数(比如某些 SDK 的底层 socket 操作),整个 worker 就会卡死——这种问题不会报错,只会静默拖慢所有请求,最后集体超时变 502。

















