先把当时的情况摆出来。一台 4 核 8G 的 CentOS 7.9 上 nginx 反代本机的 Java 服务,页面间歇性 502,error.log 里是 connect() failed while connecting to upstream,ssh 登录后 curl 127.0.0.1:8080 又完全正常。
排查方向其实有限,先把可能性排一排。upstream 写的是 127.0.0.1:8080,但后端只监听在 ::1 上,IPv6 与 IPv4 是两个地址。还有一种是后端重启期间连接被拒,nginx 没有重试就直接返回 502。
还有一种情况,SELinux 不允许 nginx 主动发起网络连接,日志在 audit 里而不是 error.log。另外,upstream 的 max_fails 把刚起来的后端标记为不可用,需要 fail_timeout 才恢复。
先确认后端监听的地址族
ss -lntp | grep 8080
随后让 upstream 同时尝试两种地址
printf 'upstream app { server 127.0.0.1:8080; server [::1]:8080 backup; }\n' > /etc/nginx/conf.d/up.conf && nginx -t
然后检查 SELinux 是否有拒绝记录
ausearch -m avc -ts recent | grep nginx
剩下的就是加失败重试并观察错误日志
nginx -s reload && tail -f /var/log/nginx/error.log | grep -i upstream
报错是间歇性的,我蹲守了半小时才抓到一次完整现场。
恢复的判定其实很直接。error.log 里不再新增 connect() failed,访问返回 200,ss 显示后端监听在 nginx 实际连接的地址族上。
间歇性 502 多半是地址族或重启窗口造成的,别一上来就怀疑后端代码;SELinux 拦截时 nginx 的报错和网络故障一模一样,很难区分。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。
