《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容器退出,日志里什么都没有》

相关推荐
木雷坞12 小时前
Qdrant Docker 部署教程:数据卷、API Key 和集合初始化
运维·docker·容器·知识图谱
团象科技12 小时前
外贸站选海外服务器 拆解跨境运营中常被忽略的核心性能细节
运维·服务器
Lv_沐曦13 小时前
银河麒麟桌面版安装、多屏配置、触摸校准
运维·docker·samba·vsftpd·银河麒麟·触控校准·多屏配置
半壶清水13 小时前
ubuntu下利用ns-3 + NetAnim搭建可视化路由选路过程的方法
linux·运维·ubuntu
ting945200014 小时前
SellerClaw 全栈技术深度拆解:基于多智能体集群的跨境电商全链路自动化系统实现
运维·自动化
三雷科技14 小时前
Rsync 命令详解:Linux 文件同步与备份的艺术
linux·运维·服务器
真实的菜14 小时前
Redis 从入门到精通(十三):性能优化与运维实战 —— 慢查询、内存优化、监控与安全
运维·redis·性能优化
j_xxx404_14 小时前
MySQL库操作硬核解析:字符集、校验规则、大小写比较、备份恢复与连接排查
运维·服务器·数据库·人工智能·mysql·ai·oracle
机汇五金_15 小时前
影响交换机箱体使用寿命的几个关键因素
运维·服务器·网络·python
无限进步_15 小时前
Linux进程终止——退出码、exit与_exit
linux·运维·服务器