《100个“反常识”经验15:Nginx 502排查:从应用到内核》

本期摘要

502 Bad Gateway 是 Nginx 最让人头疼的错误码之一。它不像 404 那样明确(文件不存在),而是表示"上游服务器返回了无效响应"。本文从一次真实故障切入,按"客户端 → Nginx → 应用 → 数据库"的链路分层排查,涵盖 upstream 超时、连接数耗尽、缓冲区不足、PHP‑FPM 崩溃、内核 backlog 溢出等常见原因。读完你就能在收到 502 告警时,快速定位是 Nginx 自身问题、后端应用问题,还是系统层面问题。

一次让人怀疑人生的故障

某个促销日,业务高峰,大量用户反馈页面打不开。Nginx 日志里全是:

text

复制代码
[error] 12345#0: *987654 connect() failed (110: Connection timed out) while connecting to upstream

502 扑面而来。运维同事第一反应:"后端服务挂了?"但检查应用进程,一切正常;检查数据库,也无异常。重启 Nginx 后短暂恢复,几分钟后又出现 502。

折腾了两个小时,发现问题出在 Nginx 与 PHP‑FPM 之间的 keepalive 配置不当,加上 upstream 响应过慢,导致连接池被耗尽。

502 的本质

Nginx 作为反向代理,接收到客户端请求后,需要向 upstream(后端应用服务器)发起新的请求。如果 Nginx 无法得到有效的 HTTP 响应,就会返回 502。

常见的上游类型:

  • HTTP 后端(Tomcat、Gunicorn、PHP‑FPM、Java 应用)

  • FastCGI(PHP‑FPM)

  • uWSGI(Python)

  • 代理服务器本身

排查四步法

第一步:查看 Nginx 错误日志

bash

复制代码
tail -f /var/log/nginx/error.log

错误日志会给出具体原因,常见错误包括:

日志关键字 含义 排查方向
connect() failed (110: Connection timed out) 连接上游超时 upstream 服务不可达或响应慢
connect() failed (111: Connection refused) 上游端口没开 upstream 服务未启动或挂掉
upstream timed out (110: Connection timed out) 读取响应头超时 upstream 处理太慢
no live upstreams 所有上游都挂了 检查 upstream 健康状态
client intended to send too large body 请求体过大 调大 client_max_body_size

第二步:检查 upstream 服务状态

如果是 HTTP 代理,直接 curl 测试:

bash

复制代码
curl -v http://127.0.0.1:8080/health   # 假设 upstream 在 8080 端口

如果超时或拒绝连接,问题在后端应用。

如果是 PHP‑FPM:

bash

复制代码
systemctl status php7.4-fpm
netstat -an | grep 9000   # 检查端口监听

第三步:检查 Nginx 与 upstream 之间的连接

连接数是否耗尽:

bash

复制代码
ss -an | grep 8080 | wc -l   # 看连接数
netstat -an | grep 8080 | grep TIME_WAIT | wc -l

如果 TIME_WAIT 堆积过多,调整内核参数或 Nginx keepalive。

upstream 响应时间:

在 Nginx 日志中记录请求时间:

bash

复制代码
log_format timed '$remote_addr - $request_time - $upstream_response_time - $request';
access_log /var/log/nginx/access.log timed;
  • $request_time:Nginx 处理总时间

  • $upstream_response_time:上游服务器响应时间

如果 $upstream_response_time 很大,说明后端慢;如果不大但 $request_time 大,可能是 Nginx 发送响应给客户端慢(网络问题)。

第四步:系统层面检查

net.core.somaxconn(监听队列长度)

bash

复制代码
sysctl net.core.somaxconn   # 默认 128,高并发时容易溢出

检查 Nginx backlog 配置

bash

复制代码
listen 80 backlog=1024;     # 增加队列容量

文件句柄限制:

bash

复制代码
ulimit -n                  # 查看当前进程可打开文件数
# 修改 /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535

常见场景及解决方案

场景 日志特征 解决方案
PHP‑FPM 响应慢 upstream timed out, 但 curl 能通 调大 fastcgi_read_timeout,优化 PHP 代码
后端服务连接池满 connect() failed (110: Connection timed out) 增加后端服务连接池,或调大 Nginx proxy_connect_timeout
TIME_WAIT 爆炸 ss 看到大量 TIME_WAIT 开启 proxy_http_version 1.1proxy_set_header Connection "",启用 keepalive
请求体过大 client intended to send too large body 增加 client_max_body_size
backlog 溢出 listen queue overflow 系统日志 增大 net.core.somaxconn 和 Nginx backlog
僵尸 upstream 被标记为 down no live upstreams 检查健康检查配置,必要时用 max_fails=0 禁止标记为 down

永久防范方案

1. 合理设置超时参数

nginx

复制代码
http {
    proxy_connect_timeout 5s;      # 连接上游超时
    proxy_send_timeout 10s;        # 发送数据超时
    proxy_read_timeout 10s;        # 接收响应超时
    fastcgi_read_timeout 60s;      # FastCGI 专用
}

2. 启用 upstream keepalive

nginx

复制代码
upstream backend {
    server 127.0.0.1:8080;
    keepalive 32;                 # 保持空闲连接数
}

server {
    location / {
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_pass http://backend;
    }
}

3. 使用健康检查

商业版 Nginx 支持主动健康检查。开源版可通过 max_failsfail_timeout 控制:

nginx

复制代码
upstream backend {
    server 10.0.0.1:8080 max_fails=3 fail_timeout=30s;
}

4. 监控与告警

  • 监控 Nginx error.log 中 502 的数量

  • 监控 upstream_response_time 的 P99 值

  • 监控 Nginx 连接数、TIME_WAIT 数量

下期预告

《100个"反常识"经验16:Docker容器退出,日志里什么都没有》

相关推荐
乘云数字DATABUFF4 天前
5分钟部署开源APM Databuff:OpenTelemetry全链路追踪入门实战
运维·后端
荣--6 天前
一键部署不是为了省时间 —— 它是把"买来的 PaaS"变成"自己的平台"的拐点
运维·zabbix·工程化·一键部署·平台化·边界设计
江华森6 天前
动手实战学 Docker — 从零到集群编排完全指南
运维
Avan_菜菜7 天前
FRP 内网穿透完整实战:从 HTTP 映射到 HTTPS 自签代理
运维·nginx·https
SelectDB8 天前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
XIAOHEZIcode9 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户03284722207010 天前
如何搭建本地yum源(上)
运维
ping某11 天前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
大树8813 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠13 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql