proxy_read_timeout只控制nginx等待后端响应体数据的空闲时长,非连接总时长;应设为后端响应p99耗时加5–10秒缓冲,并同步调大proxy_send_timeout等配套参数。

proxy_read_timeout 不控制连接是否长连接,它只管“等后端响应”这件事等多久。设得太短,会误杀慢但正常的业务请求;设得太长,又会让卡住的连接迟迟不释放,拖累 worker 资源。
它和 keepalive 的关系是「各管一段」
很多人以为开了 upstream keepalive 就不用调 proxy_read_timeout 了,其实不是:
- upstream keepalive 管的是 Nginx 和后端之间「空闲连接复用」——连接建好后不急着关,留着下次用;
- proxy_read_timeout 管的是「单次请求中,Nginx 等后端返回 body 数据的时间」——从后端开始发响应起,到完整收完为止,中间停顿太久就断开。
也就是说:即使用了长连接,只要后端在发响应时卡住(比如日志刷盘慢、GC 暂停、锁竞争),proxy_read_timeout 仍会触发超时,Nginx 主动关闭这次连接,哪怕这条 TCP 还在 keepalive 列表里。
典型误配场景和表现
常见错误配置是把它设成 5s 或 10s,而业务里有导出报表、大文件下载、异步回调等耗时操作:
- 用户看到 504 Gateway Timeout,但后端其实还在处理;
- Nginx access 日志里 uht=upstream_response_time 显示远大于 proxy_read_timeout 值;
- 后端 access log 有记录,说明请求已抵达并执行,只是响应慢;
- 反复重试会加剧后端压力,尤其带副作用的操作(如重复扣款)。
怎么设才合理
不能拍脑袋定值,得结合业务 SLA 和后端真实响应分布:
- 先看日志里的 uht 分位值(比如 p95 是 8s,p99 是 22s),把 proxy_read_timeout 设为略高于 p99(例如 30s);
- 对明确知道耗时的接口(如 /export),用 location 单独配置,比如 set $proxy_timeout "120"; proxy_read_timeout $proxy_timeout;
- 如果后端支持流式响应(如 SSE、chunked),确保它持续发数据包,避免被 proxy_read_timeout 中断;
- 别忘了配套调大 proxy_send_timeout(发请求给后端的等待时间)和 client_header_timeout/client_body_timeout(客户端侧超时),保持链路一致性。
排查时重点看这组日志字段
启用自定义日志格式后,对照这几个字段能快速定位问题归属:
- rt=upstream_connect_time:建连耗时高 → 后端 accept 队列满或网络延迟;
- uct=upstream_header_time:后端发 header 很慢 → 业务逻辑卡在初始化阶段;
- uht=upstream_response_time:整个响应耗时高,且接近 proxy_read_timeout → 超时主因在此;
- "$http_x_forwarded_for":辅助判断是否来自同一客户端或网关,排除中间设备干扰。











