多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Nginx 报 upstream timed out:3 个 timeout 到底该改哪个?

Nginx 报 upstream timed out:3 个 timeout 到底该改哪个? 用户访问接口返回504。Nginx错误日志里出现upstream timed out很多人的第一反应是搜索一段配置proxy_connect_timeout 300s; proxy_send_timeout 300s; proxy_read_timeout 300s;然后把三个超时全部改大。接口暂时不报504了发布群里宣布问题解决。但几天后Nginx连接堆积、客户端等待更久真正变慢的Spring Boot接口依然没有被修复。因为这三个超时控制的是三个完全不同的阶段。说明文中的时间仅用于解释不能作为所有业务的生产默认值。超时必须结合接口SLA、请求体大小、上游处理时间和重试策略设置。一、先画清楚一次代理请求的路径用户访问后端接口大致会经过客户端 ↓ Nginx接收请求 ↓ Nginx连接上游Spring Boot ↓ Nginx把请求发送给上游 ↓ Spring Boot处理业务 ↓ Nginx读取上游响应 ↓ 返回客户端三个常见配置分别控制proxy_connect_timeout连接上游 proxy_send_timeout向上游发送请求 proxy_read_timeout从上游读取响应所以先不要问“超时应该改多大”。先问请求到底卡在连接、发送还是读取响应二、proxy_connect_timeout连不上上游配置示例proxy_connect_timeout 3s;它控制的是Nginx与上游服务器建立连接时最多等待多久。常见问题包括上游IP或端口错误 Spring Boot没有监听端口 容器网络不通 防火墙拒绝 上游连接队列满 目标节点已经故障但仍在upstream列表错误日志常包含类似阶段while connecting to upstream这时把proxy_read_timeout调到300秒没有意义。因为Nginx连上游TCP连接都没有建立成功还没进入读取响应阶段。先验证curl-v--connect-timeout3\http://10.0.2.15:8080/actuator/health再检查ss-lntp|grep:8080如果Nginx在容器中还要从Nginx所在的容器或网络命名空间测试不能只在宿主机上curl localhost。三、proxy_send_timeout请求发不出去配置示例proxy_send_timeout 15s;它控制的是Nginx向上游传输请求时两次连续写操作之间允许等待的时间。它不是“整个请求最多允许发送15秒”。常见触发场景上传大文件 客户端请求体很大 上游读取请求非常慢 上游Socket接收缓冲区长期无法继续接收 网络发生严重拥塞错误阶段可能包含while sending request to upstream普通JSON查询接口很少卡在这里。如果一个只有几KB请求体的GET接口触发发送超时要优先怀疑上游进程已经卡死 网络链路异常 连接虽然建立但上游无法继续读取不要因为接口包含“发送”两个字就误以为所有POST请求都应该调整proxy_send_timeout。四、proxy_read_timeout上游迟迟没有返回配置示例proxy_read_timeout 30s;它控制的是Nginx读取上游响应时两次连续读取操作之间允许等待的时间。同样它通常不是整个响应从开始到结束的总时间。如果上游在超时时间内一直没有发送任何数据Nginx会关闭连接。Spring Boot接口慢、数据库等待和线程池拥堵最常触发的就是这一项。错误阶段常见while reading response header from upstream这意味着Nginx已经连上Spring Boot 请求也已经发过去 但迟迟没有读到上游响应头此时真正应该排查接口执行时间 数据库连接池pending 慢SQL与锁等待 Web线程池是否耗尽 下游HTTP或RPC调用 Full GC与Safepoint把proxy_read_timeout从30秒改成300秒只是允许用户多等270秒。五、从错误日志一句话判断阶段可以先提取日志grep-nupstream timed out\/var/log/nginx/error.log\|tail-n50重点看while ...后面的阶段错误阶段优先检查相关配置while connecting to upstreamIP、端口、网络、监听、连接队列proxy_connect_timeoutwhile sending request to upstream大请求体、上游读取、网络拥塞proxy_send_timeoutwhile reading response header from upstream应用耗时、线程池、连接池、SQLproxy_read_timeoutwhile reading upstream响应传输中断或长时间无新数据proxy_read_timeout这张表只能帮助快速分层。最终仍要结合upstream地址 请求URI 请求方法 客户端状态码 同一时间的应用日志和监控六、给 access log 加上游耗时只看错误日志通常只能知道“超时了”。为了区分连接慢还是应用慢可以记录上游时间log_format upstream_timing $remote_addr $request status$status request_time$request_time upstream_connect_time$upstream_connect_time upstream_header_time$upstream_header_time upstream_response_time$upstream_response_time upstream_addr$upstream_addr; access_log /var/log/nginx/access_timing.log upstream_timing;这些字段大致可以帮助判断upstream_connect_time建立上游连接耗时 upstream_header_time读到上游响应头耗时 upstream_response_time完整上游响应耗时 request_timeNginx处理整个请求的总耗时修改前检查sudonginx-t确认通过后再平滑加载sudonginx-sreload日志格式会增加存储量字段和保留周期应根据生产日志方案调整。七、绕过Nginx直接请求Spring Boot从Nginx所在机器或容器中执行curl-o/dev/null-sS\-wcode%{http_code} connect%{time_connect}s ttfb%{time_starttransfer}s total%{time_total}s\n\http://10.0.2.15:8080/api/orders/health然后再请求公网或网关地址curl-o/dev/null-sS\-wcode%{http_code} connect%{time_connect}s ttfb%{time_starttransfer}s total%{time_total}s\n\https://api.example.com/api/orders/health结果可以这样判断直连上游经过Nginx方向快慢Nginx配置、网络或代理链路慢慢Spring Boot及其下游依赖失败失败应用、端口或网络快失败upstream、路由、Host或TLS配置这一步可以避免所有人只盯着Nginx配置文件。八、这次事故为什么不是Nginx参数问题日志显示while reading response header from upstream直连Spring Boot接口也需要40多秒。继续查看应用指标Web线程池活跃线程接近上限 HikariCP pending持续增加 数据库出现一条锁等待SQL请求链路其实是SQL等待行锁 → 事务迟迟不结束 → 数据库连接被长期占用 → 新请求等待连接 → Web线程不断堆积 → Spring Boot迟迟不返回响应 → Nginx proxy_read_timeout如果把Nginx超时改成300秒锁等待仍然存在 连接池仍然耗尽 用户只是等待更久 Nginx保留更多长连接真正的修复是终止异常事务、统一加锁顺序并缩短事务范围而不是无限扩大代理超时。准备把proxy_read_timeout改成300秒之前建议先把这段发给负责应用和数据库的同事Nginx报超时也可能只是替后端锁等待背了锅。九、什么时候确实需要调大超时有些业务本来就需要更长时间大文件上传 大文件下载 报表生成 长轮询 流式响应 合法的长耗时任务但即使如此也不建议全局统一改大。可以按接口单独配置location /api/reports/export { proxy_pass http://report_service; proxy_connect_timeout 3s; proxy_send_timeout 30s; proxy_read_timeout 120s; }并且继续评估是否应该改成异步任务 是否应该返回任务ID 是否应该使用对象存储下载 客户端超时是否匹配 网关和负载均衡是否还有更短超时单独放大一个Nginx参数并不代表整条链路都会允许这么久。十、我的排查顺序遇到upstream timed out可以按以下顺序1. 记录完整错误日志和发生时间 2. 看清 while connecting、sending 还是 reading 3. 确认具体 upstream 地址 4. 从Nginx环境直连上游 5. 对比直连与代理耗时 6. 检查upstream连接和响应时间日志 7. 对齐Spring Boot日志、Trace ID和监控 8. 检查线程池、连接池、SQL和下游调用 9. 只有确认业务合理耗时后才调整超时 10. 尽量按接口配置不要全局改成300秒写在最后Nginx报超时不代表问题一定在Nginx。三个参数分别回答连接上游要等多久 发送请求要等多久 读取响应要等多久先看日志卡在哪个阶段再决定查网络、查Nginx还是查Spring Boot和数据库。本文归入「生产环境保命清单」系列后续会继续整理网关、Java服务和数据库的完整排查链路。你遇到过upstream timed out吗最后问题出在Nginx、Spring Boot、连接池还是SQL欢迎把最终根因留在留言区。系列导航上一篇《Load Average都到20了CPU为什么只有30%》下一篇预告《一台新服务器上线Java服务我会检查这20项》关注我回复关键词保命获取「生产环境保命清单」全部文章。也可以把脱敏后的Nginx错误日志、上游地址类型和接口耗时发来我会尽量帮你判断下一步应该查哪里。
返回列表