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

相关推荐
小小、码农3 小时前
Linux进程控制:从fork到exec,手写一个简易Shell
linux·运维·服务器
不会就选b3 小时前
Linux之进程间通信(二)---模拟进程池
linux·运维·服务器
沫璃染墨5 小时前
《从零入门Linux系统篇(十五):系统工具篇·六——GDB调试器详解:从程序执行控制到高级调试技巧》
linux·运维·服务器·c语言·c++
AIgorithmGEEK6 小时前
Linux 环境变量完全指南:从入门到理解底层原理
linux·运维·服务器
修罗王6 小时前
Linux Docker 服务管理与排查实战指南(新手速查版)
运维·docker
迪康Defender6 小时前
从静态存储到动态流转:终端透明加密两种模式实战解析
运维·服务器·网络·数据库·其他
酷可达拉斯7 小时前
Linux操作系统-升级OpenSSH修复漏洞
linux·运维·服务器·云计算
张龙6878 小时前
Docker 镜像瘦身实战:从 1.2GB 到 128MB,我踩过的 7 个坑和一套可复制的方法论
运维·后端·docker
frank00600719 小时前
Dell 17G 服务器阵列卡(PERC)纵向与横向详细对比
运维·服务器
外滩运维专家9 小时前
Nginx 上的通配符证书 90 天到期,续签这事我是这么搞的
运维