Nginx 反向代理出现 502 Bad Gateway 和 504 Gateway Timeout 错误是常见且令人头疼的问题。这两个错误都指示 Nginx 无法从上游服务器(被代理的应用服务器,如 Tomcat, Node.js, Gunicorn, PHP-FPM, 或其他 Nginx 实例等)获得有效的响应。
理解它们的区别是排查的关键:
-
502 Bad Gateway:
-
含义: Nginx 成功连接到了上游服务器,但上游服务器返回了一个无效、空或完全无法理解的响应。
-
核心问题: 上游服务器本身存在问题,或者连接/通信过程在建立后被意外中断。
-
-
504 Gateway Timeout:
-
含义: Nginx 在配置的超时时间内未能从上游服务器收到任何响应。
-
核心问题: 上游服务器响应极其缓慢(甚至无响应)、Nginx 到上游服务器的网络问题、或者 Nginx 的超时设置过短。
-
🔍 详细排查指南
📍 第一步:定位问题根源 (502 vs 504)
-
检查 Nginx 错误日志: 这是最重要的第一步!日志通常位于
/var/log/nginx/error.log
(具体路径可能因安装方式和系统而异)。-
查找关键信息: 搜索包含
502
或504
的条目,特别注意日志行中提供的上下文信息:-
upstream:
或connect()
:显示 Nginx 尝试连接的上游服务器地址和端口。 -
failed (111: Connection refused)
:通常指向 502,表示上游服务器端口没监听(服务没启动、崩溃、监听地址/端口错误)。 -
failed (110: Connection timed out)
:通常指向 504,表示连接建立阶段就超时(网络不通、防火墙阻断、上游服务器过载无法接受新连接)。 -
upstream timed out (110: Connection timed out)
:明确是连接超时(504)。 -
upstream prematurely closed connection while reading response header from upstream
:上游服务器在处理请求过程中突然关闭了连接(502,可能是上游崩溃、进程重启、或达到资源限制)。 -
upstream sent too big header / invalid header
:上游返回的响应头过大或格式非法(502)。 -
recv() failed (104: Connection reset by peer)
:上游服务器主动重置了连接(502,可能是上游崩溃、进程重启、或 keepalive 问题)。 -
no live upstreams
:所有配置的上游服务器都不可用(502)。 -
upstream response is buffered to a temporary file
:可能指示上游响应体过大,需要调整缓冲区。
-
-
日志级别: 如果默认日志信息不足,可以在
server
或location
块中临时增加日志级别:error_log /path/to/error.log debug;
(生产环境慎用,日志量巨大)。
-
-
检查访问日志: 位于
/var/log/nginx/access.log
。查找产生 502/504 的请求记录。-
注意
$upstream_addr
(实际连接的上游服务器地址)、$upstream_status
(上游服务器返回的 HTTP 状态码,502/504 时通常是 502 或 504 本身,但也可能是空或-
)、$request_time
(Nginx 处理整个请求的总时间)、$upstream_response_time
(Nginx 从上游服务器接收响应所花的时间)。这些变量需要配置在log_format
中。
-
🔧 第二步:针对 502 Bad Gateway 的排查
-
上游服务状态:
-
直接访问上游服务器:在运行 Nginx 的机器上(或确保网络可达),使用
curl
,telnet
,wget
直接访问上游服务的地址和端口(如curl http://upstream-server:port/health-check
)。看是否能得到预期响应。 -
检查服务是否运行: 登录到上游服务器,检查应用进程(如 Tomcat, Node, PHP-FPM, Gunicorn)是否正在运行 (
ps aux | grep
,systemctl status
)。 -
检查监听端口: 在上游服务器运行
netstat -tulpn | grep
或ss -tulpn | grep
,确认应用确实在监听 Nginx 配置中指定的 IP 和端口。 -
检查资源限制: 上游服务器是否耗尽内存、CPU、磁盘空间、文件描述符 (FD) 或进程/线程数?使用
top
,htop
,free -m
,df -h
,ulimit -a
等命令检查。 -
查看上游应用日志: 上游服务器应用的日志(如 Tomcat 的
catalina.out
, PHP-FPM 的php-fpm.log
, Node.js 的应用日志)是查找崩溃、错误、资源耗尽问题的关键。查找在 Nginx 报告 502 的时间点附近是否有相关错误记录。
-
-
连接问题:
-
防火墙/Security Groups: 确保上游服务器防火墙(
iptables
,firewalld
,ufw
)允许来自 Nginx 服务器 IP 的流量访问上游服务端口。在云环境中,检查安全组规则。 -
网络路由: 确保 Nginx 服务器能路由到上游服务器(
ping upstream-ip
,traceroute upstream-ip
)。检查网络设备(交换机、路由器)或云网络配置(VPC 路由表、NACL)。 -
端口是否正确: 再次确认 Nginx 配置中
proxy_pass
指向的端口与上游服务监听的端口完全一致。
-
-
Nginx 与上游通信配置:
-
proxy_pass
指令: 检查 URL 是否正确。确保末尾的/
使用符合预期(影响 URI 传递)。 -
响应头过大: 如果日志提到
upstream sent too big header
,增加缓冲区大小:proxy_buffer_size 128k; # 单个缓冲区大小 proxy_buffers 4 256k; # 缓冲区的数量和大小 proxy_busy_buffers_size 256k; # 处于busy状态时缓冲区大小
-
无效响应: 上游应用是否可能返回格式错误的 HTTP 响应?检查应用逻辑。
-
Keepalive: 配置不当的 HTTP keepalive 有时会导致问题。尝试调整:
-
proxy_http_version 1.1; # 推荐使用 HTTP/1.1
proxy_set_header Connection ""; # 清除默认的 "close",启用 keepalive
upstream backend {
server backend1:8080;
keepalive 32; # 保持的连接数
}
- 临时文件问题: 如果日志提到缓冲区写入临时文件,确保
proxy_temp_path
指向的目录存在且 Nginx 进程(通常是nginx
用户)有读写权限。
⏱ 第三步:针对 504 Gateway Timeout 的排查
-
检查 Nginx 超时设置: 这是 504 最常见的直接原因。
-
关键指令:
-
proxy_connect_timeout
: 定义 Nginx 连接到上游服务器的超时时间。默认通常 60 秒。如果网络延迟高或上游服务器过载无法快速接受连接,需要增加。proxy_connect_timeout 75s;
-
proxy_send_timeout
: 定义 Nginx 向上游服务器发送请求的超时时间。默认通常 60 秒。如果发送大量数据且网络慢,可能需要增加。proxy_send_timeout 180s;
-
proxy_read_timeout
: 定义 Nginx 从上游服务器读取响应的超时时间。这是 504 最常见的设置点。 默认通常 60 秒。如果上游应用处理请求很慢(如复杂查询、报表生成、长轮询),必须显著增加这个值。proxy_read_timeout 300s;
(根据实际需要调整)。 -
proxy_next_upstream_timeout
:定义在将请求切换到下一个上游服务器之前等待成功连接的时间。
-
-
配置位置: 这些指令通常放在
http
,server
, 或特定的location
块中。确保它们覆盖了出问题的请求路径。
-
-
上游服务器性能:
-
资源瓶颈: 上游服务器是否 CPU 100%、内存耗尽、磁盘 I/O 饱和?使用监控工具(如
top
,vmstat
,iostat
,sar
)或 APM 工具检查。 -
应用性能: 上游应用本身是否存在慢查询(数据库)、死锁、低效算法、阻塞操作?检查应用日志、数据库慢查询日志、性能剖析工具(如
pstack
,gdb
, 语言相关的 profiler)。 -
数据库/外部服务: 如果上游应用依赖数据库或其他外部服务,检查这些依赖项是否响应缓慢或超时。
-
-
网络问题:
-
网络延迟/丢包: 在 Nginx 服务器和上游服务器之间运行
ping
(看延迟和丢包)、mtr
(结合 traceroute 和 ping) 或tcpdump
(抓包分析) 检查网络质量。高延迟或丢包会显著增加通信时间。 -
带宽瓶颈: 是否在传输非常大的响应?网络链路带宽是否饱和?检查接口流量 (
ifconfig
,ip -s link
)。
-
-
负载均衡与上游健康检查:
-
如果使用了
upstream
块和负载均衡:-
检查所有
server
条目是否都有效。 -
检查
max_fails
和fail_timeout
设置。如果上游服务器响应慢但未完全宕机,可能被健康检查标记为失败,导致请求被发送到已经不健康的服务器或没有可用服务器(也会导致 502/504)。 -
确保健康检查 (
health_check
) 配置合理,能够准确反映上游服务的真实健康状态。
-
-
🧪 第四步:通用排查与优化
-
简化测试:
-
创建一个最简单的
location
块,proxy_pass
到上游,移除所有复杂的重写规则、缓存配置、Header 操作等。看问题是否消失。如果消失,再逐一添加配置定位问题点。 -
使用
curl -v http://your-domain/problem-path
或httpie
直接测试,观察详细请求/响应过程。
-
-
压力测试:
-
使用
ab
(ApacheBench),siege
,wrk
,jmeter
等工具模拟并发请求,看是否能稳定复现 502/504。这有助于识别资源耗尽、连接池不足等问题。
-
-
资源限制:
-
Nginx 资源: 检查 Nginx 自身的限制:
-
worker_connections
(在events
块):单个 worker 进程能处理的最大连接数。worker_processes
*worker_connections
应大于系统最大文件描述符限制 (ulimit -n
)。 -
worker_rlimit_nofile
:在main
上下文设置 Nginx worker 进程的文件描述符限制 (worker_rlimit_nofile 65535;
),并确保系统限制 (/etc/security/limits.conf
) 也足够高。
-
-
系统资源: 确保整个系统的文件描述符限制 (
sysctl fs.file-max
,/etc/security/limits.conf
)、网络相关内核参数 (net.core.somaxconn
,net.ipv4.tcp_max_syn_backlog
,net.ipv4.tcp_tw_reuse
等) 配置合理,适合高并发场景。
-
-
版本与模块:
-
确保 Nginx 和上游应用使用的是稳定且兼容的版本。有时特定版本存在已知 bug。
-
检查是否有第三方模块可能导致问题。尝试禁用非必需模块。
-
-
DNS 解析:
-
如果
proxy_pass
中使用的是域名而非 IP:-
确保 DNS 解析稳定可靠。在 Nginx 配置中使用
resolver
指令显式指定 DNS 服务器并设置有效期 (resolver 8.8.8.8 valid=300s;
)。 -
考虑在
upstream
块中使用 IP 地址以避免 DNS 解析带来的延迟或失败风险。
-
-
📌 总结流程图 (简化版)
通过系统性地检查 Nginx 日志、上游服务状态、网络连接、Nginx 配置(尤其是超时设置)、资源限制以及进行必要的性能分析和测试,通常能够定位并解决 Nginx 反向代理的 502 和 504 错误。日志始终是排障的第一线索! 保持耐心,逐步缩小问题范围。💪🏻