Nginx 返回 504 Gateway Timeout 上游响应太慢
认识 504 Gateway Timeout
当你使用浏览器访问某个网站或接口时,如果页面长时间空白,最终显示“504 Gateway Timeout”,这表示 Nginx 作为反向代理或负载均衡器,在等待上游服务器(如后端应用、PHP-FPM、其他 Web 服务)的响应时,等待时间超过了其设定的时间上限,因此切断了连接并向客户端返回 504 状态码。
简单来说,问题不在 Nginx 本身,而是上游服务器的处理时间太长,超过了 Nginx 允许等待的最大时长。
常见触发场景
- 后端 API 执行复杂的数据库查询,耗时超过 30 秒或 60 秒。
- 上游应用服务器负载过高,请求堆积导致响应变慢。
- 后端服务崩溃或无响应,导致 Nginx 一直等待直到超时。
- 文件上传或大文件处理耗时长,但 Nginx 中的代理超时设置过短。
- 反向代理到另一个 Nginx 或 Apache 时,下游代理的超时时间配置不当。
如何快速诊断
在动手修改配置之前,先确认问题点,避免盲目调参。
1. 查看 Nginx 错误日志
Nginx 的错误日志会明确指出上游连接超时。执行以下命令:
tail -f /var/log/nginx/error.log
常见的日志条目类似:
upstream timed out (110: Connection timed out) while reading response header from upstream
这确认了是上游响应头都没有在限定时间内返回。
2. 直接测试上游服务
绕过 Nginx,直接请求上游服务,观察其响应时间和状态。
例如,如果上游是监听在 127.0.0.1:8080 的 Node.js 应用:
curl -o /dev/null -s -w '总时间: %{time_total}s\n状态码: %{http_code}\n' http://127.0.0.1:8080/your-path
如果请求需要 90 秒才能返回,而 Nginx 的超时设置为 60 秒,则必然会出现 504。
3. 分析上游服务的慢日志
- PHP-FPM:检查
slowlog配置项,查看执行缓慢的脚本。 - 数据库:开启慢查询日志,确认是否有耗时过长的 SQL 语句。
- 应用程序:查看应用自身的日志,寻找处理时长超过预期的请求。
Nginx 侧解决方案:调整超时参数
当确认上游服务确实需要更长时间,且无法在短期内优化时,可以调大 Nginx 等待上游响应的时长。这些指令通常配置在 http、server 或 location 代码块中。
核心指令:proxy_read_timeout
该指令定义 Nginx 等待上游服务器返回完整响应 的超时时间。默认值为 60 秒。
location /api/ {
proxy_pass http://backend-server;
proxy_read_timeout 120s; # 将等待响应的时间延长至 120 秒
}
辅助指令:proxy_connect_timeout
定义 与上游服务器建立连接 的超时时间。如果上游负载高,建立连接本身就很慢,可适当增加。
proxy_connect_timeout 30s; # 默认通常为 60s,可根据需要调整
发送请求超时:proxy_send_timeout
定义 向上游服务器发送请求数据 的超时时间。对于文件上传等场景,如果上传本身很慢,需调大此值。
proxy_send_timeout 90s;
综合配置示例
location /long-process/ {
proxy_pass http://slow-upstream;
proxy_connect_timeout 30s;
proxy_send_timeout 90s;
proxy_read_timeout 300s; # 允许长任务执行 5 分钟
}
注意:盲目将超时时间设得过大(如 600 秒)可能会导致大量连接堆积,耗尽 Nginx 的工作进程,进而引发更严重的问题。应结合上游服务实际平均耗时,设定一个合理的、略高于最大正常耗时的时间。
上游服务的优化方向
调整 Nginx 只是“治标”,从根本上解决 504 错误需要优化上游服务的性能。
缩短单个请求的处理时间
- 代码优化:检查循环、无索引的数据库查询、重复计算等。
- 缓存机制:对不经常变化且计算成本高的数据,引入 Redis 等缓存,避免每次请求都重新生成。
- 异步处理:对于非即时需要的任务(如发送邮件、生成报表),改为队列异步执行,接口立刻返回“已接收”。
提升上游服务的并发能力
- 增加工作进程/线程:例如调整 PHP-FPM 的
pm.max_children,或 Node.js 的 cluster 进程数。 - 负载均衡:如果后端应用无状态,可通过 Nginx 将请求分发到多个上游实例。
- 资源扩容:为上游服务器增加 CPU 核心或内存,消除硬件瓶颈。
调整上游超时与 Nginx 匹配
某些上游服务本身也有超时控制,例如:
- PHP-FPM 的
request_terminate_timeout默认 0(无限制),如果设置了过小的值,PHP 进程会被杀死,Nginx 收不到响应导致 504。需确保该值大于proxy_read_timeout。 - AWS ELB / ALB 或 Cloudflare 等前置代理同样有超时设置,需要逐层检查超时时间的匹配关系。
临时应急措施:优雅降级
如果长时间任务无法立即优化,又不想让用户面对 504 错误,可以考虑以下方案:
- 返回“处理中”状态:让后端在几秒内先返回一个任务 ID,后续通过轮询或 WebSocket 获取最终结果。
- Nginx 缓存空响应:针对已知的超时请求,先返回一个友好的提示页面,而不是直接暴露 504。
总结
Nginx 的 504 Gateway Timeout 本质是上游响应超时保护机制,核心在于 proxy_read_timeout 指令。排查时优先查看 Nginx 错误日志,直接测量上游响应时间,然后按需调整 Nginx 配置,并从根本上优化上游服务的处理逻辑。逐层调整超时、引入缓存与异步化,才是彻底消除 504 的正确路径。