proxy_read_timeout不是连接总时长,而是两次读之间的最大空闲时间;应设为业务心跳间隔的2–3倍(如90–120s),并同步配置proxy_send_timeout、upstream keepalive及系统TCP参数。

proxy_read_timeout 不是连接总时长,而是两次读之间的空闲上限
很多人一看到 WebSocket 断连,第一反应就是把 proxy_read_timeout 拉到 86400s(24 小时),以为“越长越稳”。但实际它只管 Nginx 和后端之间 TCP 连接的「读空闲时间」:从上一次成功收到后端数据,到下一次开始等待新数据之间,最多忍耐多久。它不控制浏览器到 Nginx 的连接、不干预 TCP keepalive、也不替代应用层心跳。
设成 60s(默认值)会频繁断连;设成 0(禁用超时)又可能让僵死连接长期滞留,拖垮 upstream 连接池或触发内核 TCP FIN 超时。真正要对齐的是你后端发送心跳帧的节奏。
- 后端每 30 秒发一次 ping →
proxy_read_timeout建议设为 90–120s(2–3 倍) - 设备上报周期 60 秒 → 设为 180–240s 更稳妥
- 低频通知通道(如审批提醒)→ 3600s 是合理上限,不必硬拉到 24 小时
必须同步配齐的三个配套项,缺一不可
单改 proxy_read_timeout 是典型“半调子配置”。它只管读,不管写、不管复用、不管系统底层——这三块漏掉任何一块,都会让超时调优失效。
-
proxy_send_timeout必须与proxy_read_timeout一致,否则后端响应慢一点,Nginx 就先在发包阶段切断连接 -
upstream块中必须启用keepalive 32(或按并发量调整),否则每次消息都重建连接,心跳再准也扛不住建连开销 - 检查系统级参数:
net.ipv4.tcp_keepalive_time应 ≥ 7200,否则内核会在 Nginx 之前主动踢掉“静默”连接
Ingress 场景下别直接改 nginx.conf,用 annotation 覆盖
在 Kubernetes 中用 Nginx Ingress Controller 代理 WebSocket 时,proxy_read_timeout 不是写在 ConfigMap 或自定义 nginx.conf 里,而是通过 Ingress 资源的 annotation 注入。硬改全局配置容易被 controller 升级覆盖,且无法按路由粒度控制。
正确写法是给 Ingress 加注解:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
注意:key 名里带连字符,值必须是字符串(带引号),单位是秒,不是毫秒;若用 Helm chart 部署,这些应放在 values.yaml 的 annotations 字段下,而非 extraArgs。
心跳帧间隔必须避开 60 秒整数倍,否则和默认超时共振断连
这是最容易被忽略的隐藏陷阱。如果后端心跳固定每 60 秒发一次 ping,而 Nginx 默认 proxy_read_timeout 是 60s,那么只要某次 ping 因网络抖动延迟 500ms 到达,Nginx 就会认为“已空闲超 60s”,立即断连——看起来像随机断,实则是定时炸弹。
解决方案很简单:
- 客户端和服务端约定心跳间隔为 25s、45s 或 53s 这类非整数倍数值
- Nginx 的
proxy_read_timeout设为该值的 2–3 倍(例如 45s → 设 120s) - 前端必须响应 pong,否则单向心跳仍会触发超时
真正的稳定不在超时数字多大,而在心跳是否可观察、可测量、可预期。一旦把超时变成故障探测器,而不是被动等待器,问题就从“怎么不断”变成了“为什么断”。

















