0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Nginx 502 Bad Gateway错误的成因和排查方法

马哥Linux运维 来源:马哥Linux运维 2026-05-06 11:13 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

引言

502 Bad Gateway 是 Nginx 作为反向代理服务器时最常遭遇的错误状态码。这个错误意味着 Nginx 作为网关,成功与后端 upstream 建立了连接,但后端返回了一个无效响应,或者在传输过程中连接被异常关闭。表面上 502 只是一个 HTTP 状态码,实际上它是一系列配置错误、网络故障、后端异常的综合表现。

本文基于 Nginx 1.26.x/1.27.x(截至 2026 年 4 月的稳定版本)、PHP-FPM 8.2/8.3、Node.js 20 LTS/22 LTS 等最新稳定版本,系统性地拆解 502 错误的成因、排查方法、解决方案和预防策略。文章假设读者具备基本的 Linux 运维能力、Nginx 配置文件阅读经验,以及后端应用的调试基础。

一、问题场景:为什么需要关注 502 错误

1.1 502 是最常见的 Nginx 错误

在生产环境中,Nginx 作为入口网关承接所有外部流量。一旦出现 502 错误,意味着用户请求无法正常处理,直接影响业务可用性。根据多个大型网站的运维统计,Nginx 相关故障中 502 Bad Gateway 占到了 40% 至 60%,是所有 Nginx 错误码中出现频率最高的一种。

业务影响量化

用户点击链接后遭遇 502 页面,平均停留时长不超过 3 秒即会离开。对于电商网站,这直接导致购物车 abandonment;对于金融交易系统,502 可能意味着交易中断甚至数据不一致;对于 API 服务,502 会触发客户端重试风暴,进一步压垮后端。行业通用的估算公式是:每 1% 的 502 错误率可能导致 0.5% 至 2% 的业务损失,具体取决于业务类型和用户耐心度。

根因多样性与排查复杂性

502 错误的根因涵盖多个层面:网络层(物理链路中断、DNS 解析失败、防火墙拦截)、传输层(TCP 连接被重置、端口未监听)、应用层(后端进程崩溃、超时配置不合理、缓冲区溢出)、系统层(文件描述符耗尽、内存不足、内核参数限制)、安全层(SELinux/AppArmor 强制访问控制、iptables 规则拦截)。这种多层次性导致同一个 502 症状可能对应完全不同的根因。

多层代理架构进一步增加了排查难度。现代生产环境中,请求可能经过 CDN → 边缘 Nginx → 负载均衡层 → 应用 Nginx → 后端服务,其中任何一个节点的故障都可能以 502 形式呈现。而日志分散在多个层级,request_id 串联成为必要手段而非可选项。

日志阅读能力缺失是排查失败的主因

大量工程师遇到 502 后的第一反应是重启 Nginx 或后端服务,这种做法往往只能短暂恢复问题,无法根治。更深层的问题在于:Nginx error.log 中已经记录了详细的错误原因,但工程师不知道如何解读这些日志条目。例如"upstream prematurely closed connection"和"connect() failed (111: Connection refused)"虽然都导致 502,但指向的根因完全不同,处理方式也截然不同。

1.2 502 与 504:同样的网关错误,不同的根因

理解 HTTP 502 与 504 的本质区别,是准确定位问题的前提。

502 Bad Gateway

Nginx 向 upstream 发起请求并成功建立连接,但 upstream 返回了非正常的响应。这个响应可能是:连接建立后立即关闭(无任何数据返回)、返回了无效的 HTTP 响应(格式损坏)、连接被上游设备中断(RST 包)、或者 upstream 在协议层面出现错误(Nginx 无法解析上游的响应)。

典型错误日志:

2026/04/24 0832 [error] 12487#12487: *8921 upstream prematurely closed connection while reading response header of upstream, client: 203.0.113.45, server: api.example.com, request: "GET /api/v2/users HTTP/1.1", upstream: "http://127.0.0.1:8080/api/v2/users", upstream_connection: "9612", upstream_bytes_sent: 0, upstream_bytes_received: 0, upstream_trailers: "X-Request-Id: abc123"
2026/04/24 0918 [error] 12487#12487: *9234 connect() failed (111: Connection refused) while connecting to upstream, client: 198.51.100.23, server: www.example.com, request: "POST /api/orders HTTP/1.1", upstream: "http://127.0.0.1:9000/api/orders", upstream_connection: "128"

504 Gateway Timeout

Nginx 向 upstream 发起请求并成功建立了 TCP 连接,但 upstream 在规定时间内没有返回任何数据。超时触发后,Nginx 主动关闭连接并向客户端返回 504。504 的根因通常是后端处理时间过长(数据库查询阻塞、第三方 API 调用卡住、计算密集型任务卡死),或者 upstream 进程处于僵死状态(不崩溃但不处理请求)。

典型错误日志:

2026/04/24 1007 [error] 12487#12487: *10234 upstream timed out (110: Connection timed out) while reading response header of upstream, client: 203.0.113.89, server: api.example.com, request: "GET /api/reports HTTP/1.1", upstream: "http://127.0.0.1:8080/api/reports", upstream_connection: "15623", upstream_bytes_sent: 234, upstream_bytes_received: 0
2026/04/24 1133 [error] 12487#12487: *10891 upstream timed out (110: Connection timed out) after 30000 ms (110: Connection timed out) while connecting to upstream, client: 198.51.100.67, server: www.example.com, request: "POST /api/upload HTTP/1.1", upstream: "http://127.0.0.1:9090/api/upload"

499 Client Closed Request

这不是 Nginx 返回给客户端的错误码,而是 Nginx 记录的一种状态,表示客户端在 upstream 响应完成之前主动断开了连接(可能是客户端超时、用户取消请求、Nginx 侧配置了 client_body_timeout 或lingering_timeout 强制关闭)。499 不算 upstream 的故障,但在高并发场景下大量出现 499 可能暗示 upstream 处理速度过慢,迫使客户端等待超时。

2026/04/24 1245 [info] 12487#12487: *11567 client closed connection while waiting for response, client: 203.0.113.112, server: api.example.com, request: "GET /api/stream HTTP/1.1", upstream: "http://127.0.0.1:8080/api/stream"

500 vs 503 vs 502:细节差异

500 Internal Server Error:请求已经到达 upstream,upstream 在处理过程中发生了未捕获的异常或配置错误导致崩溃。这是 upstream 自身的问题,Nginx 只是转发了上游的错误响应。

503 Service Temporarily Unavailable:upstream 正常工作且能够响应,但 Nginx 的限流模块(limit_req_zone)或连接数限制(limit_conn_zone)触发了降级。503 通常带有 Retry-After 头,暗示客户端稍后重试。

502 Bad Gateway:upstream 连接失败或返回了无效响应。可能是 upstream 彻底不可用,也可能是连接建立后数据交换过程中断裂。

1.3 典型踩坑场景分类

在多年的生产环境排障经历中,502 错误可以归纳为以下典型场景。每个场景都有其特征性日志和明确的解决路径。

场景一:upstream 配置错误

最基础的配置错误是 ip:port 写错或域名解析失败。Nginx 启动时不会验证 upstream 的可到达性,只有在实际请求时才会尝试连接。如果配置中写错了 IP 地址(例如 127.0.0.18 而不是 127.0.0.1),或者端口号与实际监听不一致,Nginx 会在 error.log 中记录"Connection refused"错误。

# 错误配置示例
upstream backend {
  server 127.0.0.1:8081; # 实际服务运行在 8080 端口
}

# 正确配置
upstream backend {
  server 127.0.0.1:8080;
}

场景二:后端服务未启动

这是最常见也最容易被忽视的场景。Nginx 进程由 systemd 托管可以保证 Nginx 自身的高可用,但后端服务(PHP-FPM、Node.js 应用、Gunicorn、Tomcat 等)可能因为各种原因退出:OOM Killer 杀死进程、代码 bug 导致崩溃、依赖的数据库或中间件不可用。Nginx 仍然在运行,请求到达后才发现 upstream 无响应。

# systemctl 检查 PHP-FPM 状态
$ systemctl status php-fpm
● php-fpm.service - PHP FastCGI Process Manager
  Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; enabled; vendor preset: enabled)
  Active: inactive (dead) since Thu 2026-04-24 0812 CST; 2h 15min ago
  Main PID: 4521 (code=exited, status=0/SUCCESS)

场景三:超时设置过短

Nginx 的默认超时值通常比较保守(proxy_connect_timeout 60s、proxy_read_timeout 60s)。对于处理时间较长的请求(如文件上传、大数据量导出、复杂数据库查询、调用外部 API),默认超时会导致正常请求被误杀。

# 默认超时配置(过短)
proxy_read_timeout 60s; # 60秒对于复杂查询不够

# 优化后的超时配置
proxy_read_timeout 300s; # 根据业务特点调整
proxy_connect_timeout 10s; # 连接超时可以保持较短

场景四:缓冲区配置不当

Nginx 使用缓冲区来暂存 upstream 的响应数据。当 upstream 返回大文件或流式数据时,缓冲区配置不足会导致内存溢出或写入磁盘临时文件,极端情况下会触发 502。缓冲区满的症状是 error.log 中出现"upstream buffer is too small"或大量临时文件被写入 /var/lib/nginx/proxy。

# 缓冲区不足的典型日志
2026/04/24 1415 [warn] 12487#12487: *12891 an upstream response is buffered to a temporary file /var/lib/nginx/proxy/0000000123, size: 16384 bytes, expect: 5242880 bytes

场景五:keepalive 配置缺失

HTTP/1.1 默认支持 keepalive 连接复用。如果 upstream 块中没有配置 keepalive,Nginx 会为每个请求创建新的 TCP 连接。高并发场景下,频繁的 TCP 握手/挥手消耗大量资源,可能导致 upstream 过载或连接数溢出。

# 没有 keepalive 的 upstream 配置
upstream backend {
  server 127.0.0.1:8080;
}

# 优化后:配置 keepalive 连接池
upstream backend {
  server 127.0.0.1:8080;
  keepalive 32; # 保持 32 个空闲连接
  keepalive_requests 1000; # 每个连接最多处理 1000 请求
  keepalive_timeout 60s; # 空闲连接保持 60 秒
}

场景六:权限问题

当 upstream 使用 Unix Domain Socket 通信时,socket 文件的权限和所有权必须与 Nginx worker 进程的用户匹配。PHP-FPM 默认使用 www-data 用户创建 socket,而 Nginx 默认使用 nginx 用户运行 worker 进程,两者不匹配时会导致"Permission denied"错误。

# /var/log/nginx/error.log 中的权限错误
2026/04/24 1527 [crit] 12487#12487: *13456 connect() to unix:/var/run/php-fpm/www.sock failed (13: Permission denied) while connecting to upstream

SELinux 强制访问控制是另一个容易忽视的权限问题。即使 socket 文件权限正确,SELinux 策略也可能阻止 Nginx 与后端通信。

二、核心原理与关键概念拆解

2.1 Nginx 处理请求的完整流程

理解 Nginx 内部处理请求的各个阶段,是准确定位 502 根因的基础。Nginx 采用模块化架构,请求处理分为 11 个阶段(phase):post-read、server-rewrite、find-config、rewrite、post-rewrite、preaccess、access、post-access、precontent、content、log。502 错误主要发生在 content 阶段和 log 阶段之间。

连接接受阶段

Nginx master 进程监听配置的端口(80/443),worker 进程通过 accept_mutex 机制竞争接受新连接。在多核系统中,Nginx 默认使用 epoll 事件模型高效处理大量并发连接。关键配置参数:

worker_connections:每个 worker 进程可处理的最大连接数(默认 512)

multi_accept on:每个 worker 进程尽可能多地接受新连接

use epoll:使用 epoll 事件模型(Linux 高效)

# 查看当前 Nginx 连接状态
$ ss -s
Total: 298 (kernel 0)
TCP:  185 (estab 142, closed 12, orphaned 0, synrecv 0, timewait 5/0)

Transport Total   IP    IPv6
*     298    -     -
RAW    0     0     0
UDP    12    8     4
TCP    173    166    7
INET   185    174    11
FRAG   0     0     0

$ nginx -V 2>&1 | grep -o'with-http_stub_status_module'
with-http_stub_status_module

# 启用状态页面查看连接详情
location /nginx_status {
  stub_status on;
  access_log off;
  allow 127.0.0.1;
  deny all;
}
$ curl http://127.0.0.1/nginx_status
Active connections: 142
server accepts handled requests
1289345 1289345 3456782
Reading: 3 Writing: 12 Waiting: 127

请求解析与 Location 匹配

连接接受后,Nginx 解析 HTTP 请求行和请求头,根据 server_name(基于 Host header 匹配)和 location 块(精确匹配或正则匹配)确定请求的处理方式。对于反向代理配置,请求最终会进入 proxy_pass 或 fastcgi_pass 处理。

# nginx.conf 中的 server 块和 location 匹配示例
server {
  listen 80;
  server_name api.example.com;

 # 精确匹配 /api/
  location = /api/ {
    proxy_pass http://backend_api;
  }

 # 前缀匹配 /api/v2/
  location /api/v2/ {
    proxy_pass http://backend_v2;
  }

 # 正则匹配(~ 区分大小写,~* 不区分大小写)
  location ~* ^/api/vd+/users {
    proxy_pass http://backend_users;
  }
}

代理转发阶段

请求匹配到 proxy_pass 或 fastcgi_pass 后,Nginx 作为反向代理与 upstream 通信。反向代理的核心流程:

解析 proxy_pass 指令,确定 upstream 地址

从 upstream 块中选择一个 server(默认加权轮询)

建立与 upstream 的 TCP 连接(触发 connect 事件)

发送 HTTP 请求(可能受限于 send_timeout)

接收 upstream 响应头(受限于 proxy_read_timeout)

接收 upstream 响应体(受限于 buffer 配置)

将响应转发给客户端

# 核心 proxy 配置解析
location / {
  proxy_pass http://backend; # 指向 upstream 块

 # 以下请求头默认会被传递
 # Host: $host
 # X-Real-IP: $remote_addr
 # X-Forwarded-For: $proxy_add_x_forwarded_for
 # X-Forwarded-Proto: $scheme

  proxy_http_version 1.1; # 默认 1.0,1.1 支持 chunked 编码
  proxy_set_header Host$host;
  proxy_set_header X-Real-IP$remote_addr;
  proxy_set_header X-Forwarded-For$proxy_add_x_forwarded_for;
}

响应处理与缓冲区机制

Nginx 收到 upstream 响应后,先将响应头存入proxy_buffer_size(默认 4k/8k),响应体存入proxy_buffers配置的缓冲区。如果响应体数据量超过可用缓冲区总和,剩余数据会写入磁盘临时文件(受proxy_max_temp_file_size限制,默认 1024m)。

缓冲区满或写入临时文件时,Nginx 不会立即返回 502,但如果 upstream 发送速度过快且 buffer 机制未启用(proxy_buffering off),则可能出现数据积压导致超时。

# 缓冲区配置详解
proxy_buffering on; # 启用缓冲区(默认开启)
proxy_buffer_size 128k; # 响应头缓冲区,通常 128k 足够
proxy_buffers 8 256k; # 8 个 256k 缓冲区,用于响应体
proxy_busy_buffer_size 256k; # 忙碌时使用的缓冲区大小
proxy_max_temp_file_size 1024m; # 临时文件总大小上限
proxy_temp_file_write_size 128k; # 每次写入临时文件的大小

连接关闭与 keepalive

HTTP/1.1 默认使用 keepalive 保持连接复用。Nginx 通过keepalive_timeout控制连接保持打开的空闲时间,通过keepalive_requests限制单个连接处理的最大请求数。proxy 模块通过proxy_http_version 1.1和proxy_set_header Connection ""来管理与 upstream 的 keepalive 连接。

# upstream keepalive 配置
upstream backend {
  server 127.0.0.1:8080;
  keepalive 32; # 保持 32 个空闲连接
  keepalive_requests 1000;
  keepalive_timeout 60s;
}

location / {
  proxy_pass http://backend;
  proxy_http_version 1.1; # 必须使用 1.1 才能支持 keepalive
  proxy_set_header Connection""; # 清除 Connection 头
}

2.2 upstream 健康检查机制

Nginx upstream 模块支持被动健康检查,通过 max_fails 和 fail_timeout 参数实现故障节点的自动剔除。对于需要主动探测的场景,可以使用第三方模块 nginx_upstream_check_module。

被动健康检查

Nginx 默认对每个 upstream server 进行被动健康检查。当某个 server 连续 max_fails 次连接失败(Connection refused、timeout 等),Nginx 会将该 server 标记为不可用,持续 fail_timeout 秒后重新尝试。

# upstream 被动健康检查配置
upstream backend {
  server 127.0.0.1:8080 max_fails=3 fail_timeout=10s;
  server 127.0.0.1:8081 max_fails=3 fail_timeout=10s;
  server 127.0.0.1:8082 max_fails=3 fail_timeout=10s backup;
}

参数说明:

max_fails:默认 1。设置为 0 则禁用对该 server 的健康检查。

fail_timeout:默认 10s。既是 server 被判定为不可用后持续的时间,也是统计失败次数的时间窗口。

backup:标记为备用服务器,仅在主服务器全部不可用时才启用。

# 查看 upstream 配置和状态
$ nginx -T 2>&1 | grep -A 20"upstream backend"
upstream backend {
  server 127.0.0.1:8080 weight=5 max_fails=3 fail_timeout=10s;
  server 127.0.0.1:8081 weight=3 max_fails=3 fail_timeout=10s;
  server 127.0.0.1:8082 backup;
}

# 观察 error.log 中标记 server 不可用的日志
2026/04/24 0812 [warn] 12487#12487: *2341 upstream server temporarily disabled while connecting to upstream, client: 203.0.113.45, server: api.example.com, request: "GET /api/health HTTP/1.1", upstream: "http://127.0.0.1:8080/api/health"

主动健康检查(nginx_upstream_check_module)

官方 Nginx 不包含主动健康检查模块,需要使用阿里巴巴开源的 nginx_upstream_check_module。该模块允许 Nginx 主动向后端发送 TCP/HTTP 心跳包,根据响应判断 server 是否健康。

# 编译安装时加载模块
./configure --add-module=/path/to/nginx_upstream_check_module

# upstream 配置中添加主动健康检查
upstream backend {
  server 127.0.0.1:8080;
  server 127.0.0.1:8081;

 # 每隔 3 秒对所有 server 进行检查
 # 检查类型为 HTTP,检查 URI /health
 # 超时 1 秒,连续失败 2 次则标记为不可用
  check interval=3000 rise=2 fall=2 timeout=1000type=http;
  check_http_send"HEAD /health HTTP/1.0

";
  check_http_expect_alive http_2xx http_3xx;
}

# 状态页面查看健康检查结果
location /upstream_status {
  check_status;
  access_log off;
  allow 127.0.0.1;
  deny all;
}
$ curl http://127.0.0.1/upstream_status
Upstream server status:
backend
 server 127.0.0.1:8080   up   1234567890 ms
 server 127.0.0.1:8081   down  0 ms (2/2)

动态 upstream 与服务发现

在容器化和微服务架构中,upstream 列表需要动态更新。常见方案:

Consul/Etcd + Consul-template 或 etcd dynamical:通过服务发现系统维护后端列表,使用模板工具动态生成 Nginx 配置文件并 reload。

OpenResty + lua-upstream-nginx-module:使用 Lua 脚本直接操作 Nginx upstream 内存结构,实现运行时更新。

Nginx Plus 商业版:原生支持 DNS 发现和 API 动态修改 upstream。

# consul-template 配置文件示例
upstream backend {
 least_conn;

 {{ range service"backend"}}
 server {{ .Address }}:{{ .Port }};
 {{ end }}
}

2.3 缓冲区机制深度解析

缓冲区是 Nginx 与 upstream 之间数据传输的核心机制。理解缓冲区的工作方式,能够解释许多看似莫名其妙的超时和 502 错误。

proxy_buffer_size:响应头缓冲区

Nginx 收到 upstream 的响应状态行和响应头后,将其存储在proxy_buffer_size指定的内存区域中。默认值为 4k 或 8k(取决于操作系统页大小)。对于绝大多数 HTTP 响应头,这个大小足够。如果 upstream 返回的响应头过大(如大量 Cookie、复杂 CSP 头),可能需要增大此值。

# 响应头过大时的错误日志
2026/04/24 0933 [warn] 12487#12487: *4521 could not build large header, shoulder increase the size of proxy_buffer_size
# 调整响应头缓冲区
proxy_buffer_size 256k; # 增大到 256k

proxy_buffers:响应体缓冲区

响应体数据块被缓存在proxy_buffers分配的内存缓冲区中。如果响应体总大小超过所有缓冲区的总容量,剩余数据会写入磁盘临时文件。临时文件路径由proxy_temp_path指定(默认 /var/lib/nginx/proxy)。

# 默认配置
proxy_buffers 8 4k/8k; # 8 个缓冲区,每个 4k 或 8k

# 大文件下载场景
proxy_buffers 16 32k;
proxy_buffering on; # 确保启用
proxy_max_temp_file_size 2048m; # 允许最大 2G 临时文件
# 出现大量临时文件时的告警日志
2026/04/24 1015 [warn] 12487#12487: *7823 upstream sent chunked body with size larger than the whole proxy buffers space while reading upstream

proxy_busy_buffer_size:忙碌缓冲区

当 Nginx 开始向客户端发送响应时,如果客户端网络速度较慢,Nginx 会继续从 upstream 读取数据并存入缓冲区。proxy_busy_buffer_size定义了在等待客户端接收数据时可以使用的最大缓冲区总大小。默认等于proxy_buffer_size或proxy_buffers中的单个缓冲区大小。

fastcgi_buffering / uwsgi_buffering / scgi_buffering

对于 PHP-FPM 环境,使用 fastcgi_pass 时,缓冲区配置指令前缀变为fastcgi_buffer_。原理与 proxy buffering 完全一致。

# PHP-FPM 环境缓冲区配置
fastcgi_buffering on;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_max_temp_file_size 1024m;
fastcgi_temp_file_write_size 128k;

2.4 超时体系全面解析

Nginx 的超时配置构成一个多层次的体系,不同的超时指令控制请求处理的不同阶段。错误地设置超时是导致 502 和 504 的最常见原因。

proxy_connect_timeout:建立连接的超时

Nginx 等待与 upstream 建立 TCP 握手完成的超时。如果 upstream 服务器的端口未监听或网络不通,这个超时会在第一次连接尝试时触发。默认值 60s 通常足够,但如果 upstream 位于跨地域网络或高负载环境中,可能需要适当调大。

# 默认 60 秒,跨地域场景可调大
proxy_connect_timeout 60s;

# 高延迟网络环境
proxy_connect_timeout 10s; # 10 秒足够检测出不可达
# connect timeout 的错误日志
2026/04/24 1108 [error] 12487#12487: *8921 connect() failed (110: Connection timed out) while connecting to upstream, client: 203.0.113.45, upstream: "http://10.0.1.55:8080/"

proxy_send_timeout:向后端发送请求的超时

Nginx 向 upstream 发送请求体的超时。对于 POST/PUT 请求(表单提交、文件上传、API 调用),如果请求体数据量大或上游处理慢,可能触发此超时。默认值 60s。

# 文件上传等大请求场景
proxy_send_timeout 300s; # 5 分钟
client_max_body_size 100m; # 允许最大请求体 100M

proxy_read_timeout:读取后端响应的超时

Nginx 从 upstream 读取响应头和响应体的总超时。这是生产环境中最常需要调整的参数。默认值 60s,对于复杂业务逻辑、数据库查询、第三方 API 调用等场景,60s 往往不够。

# 长时间处理的后端服务
proxy_read_timeout 300s; # 5 分钟
proxy_send_timeout 300s;

# 实时性要求高的 API
proxy_read_timeout 30s;
# read timeout 的错误日志
2026/04/24 1245 [error] 12487#12487: *10234 upstream timed out (110: Connection timed out) while reading response header of upstream, client: 198.51.100.23, upstream: "http://127.0.0.1:8080/api/report"

send_timeout:发送给客户端的超时

控制 Nginx 向客户端发送数据的超时,与 upstream 无关。如果客户端网络慢或客户端停滞,Nginx 在send_timeout期间未发送任何数据后会关闭连接。这个超时不影响 502,但可能导致客户端收到不完整的响应。

# 默认 60 秒
send_timeout 60s;

keepalive_timeout:keepalive 空呆时间

HTTP/1.1 keepalive 连接在空闲状态下保持的最大时间。超过此时间未收到任何数据,Nginx 会主动关闭连接。

# keepalive 超时设置
keepalive_timeout 75s; # 默认 75 秒
keepalive_requests 1000; # 单连接最大请求数

超时时间的实际计算逻辑

多个超时参数可能同时生效。Nginx 在各个阶段分别计时:

TCP 连接建立:proxy_connect_timeout

请求体发送:proxy_send_timeout(从连接建立到请求体发送完成)

等待响应头:proxy_read_timeout(从请求发送完成到收到响应头)

读取响应体:proxy_read_timeout 继续累积(从收到响应头到响应体读取完成)

三、实战步骤与常见排障路径

3.1 502 问题排查的黄金法则

502 错误的排查需要遵循系统化的步骤,从表象到根因逐层递进。下列步骤经过大量生产环境验证,可以快速定位绝大多数 502 问题。

第一步:确认是否真的是 502

使用 curl -v 查看详细的 HTTP 交互过程,观察 502 是在哪个阶段发生的。

$ curl -v http://api.example.com/api/v2/users 2>&1
* About to connect() to api.example.com port 80 (#0)
*  Trying 203.0.113.10...
* Connected to api.example.com (203.0.113.10) port 80 (#0)
> GET /api/v2/users HTTP/1.1
> User-Agent: curl/8.4.0
> Host: api.example.com
> Accept: */*
>
< HTTP/1.1 502 Bad Gateway
< Server: nginx/1.26.2
< Date: Fri, 24 Apr 2026 0812 GMT
< Content-Type: text/html
< Content-Length: 157
< Connection: keep-alive
<
{ [data not shown]
* Connection #0 to host api.example.com left intact
* Closure expected

从 curl 输出可以确认:TCP 连接成功建立(Connected),Nginx 返回了 502 状态码,Server 头显示 Nginx 版本为 1.26.2。这说明问题发生在 Nginx 与 upstream 之间。

第二步:检查 Nginx 错误日志

Nginx error.log 是定位 502 根因的第一手资料。配置error_log级别为 info 或 debug 可以获取更详细的调试信息,但需要注意日志量激增对磁盘和性能的影响。

# 实时跟踪 error.log 中的 502 相关错误
$ tail -f /var/log/nginx/error.log | grep -E"(502|upstream|connect|timed out)"

# 统计最近 1000 条日志中各类错误的数量
$ awk'/[error]/ {count++} /502/ {502count++} /timed out/ {timeout++} /Connection refused/ {refused++} END {print "Total errors:", count, "502 errors:", 502count, "Timeouts:", timeout, "Connection refused:", refused}'/var/log/nginx/error.log
Total errors: 234 502 errors: 45 Timeouts: 12 Connection refused: 33

# 查看错误上下文(前后 5 行)
$ grep -C 5"502"/var/log/nginx/error.log | head -100

# 统计 502 错误的来源 IP
$ awk'/502/ && /client: / {gsub(/,.*/, "", $6); print $6}'/var/log/nginx/error.log | sort | uniq -c | sort -rn
  23 203.0.113.45
  15 198.51.100.123
   7 192.0.2.89
# error.log 配置建议
error_log /var/log/nginx/error.log warn; # 生产环境使用 warn 级别,调试时使用 info

# 调试时临时开启 debug(仅限测试环境)
error_log /var/log/nginx/error.log debug;
# debug 日志量极大,务必在完成调试后恢复

第三步:检查后端服务状态

后端服务未启动或异常是最常见的 502 根因。检查后端进程是否存活、端口/socket 是否监听、进程资源使用情况。

# 检查 PHP-FPM 进程状态
$ systemctl status php-fpm
● php-fpm.service - PHP FastCGI Process Manager
  Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; enabled; vendor preset: enabled)
  Active: active (running) since Thu 2026-04-24 0600 CST; 2h 15min ago
 Main PID: 4521 (php-fpm)
  Status:"祥 system is running..."
  Tasks: 12 (limit: 32768)
  Memory: 245.6M
  CGroup: /system.slice/php-fpm.service
      ├─4521 php-fpm: master process (/etc/php-fpm.conf)
      ├─4522 php-fpm: pool www
      ├─4523 php-fpm: pool www
      └─4524 php-fpm: pool www

# 检查监听端口
$ ss -tlnp | grep -E':(80|443|8080|9000|php)'
State  Recv-Q  Send-Q  Local Address:Port  Peer Address:Port  Process
LISTEN  0    511   127.0.0.1:9000     0.0.0.0:*      users:(("php-fpm",pid=4522,fd=9),("php-fpm",pid=4523,fd=9))
LISTEN  0    511   0.0.0.0:8080      0.0.0.0:*      users:(("node",pid=3421,fd=18))
LISTEN  0    511   0.0.0.0:80       0.0.0.0:*      users:(("nginx",pid=12487,fd=6),("nginx",pid=12488,fd=6))

# 如果使用 Unix socket
$ ls -la /var/run/php-fpm/
total 8
srwxr-xr-x 3 root www-data www-data 120 Apr 24 06:00 /var/run/php-fpm/
srwxrwxrwx 1 www-data www-data  6 Apr 24 06:00 www.sock

# 测试 socket 连接性(使用 php-fpm 官方探活接口)
$ SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET cgi-fcgi -bind-connect /var/run/php-fpm/www.sock
Content-type: text/plain
X-Powered-By: PHP 8.3.8
Status: 200 OK
X-Request-Id: abc123
Free: 1
MPool: enabled
Prober:builtin
Content-Length: 6
OK

# 检查后端进程 CPU 和内存占用
$ top -b -n 1 | head -20
top - 0833 up 42 days, 3:22, 2 users, load average: 3.45, 2.89, 2.76
Tasks: 287 total,  5 running, 282 sleeping,  0 stopped,  0 zombie
%Cpu(s): 78.5 us, 12.3 sy, 0.0 ni, 9.2 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 32768.0 total,  4523.4 free, 18234.5 used, 10010.1 buff/cache
MiB Swap:  8192.0 total,  8192.0 free,   0.0 used. 11234.3 avail Mem

 PID USER   PR NI  VIRT  RES  SHR S %CPU %MEM   TIME+ COMMAND
4522 www-data 20  0 523456 28934  9212 S 45.2  0.1 234:56 php-fpm
4523 www-data 20  0 512234 24567  8734 S 38.7  0.1 198:34 php-fpm
3421 root   20  0 1245678 456123 23456 S 12.3  1.4  56:78 node

第四步:确认网络连通性

排除物理网络层面的问题。即使 upstream 在本机,也需要验证端口可连接性。

# telnet 测试端口连通性(交互式命令,Ctrl+] 退出)
$ telnet 127.0.0.1 8080
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is'^]'.

# nc 测试端口连通性(更现代的方式)
$ nc -zv 127.0.0.1 8080
Connection to 127.0.0.1 8080 port [tcp/*] succeeded!

$ nc -zv 127.0.0.1 9000 -w 3
Connection to 127.0.0.1 9000 port [tcp/*] succeeded!

# 如果是域名形式的 upstream,测试 DNS 解析
$ dig +short api-backend.internal.example.com
10.0.1.55
10.0.1.56
10.0.1.57

$ nslookup api-backend.internal.example.com

# 测试 TCP 握手时间(使用 httping)
$ httping -g http://127.0.0.1:8080/health -c 3
PING 127.0.0.1:8080 (to=127.0.0.1):
connected to 127.0.0.1:8080 (301 bytes), seq=0 time=00.35 ms
connected to 127.0.0.1:8080 (301 bytes), seq=1 time=00.31 ms
connected to 127.0.0.1:8080 (301 bytes), seq=2 time=00.28 ms
--- http://127.0.0.1:8080/ ping statistics ---
3 connects, 3 ok, 0.00% roundtrip loss, 0.0/3.0/0.3/0.4 ms min/avg/max

# iptables/firewalld 规则检查
$ iptables -L -n | grep -E'(DROP|REJECT)'| head -20
$ firewall-cmd --list-all 2>/dev/null

第五步:验证 upstream 配置是否正确

检查 nginx.conf 中 upstream 块的配置,确保 IP 地址、端口、权重、备份服务器等参数正确。

# 测试 Nginx 配置语法
$ nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conftestis successful

# 完整输出配置树(包含所有 include 文件)
$ nginx -T 2>&1 | head -500

# 检查特定 upstream 块的配置
$ nginx -T 2>&1 | grep -A 10"^  upstream backend"

3.2 日志深度解读

Nginx error.log 中记录的错误信息是诊断 502 问题最直接的证据。不同的错误信息对应不同的根因和处理方式。

"upstream prematurely closed connection"

表示 Nginx 与 upstream 之间的连接在 Nginx 读取完响应头之前就被 upstream 主动关闭。这通常意味着 upstream 进程崩溃、OOM 被杀、或遭遇了致命错误。

# 典型日志
2026/04/24 0832 [error] 12487#12487: *8921 upstream prematurely closed connection while reading response header of upstream, client: 203.0.113.45, server: api.example.com, request: "GET /api/v2/users HTTP/1.1", upstream: "http://127.0.0.1:8080/api/v2/users", upstream_connection: "9612", upstream_bytes_sent: 234, upstream_bytes_received: 0

关键字段解读:

upstream prematurely closed connection:根因,upstream 提前关闭了连接

upstream_connection: "9612":Nginx 侧连接的标识符,可用于关联同一连接的多次请求

upstream_bytes_sent: 234:已发送给 upstream 的字节数

upstream_bytes_received: 0:从 upstream 收到的字节数,说明 upstream 尚未返回任何数据就被关闭了

排查步骤:

检查 upstream 服务(后端应用)的错误日志,寻找崩溃或 panic 的记录

检查系统日志(dmesg、/var/log/messages)是否有关于 OOM Killer 的记录

确认后端服务是否因为代码 bug、资源耗尽而崩溃

# 检查 dmesg 中的 OOM Killer 记录
$ dmesg -T | grep -i"oom|killed process"| tail -20
[Thu Apr 24 0800 2026] php-fpm[4522]: oom_reaper: reaped process 4522 (php-fpm), now anon-rss: 0kb, file-rss: 0kb

# 检查 /var/log/messages 中的相关记录
$ grep -i"oom|kill|php-fpm"/var/log/messages | tail -30

"connect() failed (111: Connection refused)"

Nginx 尝试连接 upstream 时,目标端口无进程监听。这是配置错误或后端服务未启动的明确信号

# 典型日志
2026/04/24 0918 [error] 12487#12487: *9234 connect() failed (111: Connection refused) while connecting to upstream, client: 198.51.100.23, server: www.example.com, request: "POST /api/orders HTTP/1.1", upstream: "http://127.0.0.1:9000/api/orders", upstream_connection: "128"

关键字段解读:

connect() failed:连接建立失败

(111: Connection refused):系统级 errno,111 = ECONNREFUSED,表示目标地址有响应但端口未监听(对比 ENETUNREACH = Network unreachable)

排查步骤:

确认 upstream 服务进程是否运行:systemctl status php-fpm或ss -tlnp

确认 upstream 配置的 IP:端口是否正确

如果是 Unix socket,确认 socket 文件是否存在且权限正确

# 模拟 Nginx 的连接行为
$ strace -e trace=connect -s 200 nginx -s reload 2>&1 | grep -i"connection refused"
# 或者对已知的后端端口抓包
$ tcpdump -i lo port 9000 -nn 2>&1

"no live upstreams while connecting"

所有 upstream server 都不可用,Nginx 找不到可用的后端节点。

# 典型日志
2026/04/24 1007 [error] 12487#12487: *10234 no live upstreams while connecting to upstream, client: 203.0.113.89, server: api.example.com, request: "GET /api/health HTTP/1.1"

排查步骤:

检查 upstream 块中所有 server 的健康状态

可能是所有 server 都触发了 max_fails 阈值被暂时禁用

检查 Nginx 配置中是否有语法错误导致 upstream 块无效

# 检查 upstream 配置
$ nginx -T 2>&1 | grep -A 15"upstream backend"

# 检查所有 upstream server 是否都被标记为 down
# 在 error.log 中搜索 upstream server 状态变化
$ grep"upstream.*server.*down|upstream.*server.*disabled"/var/log/nginx/error.log | tail -20
2026/04/24 0812 [warn] 12487#12487: *234 upstream server 127.0.0.1:8080 is marked as down
2026/04/24 0815 [warn] 12487#12487: *235 upstream server 127.0.0.1:8081 is marked as down

"upstream timed out (110: Connection timed out)"

与 upstream 的连接建立成功,但在 proxy_read_timeout 规定的时间内未收到响应,Nginx 主动关闭连接。

# 典型日志 - 响应头超时
2026/04/24 1133 [error] 12487#12487: *10891 upstream timed out (110: Connection timed out) after 30000 ms (110: Connection timed out) while connecting to upstream, client: 198.51.100.67, server: www.example.com, request: "POST /api/upload HTTP/1.1", upstream: "http://127.0.0.1:9090/api/upload"

# 典型日志 - 读取响应超时
2026/04/24 1244 [error] 12487#12487: *11567 upstream timed out (110: Connection timed out) while reading response header of upstream, client: 203.0.113.112, server: api.example.com, request: "GET /api/reports HTTP/1.1", upstream: "http://127.0.0.1:8080/api/reports", upstream_connection: "15623"

排查步骤:

检查后端服务的处理时间(数据库查询、文件 I/O、第三方 API 调用)

确认 proxy_read_timeout 设置是否合理

使用后端应用自身的慢查询日志定位瓶颈

# PHP-FPM 慢查询日志
$ grep -i"slow"/var/log/php-fpm/www-slow.log | tail -20
[24-Apr-2026 1112] [pool www] pid 5534
script: /var/www/html/api/report.php
call: mysqli_query
time: 45.234567 s
memory: 128.00M

# Node.js 慢日志(使用 --inspect 配合 APM 工具)
$ journalctl -u node-backend --since"2026-04-24 1100"| grep -i"slow|timeout"

access.log 的 502 占比统计

通过分析 access.log 中各类状态码的分布,可以量化 502 错误的严重程度和变化趋势。

# 统计 access.log 中各状态码的数量
$ awk'{code[$9]++} END {for (c in code) print c, code[c]}'/var/log/nginx/access.log | sort -k2 -rn
200 1289345
502 4523
499 1234
304 890
404 567
500 234
503 89

# 计算 502 错误率
$ total=$(wc -l < /var/log/nginx/access.log); errors502=$(grep -c " 502 " /var/log/nginx/access.log); echo"scale=4; $errors502 / $total * 100" | bc
0.3489%

# 按时间段统计 502 错误
$ awk '$4 ~ /[24/Apr/2026:1[0-2]/ && $9 == 502 {hour[$4]++} END {for (h in hour) print h, hour[h]}' /var/log/nginx/access.log
[24/Apr/202600:00 +0800] 23
[24/Apr/202600:00 +0800] 45
[24/Apr/202600:00 +0800] 12

# 统计产生 502 错误最多的请求路径
$ awk '$9 == 502 {path[$7]++} END {for (p in path) print path[p], p}' /var/log/nginx/access.log | sort -rn | head -10
234 /api/v2/users
189 /api/orders/submit
123 /api/reports/generate
67 /api/payments/callback

日志级别配置与影响

Nginx 日志级别从低到高:debug、info、notice、warn、error、crit、alert、emerg。生产环境建议使用 warn 或 error 级别,避免 debug 级别产生过大的日志量。

# 日志级别说明
debug: 调试信息,仅在编译时 --with-debug 启用
info: 一般信息
notice: 需要注意的信息
warn: 警告信息,可能存在问题但不影响运行
error: 错误信息
crit: 严重错误,部分功能不可用
alert: 必须立即处理
emerg: 系统不可用
# 配置示例
error_log /var/log/nginx/error.log warn;

# 临时开启 debug(测试环境)
error_log /var/log/nginx/error.log debug;

# debug 级别的连接追踪
events {
  debug_connection 203.0.113.0/24; # 仅对特定 IP 开启 debug
  debug_connection 127.0.0.1;
}

分布式 trace:request_id 串联日志

在多层代理架构中,单个请求可能经过多个 Nginx 节点。使用 request_id 将各层日志串联起来,可以实现端到端的请求追踪。

# Nginx 自动生成 $request_id(1.11.0+)
# 格式:16 字节的十六进制随机数

# 在请求头中传递 request_id
location / {
  proxy_pass http://backend;
  proxy_set_header X-Request-ID$request_id;
}

# 在 PHP 中获取 request_id
$requestId=$_SERVER['HTTP_X_REQUEST_ID'] ??'';

# 在 Node.js 中获取 request_id
const requestId = req.headers['x-request-id'];

# 查询串联后的日志
$ grep"X-Request-Id: abc12345"/var/log/nginx/error.log
2026/04/24 0832 [error] 12487#12487: *8921 upstream prematurely closed connection..., request_id: "abc12345"
2026/04/24 0833 [error] 4522#4522: *8921 php-fpm: pool www: child exited..., request_id: "abc12345"

$ grep"abc12345"/var/log/php-fpm/www-error.log
[24-Apr-2026 0832 UTC] PHP Fatal error: Allowed memory size of 128M exhaustedin/var/www/html/api/v2/users.php on line 234, request_id: abc12345

3.3 常见场景的排障路径

场景一:PHP-FPM 进程全挂

PHP-FPM 是最常见的后端服务之一,PHP-FPM 进程异常退出是导致 502 的高频原因。

症状识别

error.log 大量"connect() failed (111: Connection refused) while connecting to upstream"

upstream 指向 php-fpm socket 或端口

curl 测试直接连接后端也失败

排查步骤

# 1. 检查 PHP-FPM 服务状态
$ systemctl status php-fpm
● php-fpm.service - PHP FastCGI Process Manager
  Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; enabled; vendor preset: enabled)
  Active: inactive (dead) since Thu 2026-04-24 0812 CST; 2h 15min ago
 Main PID: 4521 (code=exited, status=0/SUCCESS)

# 2. 检查 PHP-FPM 主进程退出原因
$ journalctl -u php-fpm --since"2026-04-24 0800"--until"2026-04-24 0800"
Apr 24 0812 web01 systemd[1]: php-fpm.service: Main process exited, code=killed, status=9/KILL
Apr 24 0812 web01 systemd[1]: php-fpm.service: Failed with result'signal'.

# 3. 检查 dmesg 中是否有 OOM Killer 记录
$ dmesg -T | grep -E"php|oom|killed"| tail -10
[Thu Apr 24 0811 2026] php-fpm[4522]: memory usage 256MB exceedslimit256MB, terminated
[Thu Apr 24 0811 2026] Out of memory: Killed process 4522 total-vm:512MB, anon-rss:256MB file-rss:0KB

# 4. 检查 PHP-FPM 配置中的进程管理参数
$ grep -E"^pm|^proces|child|memory"/etc/php-fpm/www.conf
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500
;emergency_restart_threshold = 10
;emergency_restart_interval = 1m
;process_control_timeout = 10s
php_admin_value[memory_limit] = 256M

# 5. 检查 PHP-FPM 错误日志
$ cat /var/log/php-fpm/www-error.log | tail -30
[24-Apr-2026 0810 UTC] PHP Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 16384 bytes)in/var/www/html/api/v2/users.php on line 145
[24-Apr-2026 0811 UTC] PHP Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 32768 bytes)in/var/www/html/api/v2/users.php on line 234

解决方案

临时恢复服务:重启 PHP-FPM

$ systemctl restart php-fpm
$ systemctl status php-fpm
● php-fpm.service - PHP FastCGI Process Manager
  Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; enabled; vendor preset: enabled)
  Active: active (running) since Thu 2026-04-24 1000 CST; 5s ago

长期优化:根据 OOM 日志定位内存消耗最大的 PHP 脚本,优化代码或上调 memory_limit

# 临时调高 memory_limit(不推荐作为长期方案)
$ sed -i's/php_admin_value[memory_limit] = 256M/php_admin_value[memory_limit] = 512M/'/etc/php-fpm/www.conf
$ systemctl restart php-fpm

# 优化 pm.max_children(根据可用内存计算)
# 公式:max_children = (总内存 - 操作系统预留 - 其他服务内存) / 单个 PHP 进程内存
# 假设服务器 32G 内存,OS 预留 4G,MySQL 占用 8G,单个 PHP 进程平均 64M
# max_children = (32 - 4 - 8) * 1024 / 64 = 320

根因预防

配置 PHP-FPM emergency_restart_threshold,当进程在规定时间内异常退出次数超过阈值时自动重启

配置 OOM Score Adj,使 PHP-FPM 进程更容易被 OOM Killer 先选中

使用 PHP 内存分析工具(xdebug、memprof)定位内存泄漏

场景二:Node.js/Python 后端 CPU 跑满

后端服务 CPU 跑满时,请求处理速度急剧下降,Nginx 等待后端响应超时,最终导致 502。

症状识别

error.log 出现"upstream timed out"

502 错误持续出现,但后端进程仍在运行

系统 load average 显著升高

排查步骤

# 1. 检查 CPU 使用情况
$ top -b -n 1 -p $(pgrep -d','node)
top - 0815 up 42 days, 3:37, 2 users, load average: 8.45, 6.89, 5.76
Tasks: 12 total,  9 running,  3 sleeping,  0 stopped,  0 zombie
%Cpu(s): 95.5 us, 3.2 sy, 0.0 ni, 1.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
 PID USER   PR NI  VIRT  RES  SHR S %CPU %MEM   TIME+  COMMAND
3421 root   20  0 1245678 456123 23456 R 78.5  1.4  2345:56 node
3422 root   20  0 234567 123456  8901 R 15.2  0.4  456:34 node
3423 root   20  0 212345 112234  7802 R  1.2  0.3  123:45 node

# 2. 检查 Node.js 进程的请求队列长度
$ curl -s http://127.0.0.1:8080/metrics | grep -E"nodejs_active_requests|eventloop_lag"
# HELP nodejs_active_requests Number of active requests
# TYPE nodejs_active_requests gauge
nodejs_active_requests 150
# HELP nodejs_eventloop_lag Lag in the Node.js event loop in milliseconds
# TYPE nodejs_eventloop_lag gauge
nodejs_eventloop_lag 5234

# 3. 分析 Node.js 慢日志(如果有)
$ cat /var/log/node-backend/slow.log | tail -20
[SLOW] 2026-04-24T0812.234Z - 5034ms - /api/v2/report - Database query slow
[SLOW] 2026-04-24T0815.567Z - 6123ms - /api/v2/report - Memory allocation high

# 4. Python (Gunicorn) 场景:检查 worker 状态
$ ps aux | grep gunicorn | grep -v grep
root   5621 0.0 2.1 245678 456789 ?    S  Apr23  0:30 gunicorn: master [app]
www-data 5622 95.0 3.2 267890 567890 ?    R  Apr24  234:56 gunicorn: worker [/var/www/app]
www-data 5623 92.0 3.1 259876 543210 ?    R  Apr24  198:34 gunicorn: worker [/var/www/app]

$ curl http://127.0.0.1:8000/syncdict # Gunicorn 同步模式下单个请求阻塞整个 worker

解决方案

快速止血:增加 worker 进程数量或切换到异步模式

# Node.js: 临时增加 cluster worker 数量
# 编辑 app.js,将 worker 数量从 4 增加到 8
$ sed -i's/workers: 4/workers: 8/'/etc/node-backend/config.js
$ systemctl restart node-backend

# Python: 增加 Gunicorn worker 数量,使用异步 worker
$ sed -i's/workers=4/workers=8/'/etc/gunicorn/config.py
$ sed -i's/worker-class=sync/worker-class=uvicorn.workers.UvicornWorker/'/etc/gunicorn/config.py
$ systemctl restart gunicorn

定位瓶颈:使用 profiler 找到 CPU 热点代码

# Node.js: 使用 --prof 生成 V8 profiling 数据
$kill-USR2 $(pgrep node) # 触发 profiling
$ sleep 30
$kill-USR2 $(pgrep node) # 停止 profiling
$ node --prof-process isolate-*.log| head -30

优化超时配置:根据后端处理能力调整 Nginx 超时

# upstream 块中添加合理的超时配置
upstream backend {
  server 127.0.0.1:8080;
  keepalive 16;
}

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

  # 根据后端处理能力调整超时
  proxy_connect_timeout 5s;
  proxy_send_timeout 30s;
  proxy_read_timeout 60s;
}

场景三:数据库连接池耗尽

后端服务依赖数据库,当数据库连接池耗尽时,后端请求在等待数据库连接时阻塞,间接导致 Nginx 侧超时。

症状识别

502 错误呈现周期性(如每 30 分钟出现一次高峰)

后端应用日志中大量"connection timeout"或"pool exhausted"

数据库服务器 CPU/内存正常,但连接数达到上限

排查步骤

# 1. 检查 MySQL 连接数
$ mysql -e"SHOW PROCESSLIST;"| wc -l
145

$ mysql -e"SHOW PROCESSLIST;"| grep -E"Sleep|Query"| head -20
+----+------+-----------+--------------------+---------+------+----------+-----------------------+
| Id | User | Host   | db         | Command | Time | State  | Info         |
+----+------+-----------+--------------------+---------+------+----------+-----------------------+
| 1 | root | localhost | information_schema | Query  |  0 | starting | SHOW PROCESSLIST   |
| 45 | app | web01:456 | myapp_production  | Sleep  | 892 |     | NULL         |
| 46 | app | web01:457 | myapp_production  | Sleep  | 891 |     | NULL         |
| 47 | app | web01:458 | myapp_production  | Sleep  | 890 |     | NULL         |
| 48 | app | web02:123 | myapp_production  | Sleep  | 892 |     | NULL         |
+----+------+-----------+--------------------+---------+------+----------+-----------------------+

# 2. 检查 MySQL 最大连接数配置
$ mysql -e"SHOW VARIABLES LIKE 'max_connections';"
+-----------------+-------+
| Variable_name  | Value |
+-----------------+-------+
| max_connections | 151  |
+-----------------+-------+

# 3. 检查 PHP/Python 应用的数据库连接池配置
$ grep -E"max_connections|pool_size|connection_pool"/var/www/html/config/database.php
$connPool= new PDO($dsn,$user,$pass, [
  PDO::ATTR_POOL =>true,
  PDO::ATTR_POOL_SIZE => 20,
]);

# 4. 检查慢查询日志(长时间运行的 Query 会占用连接)
$ mysql -e"SHOW GLOBAL STATUS LIKE 'Slow_queries';"
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Slow_queries | 1234 |
+---------------+-------+

$ cat /var/log/mysql/slow-query.log | head -30

解决方案

数据库端优化:增加 max_connections,调优 wait_timeout

-- 临时增加连接数上限
SETGLOBALmax_connections =500;

-- 检查并调优 wait_timeout(避免 Sleep 连接长期占用)
SHOWGLOBALVARIABLESLIKE'wait_timeout';
SETGLOBALwait_timeout =600;
SETGLOBALinteractive_timeout =600;

应用端优化:使用连接池管理,设置连接超时,快速失败

// PHP: 使用 Doctrine DBAL 连接池,设置短超时
$config =newDoctrineDBALConfiguration();
$config->setDriverChain(['adapter'=>'pdo_mysql']);
$connection = DoctrineDBALManagerRegistry::getConnection([
 'driver'=>'pdo_mysql',
 'host'=>'10.0.1.100',
 'dbname'=>'myapp',
 'user'=>'app',
 'password'=>'xxx',
 'options'=> [
    PDO::ATTR_TIMEOUT =>5, // 5 秒超时
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  ],
]);

Nginx 端配置:使用短超时和快速失败,避免请求堆积

location / {
  proxy_pass http://backend;
  proxy_connect_timeout 3s;
  proxy_send_timeout 10s;
  proxy_read_timeout 30s;

  # 后端处理过慢时立即返回 502,不累积请求
  proxy_next_upstream error timeout http_502;
}

场景四:Socket 文件权限问题

PHP-FPM 使用 Unix Domain Socket 与 Nginx 通信时,socket 文件的权限和所有权必须正确配置,否则 Nginx 无法连接 PHP-FPM。

症状识别

error.log 中出现"connect() to unix:/var/run/php-fpm/www.sock failed (13: Permission denied)"

PHP-FPM 进程正常运行,但 Nginx 返回 502

直接测试 socket 连通性失败

排查步骤

# 1. 检查 socket 文件权限
$ ls -la /var/run/php-fpm/
total 8
srwxr-xr-x 3 root www-data www-data 120 Apr 24 06:00 /var/run/php-fpm/
srwxrwxrwx 1 www-data www-data  6 Apr 24 06:00 www.sock

# 2. 检查 Nginx worker 进程的用户
$ ps aux | grep"nginx: worker"| head -3
root   12487 0.0 0.3 56789 23456 ? S  Apr23  0:12 nginx: worker process
root   12488 0.0 0.3 56790 23457 ? S  Apr23  0:11 nginx: worker process

# nginx.conf 中 user 指令
$ grep"^user"/etc/nginx/nginx.conf
user nginx nginx;

# 3. 检查 PHP-FPM pool 配置中的 listen.owner 和 listen.group
$ grep -E"^listen.|listen.owner|listen.group|listen.mode"/etc/php-fpm/www.conf
listen = /var/run/php-fpm/www.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

# 4. 测试 socket 连接性
$ sudo -u nginx php-fpm-test-connection /var/run/php-fpm/www.sock
# 或使用 ss 查看 socket 状态
$ ss -x | grep php-fpm
u_str LISTEN 0 511 /var/run/php-fpm/www.sock 12345 users:(("php-fpm",pid=4522,fd=9))

SELinux/AppArmor 拦截检查

# 检查 SELinux 状态
$ getenforce
Enforcing

# 查看 SELinux 阻止的访问
$ grep nginx /var/log/audit/audit.log | grep -i"denied|refused"| tail -10
type=AVC msg=audit(1713936000.234 avc: denied { connectto }for pid=12487 comm="nginx"path="/var/run/php-fpm/www.sock"scontext=system_uhttpd_t:s0 tcontext=system_uphp-fpm_t:s0 tclass=unix_stream_socket permissive=0

# 临时解决:设置 SELinux 允许 nginx 连接 php-fpm socket
$ setsebool -P httpd_can_network_connect 1

# 永久解决:添加 SELinux 策略
$ cat > /etc/selinux/local/nginx_php_fpm.te << 'EOF'
module nginx_php_fpm 1.0;

require {
    type httpd_t;
    type php-fpm_t;
    class unix_stream_socket connectto;
}

allow httpd_t php-fpm_t:unix_stream_socket connectto;
EOF

$ checkmodule -M -m -o nginx_php_fpm.mod nginx_php_fpm.te
$ semodule_package -o nginx_php_fpm.pp -m nginx_php_fpm.mod
$ semodule -i nginx_php_fpm.pp

解决方案

统一用户和组

# 方案一:让 Nginx 和 PHP-FPM 使用相同的用户
# /etc/php-fpm/www.conf
listen.owner = nginx
listen.group = nginx
listen.mode = 0660

# /etc/nginx/nginx.conf
user nginx nginx;

# 方案二:使用 TCP 连接而非 Unix socket
# /etc/php-fpm/www.conf
listen = 127.0.0.1:9000

# /etc/nginx/nginx.conf
location ~ .php$ {
  fastcgi_pass 127.0.0.1:9000;
}

修复 socket 权限

$ chown www-data:www-data /var/run/php-fpm
$ chmod 0775 /var/run/php-fpm
$ systemctl restart php-fpm

场景五:反代到 Docker 容器

Docker 容器的网络模式、容器健康状态、容器重启策略等都会影响 Nginx 对容器的代理行为。

症状识别

upstream 指向 Docker 容器 IP 或映射端口

502 错误在容器重启后突然出现

docker ps 显示容器状态不稳定

排查步骤

# 1. 检查容器状态
$ docker ps -a
CONTAINER ID  IMAGE      STATUS     PORTS         NAMES
abc123def456  myapp:latest  Up 2 hours   0.0.0.0:8080->8080/tcp web01
def456ghi789  myapp:latest  Restarting   0.0.0.0:8081->8080/tcp web02
ghi789jkl012  myapp:latest  Exited (1) 5m  0.0.0.0:8082->8080/tcp web03

# 2. 检查容器日志
$ docker logs def456ghi789 --tail 50
[2026-04-24 0800] INFO: Starting server on port 8080
[2026-04-24 0801] ERROR: Database connection failed: connection timeout
[2026-04-24 0801] INFO: Retryingin5 seconds...
[2026-04-24 0806] ERROR: Database connection failed: connection timeout
[2026-04-24 0806] FATAL: Could not connect to database after 5 attempts, exiting

# 3. 检查 Docker 网络模式
$ docker inspect def456ghi789 | grep -A 10"NetworkSettings"
"NetworkSettings": {
 "Bridge":"",
 "SandboxID":"xyz123",
 "Gateway":"172.17.0.1",
 "IPAddress":"172.17.0.8",
 "Ports": {
   "8080/tcp": [
      {
       "HostIp":"0.0.0.0",
       "HostPort":"8081"
      }
    ]
  }
}

# 4. 测试容器网络连通性
$ dockerexec-it abc123def456 ping -c 3 db.internal.example.com
PING db.internal.example.com (10.0.1.100) 56(84) bytes of data.
64 bytes from db.internal.example.com (10.0.1.100): icmp_seq=1 ttl=63 time=0.5 ms

$ dockerexec-it abc123def456 curl -v http://localhost:8080/health
* Connected to localhost:8080 (127.0.0.1) port 8080
< HTTP/1.1 200 OK

# 5. 检查 Docker daemon 日志
$ journalctl -u docker --since "2026-04-24 0800" | tail -50

解决方案

使用 Docker Compose 健康检查和 depends_on 确保启动顺序

# docker-compose.yml
version:'3.8'
services:
db:
 image:mysql:8.0
 healthcheck:
  test:["CMD","mysqladmin","ping","-h","localhost"]
  interval:10s
  timeout:5s
  retries:5

app:
 image:myapp:latest
 depends_on:
  db:
   condition:service_healthy
 healthcheck:
  test:["CMD","curl","-f","http://localhost:8080/health"]
  interval:15s
  timeout:5s
  retries:3
 restart:on-failure

在 Nginx upstream 中使用容器名称(Docker Compose 网络内)

upstream backend {
  server web01:8080;
  server web02:8080;
  server web03:8080 backup;
}

location / {
  proxy_pass http://backend;
  resolver 127.0.0.11 valid=10s; # Docker 内置 DNS
  proxy_set_header Host $host;
}

配置 Nginx upstream 主动健康检查

upstream backend {
  server web01:8080;
  server web02:8080;
  server web03:8080 backup;

  check interval=5000 rise=2 fall=3 timeout=3000 type=http;
  check_http_send "HEAD /health HTTP/1.0

";
  check_http_expect_alive http_2xx;
}

3.4 配置优化实战

超时参数调优

超时配置是 502 问题的核心配置项。根据业务特点合理设置超时,可以在保护后端和保证可用性之间取得平衡。

# 生产环境推荐的超时配置
proxy_connect_timeout 10s;  # 连接超时,短即可
proxy_send_timeout 60s;   # 发送请求超时,根据请求体大小调整
proxy_read_timeout 120s;   # 读取响应超时,根据业务处理时间调整

# 上传/下载大文件的场景
client_max_body_size 500m;  # 允许最大请求体 500M
proxy_read_timeout 600s;   # 大文件处理需要更长超时

# API 服务的超时配置
location /api/ {
  proxy_pass http://backend_api;
  proxy_connect_timeout 5s;
  proxy_send_timeout 30s;
  proxy_read_timeout 60s;

  # 启用请求缓冲,用于大请求体
  proxy_request_buffering on;
  proxy_buffer_size 256k;
}
# 验证超时配置生效
$ nginx -T 2>&1 | grep -E"proxy_(connect|send|read)_timeout"
  proxy_connect_timeout 10s;
  proxy_send_timeout 60s;
  proxy_read_timeout 120s;

# 通过压力测试验证超时行为
$ ab -n 100 -c 10 -s 30 http://api.example.com/api/v2/report
# 观察是否会因为超时导致 502

缓冲区优化

缓冲区配置直接影响 Nginx 转发大量数据时的效率。配置不当可能导致内存占用过高或频繁写入临时文件。

# 大流量站点推荐缓冲区配置
proxy_buffering on;
proxy_buffer_size 256k;   # 响应头缓冲区
proxy_buffers 16 256k;    # 响应体缓冲区,16 * 256k = 4M
proxy_busy_buffer_size 512k; # 忙碌时缓冲区

# 临时文件配置(用于超过内存缓冲区的响应)
proxy_max_temp_file_size 2048m; # 临时文件总大小上限
proxy_temp_file_write_size 256k; # 单次写入大小

# 静态文件代理(减少后端压力)
location /static/ {
  proxy_pass http://backend_static;
  proxy_buffering on;
  proxy_cache_valid 200 60m; # 缓存 200 响应 60 分钟
  proxy_cache_valid 404 1m;
}
# 监控缓冲区使用情况
$ watch -n 1'cat /proc/$(pgrep nginx | head -1)/status | grep -E "VmPeak|VmSize|Rss"'
Every 1.0s: cat /proc/12487/status | grep -E"VmPeak|VmSize|Rss"

VmPeak: 524288 kB
VmSize: 498234 kB
Rss:   123456 kB

# 检查是否有大量临时文件
$ ls -lah /var/lib/nginx/proxy/ | wc -l
23
$ du -sh /var/lib/nginx/proxy/
1.2G

Keepalive 配置

HTTP keepalive 可以复用 TCP 连接,显著减少连接建立的开销。在高并发场景中,合理配置 upstream keepalive 是保护后端的重要手段。

# upstream keepalive 配置
upstream backend {
  server 127.0.0.1:8080 weight=5;
  server 127.0.0.1:8081 weight=3;
  server 127.0.0.1:8082 backup;

  # keepalive 配置
  keepalive 32;       # 保持 32 个空闲连接
  keepalive_requests 1000;  # 单连接最大请求数
  keepalive_timeout 60s;   # 空闲连接超时
}

# location 中启用 HTTP/1.1 和清除 Connection 头
location / {
  proxy_pass http://backend;

  # 必须使用 HTTP/1.1 才能支持 keepalive
  proxy_http_version 1.1;

  # 清除 Connection 头,否则 nginx 会保持短连接
  proxy_set_header Connection "";

  # 可选:添加存活探测
  proxy_connect_timeout 10s;
}
# 对比有无 keepalive 的性能差异
# 无 keepalive
$ wrk -t4 -c100 -d30s http://127.0.0.1/api/test
Requests/sec: 1234.56
Latency avg:  45.67ms

# 有 keepalive(32 连接)
$ wrk -t4 -c100 -d30s http://127.0.0.1/api/test
Requests/sec: 4567.89
Latency avg:  12.34ms

# 性能提升约 3.7 倍

3.5 预防性监控

502 错误率告警

#!/bin/bash
# 监控 502 错误率,超过阈值则告警

LOG_FILE="/var/log/nginx/access.log"
THRESHOLD=1.0 # 阈值 1%

calculate_502_rate() {
  total=$(wc -l < "$LOG_FILE")
    errors502=$(grep -c " 502 ""$LOG_FILE" 2>/dev/null ||echo0)

 if["$total"-eq 0 ];then
   echo"0"
   return
 fi

  rate=$(echo"scale=4;$errors502/$total* 100"| bc)
 echo"$rate"
}

rate=$(calculate_502_rate)
result=$(echo"$rate>$THRESHOLD"| bc)

if["$result"-eq 1 ];then
 echo"CRITICAL: 502 error rate is${rate}%, threshold is${THRESHOLD}%"
 # 触发告警(对接 Prometheus Alertmanager / Grafana / PagerDuty 等)
  curl -X POST"http://alertmanager:9093/api/v1/alerts"
    -H"Content-Type: application/json"
    -d'[{"labels":{"alertname":"Nginx502High","severity":"critical"}}]'
fi

Prometheus + Grafana 监控配置

# prometheus.yml - scrape 配置
scrape_configs:
-job_name:'nginx'
 static_configs:
  -targets:['127.0.0.1:9100']# nginx-vts 或 nginx-exporter

# Grafana 查询 - 502 错误率
# Nginx upstream response time (5xx)
sum(rate(nginx_upstream_response_seconds_count{upstream=~".*",status=~"5.."}[5m]))by(upstream)

# Nginx upstream request errors
sum(rate(nginx_upstream_request_errors_total[5m]))by(upstream)

# Nginx connection status
nginx_connections_total{status="active"}
nginx_connections_total{status="reading"}
nginx_connections_total{status="writing"}
nginx_connections_total{status="waiting"}

upstream 响应时间分布

# 使用 awk 分析 access.log 中 upstream 响应时间分布
$ awk -F'"''$2 ~ /upstream/ {
  split($2, parts, " ")
  for (i=1; i<=length(parts); i++) {
        if (parts[i] ~ /upstream_response_time/) {
            split(parts[i], kv, ":")
            time = kv[3] + 0
            if (time < 0.1) bucket["<100ms"]++
            else if (time < 0.5) bucket["100-500ms"]++
            else if (time < 1) bucket["500ms-1s"]++
            else if (time < 5) bucket["1-5s"]++
            else if (time < 30) bucket["5-30s"]++
            else bucket[">30s"]++
      total++
      break
    }
  }
}
END {
  for (b in bucket) {
    pct = int(bucket[b] / total * 100)
    printf "%s: %d (%d%%)
", b, bucket[b], pct
  }
}'/var/log/nginx/access.log

<100ms: 12345 (45%)
100-500ms: 9876 (36%)
500ms-1s: 2345 (9%)
1-5s: 1234 (5%)
5-30s: 567 (2%)
>30s: 33 (1%)

四、生产环境最佳实践

4.1 架构优化

多层 Nginx 架构

在大型生产环境中,建议部署两层 Nginx:边缘代理层(Edge Proxy)和应用代理层(Application Proxy)。边缘代理负责 SSL 终结、请求日志、基础安全过滤、静态资源缓存;应用代理负责业务路由、upstream 健康检查、负载均衡、故障转移。

          Internet
            |
        Edge Proxy (NLB)
        1.1.1.1 / 1.1.1.2
        SSL Termination
        Static Cache
        Rate Limiting
            |
        Application Proxy Cluster
        10.0.1.10 / 10.0.1.11 / 10.0.1.12
        Upstream Health Check
        Load Balancing
        Business Routing
            |
        Backend Services
        +------------+------------+
        |      |      |
      PHP-FPM   Node.js   Python
        |      |      |
      Database  Redis    PostgreSQL
# 边缘代理层配置 - /etc/nginx/edge.conf
# 处理 SSL 终结和静态资源
server {
  listen 443 ssl http2;
  server_name www.example.com;

  ssl_certificate /etc/nginx/ssl/example.com.crt;
  ssl_certificate_key /etc/nginx/ssl/example.com.key;
  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared10m;
  ssl_session_timeout 1d;

  # 静态资源缓存
  location /static/ {
    proxy_pass http://cdn_backend;
    proxy_cache static_cache;
    proxy_cache_valid 200 7d;
    add_header X-Cache-Status $upstream_cache_status;
  }

  # 动态请求转发到应用代理层
  location / {
    proxy_pass http://app_proxy_cluster;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # 限流配置
    limit_req zone=api_limit burst=100 nodelay;
    limit_conn_status 429;
  }
}

# 应用代理层配置 - /etc/nginx/app.conf
# 负责 upstream 健康检查和负载均衡
upstream backend_php {
  least_conn;

  server 10.0.1.20:9000 weight=5;
  server 10.0.1.21:9000 weight=5;
  server 10.0.1.22:9000 backup;

  # 主动健康检查
  check interval=3000 rise=2 fall=2 timeout=1000 type=http;
  check_http_send "HEAD /health HTTP/1.0

";
  check_http_expect_alive http_2xx;
}

upstream backend_node {
  ip_hash;

  server 10.0.1.30:8080 weight=3;
  server 10.0.1.31:8080 weight=3;
  server 10.0.1.32:8080 weight=3;
}

server {
  listen 80;
  server_name api.example.com;

  location /api/v1/ {
    proxy_pass http://backend_php;
    include /etc/nginx/conf.d/proxy_params.conf;
  }

  location /api/node/ {
    proxy_pass http://backend_node;
    include /etc/nginx/conf.d/proxy_params.conf;
  }
}

主动健康检查配置

使用 nginx_upstream_check_module 实现主动健康检查,比被动检查更早发现故障节点,避免将请求发往已故障的后端。

# 加载模块(编译时添加)
# ./configure --add-module=/path/to/nginx_upstream_check_module

upstream backend {
  server 127.0.0.1:8080;
  server 127.0.0.1:8081;
  server 127.0.0.1:8082 backup;

  # 主动健康检查配置
  # interval: 检查间隔 3 秒
  # rise: 连续 2 次成功则标记为 up
  # fall: 连续 3 次失败则标记为 down
  # timeout: 检查超时 1 秒
  # type: 检查类型为 HTTP
  check interval=3000 rise=2 fall=3 timeout=1000 type=http;

  # 发送的 HTTP 请求
  check_http_send "HEAD /health HTTP/1.0

";

  # 期望的响应状态码
  check_http_expect_alive http_2xx http_3xx;
}

# 健康检查状态页面
server {
  listen 8080;
  server_name localhost;

  location /upstream_status {
    check_status;
    access_log off;
    allow 127.0.0.1;
    deny all;
  }

  location /health {
    return 200 "OK";
    add_header Content-Type text/plain;
  }
}
# 验证健康检查状态
$ curl http://127.0.0.1:8080/upstream_status
Upstream server status:
backend
 server 127.0.0.1:8080   up   1234567890 ms
 server 127.0.0.1:8081   down  5000 ms (3/3)
 server 127.0.0.1:8082   backup
Total connections: 2345
upstream alive connections: 1234

灰度发布与权重调整

在升级后端服务时,使用 Nginx 的权重调整实现流量切换,而非直接替换。新版本接收小部分流量,观察无异常后逐步增加权重。

# 金丝雀发布配置
upstream backend_stable {
  server 127.0.0.1:8080; # 当前稳定版本
}

upstream backend_canary {
  server 127.0.0.1:8081; # 新版本,权重为 1
}

# 90% 流量到稳定版,10% 到金丝雀
upstream backend {
  server 127.0.0.1:8080 weight=9;
  server 127.0.0.1:8081 weight=1;
}

# 或者根据请求特征(如 Cookie、Header)分流
map $cookie_canary_version $backend_pool {
  default http://backend_stable;
  "v2" http://backend_canary;
}

location / {
  proxy_pass $backend_pool;
  include /etc/nginx/conf.d/proxy_params.conf;
}
# 监控金丝雀版本的错误率
$ awk'$9 ~ /5../ && /127.0.0.1:8081/ {count++} END {print "Canary 5xx:", count}'/var/log/nginx/access.log
Canary 5xx: 12

$ awk'$9 ~ /5../ && /127.0.0.1:8080/ {count++} END {print "Stable 5xx:", count}'/var/log/nginx/access.log
Stable 5xx: 3

# 金丝雀错误率略高,继续观察

限流与熔断

在 upstream 压力过大或响应变慢时,主动拒绝部分请求,防止雪崩效应。

# 限流配置
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

server {
  location /api/ {
    # 令牌桶限流,burst=200 表示突发最多接受 200 个请求
    # nodelay 不延迟处理,直接返回 503
    limit_req zone=api_limit burst=200 nodelay;

    # 连接数限制
    limit_conn conn_limit 10;

    proxy_pass http://backend;
    proxy_next_upstream error timeout http_502 http_503;
  }
}

# 熔断配置:基于响应时间自动降级
# 当 upstream 平均响应时间超过阈值时,返回降级响应
proxy_cache_bypass $upstream_http_x_downgrade;

4.2 配置模板

生产环境完整配置示例

# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;

events {
  worker_connections 65535;
  use epoll;
  multi_accept on;
}

http {
  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  # 日志格式
  log_format main '$remote_addr - $remote_user [$time_local] "$request" '
          '$status $body_bytes_sent "$http_referer" '
          '"$http_user_agent" "$http_x_forwarded_for" '
          'rt=$request_time uct="$upstream_connect_time" '
          'uht="$upstream_header_time" urt="$upstream_response_time" '
          'request_id="$request_id"';

  access_log /var/log/nginx/access.log main buffer=16k flush=2s;

  # 基础优化
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  server_tokens off;

  # 超时配置
  keepalive_timeout 65;
  keepalive_requests 1000;
  client_header_timeout 15s;
  client_body_timeout 15s;
  send_timeout 60s;

  # 缓冲区配置
  client_max_body_size 100m;
  client_body_buffer_size 256k;
  client_header_buffer_size 4k;
  large_client_header_buffers 4 16k;

  # Gzip 压缩
  gzip on;
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml;

  # 隐藏 Nginx 版本号
  server_tokens off;

  # 安全头
  add_header X-Frame-Options "SAMEORIGIN" always;
  add_header X-Content-Type-Options "nosniff" always;
  add_header X-XSS-Protection "1; mode=block" always;
  add_header Referrer-Policy "strict-origin-when-cross-origin" always;

  # upstream 块定义
  include /etc/nginx/conf.d/upstream/*.conf;

  # 引入各站点的 server 配置
  include /etc/nginx/sites-enabled/*.conf;
}
# /etc/nginx/conf.d/upstream/backend.conf
upstream backend_php {
  least_conn;

  server 127.0.0.1:9000 weight=5 max_fails=3 fail_timeout=10s;
  server 127.0.0.1:9001 weight=5 max_fails=3 fail_timeout=10s;
  server 127.0.0.1:9002 backup;

  keepalive 32;
  keepalive_requests 1000;
  keepalive_timeout 60s;
}

upstream backend_static {
  server 127.0.0.1:8080 weight=5;
  server 127.0.0.1:8081 weight=5;
  server 127.0.0.1:8082 backup;

  keepalive 32;
}

upstream backend_api {
  ip_hash;

  server 10.0.1.20:8080;
  server 10.0.1.21:8080;
  server 10.0.1.22:8080;

  # 主动健康检查
  check interval=3000 rise=2 fall=2 timeout=1000 type=http;
  check_http_send "HEAD /health HTTP/1.0

";
  check_http_expect_alive http_2xx;
}
# /etc/nginx/sites-enabled/api.example.com.conf
server {
  listen 80;
  server_name api.example.com;

  # 将 HTTP 请求重定向到 HTTPS
  return 301 https://$server_name$request_uri;
}

server {
  listen 443 ssl http2;
  server_name api.example.com;

  ssl_certificate /etc/nginx/ssl/api.example.com.crt;
  ssl_certificate_key /etc/nginx/ssl/api.example.com.key;
  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
  ssl_prefer_server_ciphers off;
  ssl_session_cache shared10m;
  ssl_session_timeout 1d;
  ssl_session_tickets off;

  # 安全头
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

  # 访问日志
  access_log /var/log/nginx/api.example.com.access.log main buffer=16k;

  # 健康检查端点(不经过限流)
  location = /health {
    access_log off;
    return 200 "OK
";
    add_header Content-Type text/plain;
  }

  # API 路由
  location /api/v1/ {
    # 限流
    limit_req zone=api_limit burst=100 nodelay;
    limit_req_status 429;

    # proxy 配置
    proxy_pass http://backend_php;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Connection "";

    # 超时配置
    proxy_connect_timeout 10s;
    proxy_send_timeout 60s;
    proxy_read_timeout 120s;

    # 缓冲区配置
    proxy_buffering on;
    proxy_buffer_size 128k;
    proxy_buffers 8 256k;
    proxy_busy_buffer_size 256k;

    # 错误处理:后端故障时返回降级响应
    error_page 502 503 = @fallback;
  }

  # 静态资源
  location /static/ {
    proxy_pass http://backend_static;
    proxy_cache static_cache;
    proxy_cache_valid 200 60m;
    proxy_cache_valid 404 1m;
    proxy_cache_use_stale error timeout updating;
    add_header X-Cache-Status $upstream_cache_status;
    expires 7d;
    add_header Cache-Control "public, immutable";
  }

  # 降级响应
  location @fallback {
    default_type application/json;
    return 503 '{"code":503,"message":"Service temporarily unavailable","request_id":"$request_id"}';
  }

  # 429 Too Many Requests 响应
  location = /429.html {
    internal;
    default_type application/json;
    return 429 '{"code":429,"message":"Rate limit exceeded","retry_after":1}';
  }
}

日志切割配置

# /etc/logrotate.d/nginx
/var/log/nginx/*.log{
  daily
  missingok
  rotate 30
  compress
  delaycompress
  notifempty
  create 0640 nginx adm
  sharedscripts
  postrotate
    [ -f /run/nginx.pid ] &&kill-USR1 $(cat /run/nginx.pid)
  endscript
}
# 手动测试日志切割
$ logrotate -f /etc/logrotate.d/nginx
$ ls -la /var/log/nginx/
total 1234
-rw-r----- 1 nginx adm  45678 Apr 24 00:00 access.log
-rw-r----- 1 nginx adm  12345 Apr 24 00:00 access.log-20260424.gz
-rw-r----- 1 nginx adm  23456 Apr 24 00:00 error.log
-rw-r----- 1 nginx adm  8901 Apr 24 00:00 error.log-20260424.gz

性能测试基线

# 使用 wrk 进行基准性能测试
$ wrk -t4 -c100 -d60s --latency http://api.example.com/api/v1/health

Running 1mtest@ http://api.example.com/api/v1/health
 4 threads and 100 connections
 Thread Stats  Avg   Stdev   Max  +/- Stdev
  Latency   12.34ms  2.15ms 45.67ms  90.12%
  Req/Sec  2345.67   89.23 2500.00  85.00%
 Latency Distribution
  50%  11.89ms
  75%  13.45ms
  90%  15.23ms
  99%  25.67ms
 1234567 requestsin60.00s, 234.56MBread
Requests/sec: 20576.12
Transfer/sec:  3.91MB
# 使用 ab 进行连接测试
$ ab -n 10000 -c 1000 -g ab_results.tsv http://api.example.com/api/v1/health

This is ApacheBench, Version 2.3 <$Revision: 1879490 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking api.example.com (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests

Server Software:    nginx/1.26.2
Server Hostname:    api.example.com
Server Port:      443
SSL/TLS Protocol:    TLSv1.3, ECDHE-RSA-AES256-GCM-SHA384, 256bit

Document Path:     /api/v1/health
Document Length:    3 bytes

Concurrency Level:   1000
Time takenfortests:  12.345 seconds
Complete requests:   10000
Failed requests:    0
Non-2xx responses:   0
Total transferred:   2340000 bytes
HTML transferred:    30000 bytes
Requests per second:  810.23 [#/sec] (mean)
Time per request:    1234.567 [ms] (mean)
Time per request:    1.235 [ms] (mean, across all concurrent requests)
Transfer rate:     185.23 [Kbytes/sec] received

Connection Times (ms)
       min mean[+/-sd] median  max
Connect:    0  0  0.0   0    0
Processing:  123 456 78.9  434  1234
Waiting:    123 455 78.9  433  1233
Total:     123 456 78.9  434  1234

Percentage of the requests served within a certain time (ms)
 50%  434
 66%  456
 75%  478
 80%  489
 90%  534
 95%  612
 98%  723
 99%  789
100%  1234 (longest request)

4.3 故障应急

502 故障的快速止血

故障发生时,第一目标是快速恢复服务,最小化业务影响。

# 1. 立即检查 error.log,确认 502 根因类型
$ tail -100 /var/log/nginx/error.log | grep -E"[error]"| tail -20

# 2. 快速检查后端服务状态
$ systemctl status php-fpm node-backend gunicorn 2>&1 | grep -E"Active:|Main PID:"

# 3. 如果后端服务挂了,立即重启
$ systemctl restart php-fpm
$ systemctl restart node-backend

# 4. 如果是单个 upstream server 故障,临时从 upstream 中移除
$ vim /etc/nginx/conf.d/upstream/backend.conf
# 注释掉故障 server,保留可用的
upstream backend {
  server 127.0.0.1:9000;
 # server 127.0.0.1:9001; # 临时禁用
}

$ nginx -t && nginx -s reload

# 5. 如果所有后端都不可用,启动备用服务
$ systemctl start emergency-backend

# 6. 扩大上游超时时间,减少 502 触发
$ sed -i's/proxy_read_timeout 120s;/proxy_read_timeout 300s;/'/etc/nginx/conf.d/upstream/*.conf
$ nginx -s reload

后端切换的手动操作

# 手动切换流量到备用后端
# 场景:主数据库故障,需要切换到从库

# 1. 备份当前 upstream 配置
$ cp /etc/nginx/conf.d/upstream/app.conf /etc/nginx/conf.d/upstream/app.conf.bak.$(date +%Y%m%d%H%M%S)

# 2. 修改 upstream 指向备用后端
$ cat > /etc/nginx/conf.d/upstream/app_standby.conf << 'EOF'
upstream backend_app {
    server 10.0.2.20:8080 weight=5;
    server 10.0.2.21:8080 weight=5;
    server 10.0.2.22:8080 backup;
}
EOF

# 3. 测试配置语法
$ nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

# 4. 优雅reload,不中断现有连接
$ nginx -s reload

# 5. 监控错误率变化
$ watch -n 1 'grep -c " 502 " /var/log/nginx/access.log'

# 6. 验证备用后端可用性
$ curl -s http://10.0.2.20:8080/health | grep OK
$ curl -s http://10.0.2.21:8080/health | grep OK

业务降级方案

当后端无法处理请求时,返回预设的降级响应而非 502,提升用户体验。

# 降级配置示例
upstream backend_primary {
  server 127.0.0.1:8080;
  server 127.0.0.1:8081 backup;
}

# 主服务不可用时返回缓存或静态降级内容
proxy_cache_key "$host$request_uri";
proxy_cache_valid 200 10m;
proxy_cache_valid 404 1m;
proxy_cache_valid 500 502 503 504 1m;

location /api/ {
  # 尝试主后端
  proxy_pass http://backend_primary;

  # 后端返回 502/503 时使用缓存
  proxy_cache_use_stale error timeout updating http_502 http_503 http_504;

  # 后端响应慢时使用缓存
  proxy_cache_use_stale error timeout updating;

  # 缓存刷新时间
  proxy_cache_background_update on;
  proxy_cache_lock on;

  # 降级响应:如果缓存也没有,返回静态 JSON
  error_page 502 503 504 = @degraded_response;
}

location @degraded_response {
  default_type application/json;
  # 返回最近缓存的响应(由 proxy_cache_valid 控制)
  add_header X-Cache-Status "DEGRADED";
  return 200 '{"code":200,"message":"Cached response","data":null,"degraded":true}';
}

五、扩展阅读与证据链

5.1 官方文档

Nginx 官方文档

Nginx 官方文档(英文):https://nginx.org/en/docs/

Nginx upstream 模块文档:https://nginx.org/en/docs/http/ngx_http_upstream_module.html

Nginx proxy 模块文档:https://nginx.org/en/docs/http/ngx_http_proxy_module.html

Nginx 故障排查指南:https://nginx.org/en/docs/support.html

PHP-FPM 官方文档

PHP-FPM 配置说明:https://www.php.net/manual/en/install.fpm.configuration.php

PHP-FPM 进程管理:https://www.php.net/manual/en/install.fpm.pm.php

第三方模块文档

nginx_upstream_check_module(阿里巴巴):https://github.com/yaoweibin/nginx_upstream_check_module

OpenResty + lua-upstream:https://github.com/openresty/lua-upstream-nginx-module

5.2 关键配置文件参考

nginx.conf 完整模板

# Nginx 1.26.x / 1.27.x 完整配置模板
user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
worker_rlimit_sigpending 65535;

error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;

events {
  worker_connections 65535;
  use epoll;
  multi_accept on;
  accept_mutex on;
  accept_mutex_delay 500ms;
}

http {
  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  # 字符集
  charset utf-8;
  charset_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml;

  # 日志格式(包含 upstream 详细信息)
  log_format main_ext '$remote_addr - $remote_user [$time_local] "$request" '
            '$status $body_bytes_sent "$http_referer" '
            '"$http_user_agent" "$http_x_forwarded_for" '
            'rt=$request_time '
            'uct="$upstream_connect_time" '
            'uht="$upstream_header_time" '
            'urt="$upstream_response_time" '
            'request_id="$request_id" '
            'upstream_addr="$upstream_addr" '
            'upstream_status="$upstream_status"';

  access_log /var/log/nginx/access.log main_ext buffer=32k flush=5s;

  # 基础优化
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;

  # 超时配置
  keepalive_timeout 65;
  keepalive_requests 1000;
  client_header_timeout 15s;
  client_body_timeout 15s;
  send_timeout 60s;
  lingering_timeout 5s;
  reset_timedout_connection on;

  # 缓冲区配置
  client_max_body_size 100m;
  client_body_buffer_size 256k;
  client_header_buffer_size 4k;
  large_client_header_buffers 4 32k;
  connection_pool_size 256;
  request_pool_size 4k;

  # Gzip 压缩
  gzip on;
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_min_length 1024;
  gzip_types text/plain text/css text/xml application/json application/javascript application/xml application/atom+xml application/rss+xml image/svg+xml;

  # 安全配置
  server_tokens off;
  hide_server_token on;

  # Open file cache
  open_file_cache max=65535 inactive=60s;
  open_file_cache_valid 30s;
  open_file_cache_min_uses 2;
  open_file_cache_errors on;

  # 限制请求
  limit_req_zone $binary_remote_addr zone=general:10m rate=100r/s;
  limit_req_zone $binary_remote_addr zone=api:10m rate=1000r/s;
  limit_conn_zone $binary_remote_addr zone=conn:10m;

  # 引入 upstream 配置
  include /etc/nginx/conf.d/upstream/*.conf;

  # 引入站点配置
  include /etc/nginx/sites-enabled/*.conf;
}

PHP-FPM 配置参数说明

; /etc/php-fpm/www.conf 关键参数说明

; 进程管理器类型
; static - 固定数量的子进程
; dynamic - 动态数量的子进程
; ondemand - 按需创建子进程
pm = dynamic

; 子进程最大数量
pm.max_children = 50

; 启动时创建的子进程数(dynamic 模式)
pm.start_servers = 10

; 最小空闲子进程数(dynamic 模式)
pm.min_spare_servers = 5

; 最大空闲子进程数(dynamic 模式)
pm.max_spare_servers = 20

; 子进程处理请求数上限,达到后重启(防止内存泄漏累积)
pm.max_requests = 500

; 子进程空闲超时
pm.process_idle_timeout = 10s

; 紧急重启阈值
emergency_restart_threshold = 10
emergency_restart_interval = 1m

; 进程控制超时(处理 SIGTERM 需要的时间)
process_control_timeout = 10s

; PHP 内存限制
php_admin_value[memory_limit] = 256M
php_admin_flag[log_errors] = on

; 慢查询日志
slowlog = /var/log/php-fpm/www-slow.log
request_slowlog_timeout = 10s
request_slowlog_trace_depth = 20

; 健康检查
ping.path = /ping
ping.response = pong

; Socket 配置
listen = /var/run/php-fpm/www.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

systemd Service 文件

; /etc/systemd/system/php-fpm.service
[Unit]
Description=PHP FastCGI Process Manager
Documentation=man:php-fpm(8)
After=network.target

[Service]
Type=notify
PIDFile=/run/php-fpm/php-fpm.pid
ExecStart=/usr/sbin/php-fpm --nodaemonize --fpm-config /etc/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID
ExecStop=/bin/kill -SIGINT $MAINPID
PrivateTmp=true
Restart=always
RestartSec=10s
TimeoutStartSec=30s
TimeoutStopSec=30s

; 资源限制
LimitNOFILE=65535
LimitNPROC=8192

; OOM 策略 - 不阻止 OOM Killer
OOMScoreAdjust=-500

[Install]
WantedBy=multi-user.target
; /etc/systemd/system/nginx.service
[Unit]
Description=nginx - high performance web server
Documentation=https://nginx.org/en/docs/
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
Restart=always
RestartSec=5s

; 资源限制
LimitNOFILE=65535
LimitCORE=infinity

[Install]
WantedBy=multi-user.target

5.3 常见错误码速查表

errno 系统调用错误 含义 常见场景
111 ECONNREFUSED 连接被拒绝 upstream 端口未监听
110 ETIMEDOUT 连接超时 upstream 无响应,防火墙拦截
113 EHOSTUNREACH 主机不可达 IP 地址错误,网络不通
111 ECONNREFUSED 连接被拒绝 PHP-FPM socket 权限错误
104 ECONNRESET 连接被重置 upstream 进程崩溃
32 EPIPE 管道破裂 upstream 提前关闭连接
2 ENOENT 文件不存在 Unix socket 文件不存在

5.4 502 排查流程图(文字版)

发现 502 错误
  |
  v
检查 error.log 中的具体错误信息
  |
  +--->"connect() failed (111)"---> upstream 端口未监听
  |   |
  |   +---> 检查后端服务是否运行: systemctl status php-fpm/node-backend
  |   +---> 检查端口/socket 是否监听: ss -tlnp | grep 9000
  |   +---> 检查配置中 IP:端口是否正确
  |
  +--->"upstream prematurely closed"---> upstream 进程崩溃
  |   |
  |   +---> 检查 dmesg | grep -i oom(内存不足)
  |   +---> 检查后端错误日志(PHP fatal error、core dump)
  |   +---> 检查 upstream 是否被 OOM Killer 杀死
  |
  +--->"upstream timed out"---> 后端处理超时
  |   |
  |   +---> 检查后端处理时间(数据库查询、外部 API)
  |   +---> 调整 proxy_read_timeout
  |   +---> 优化后端性能或增加资源
  |
  +--->"no live upstreams"---> 所有 upstream 都不可用
     |
     +---> 检查所有 upstream server 的健康状态
     +---> 可能是 max_fails 导致所有节点被暂时禁用
     +-----> 等待 fail_timeout 过去或重启 upstream

六、自检清单

6.1 部署前检查清单

[ ] Nginx 配置文件语法验证通过:nginx -t

[ ] 后端服务已启动并监听正确端口

[ ] upstream 配置的 IP:端口与实际一致

[ ] 超时参数(proxy_connect_timeout、proxy_read_timeout)已根据业务调整

[ ] 缓冲区参数(proxy_buffer_size、proxy_buffers)已配置

[ ] keepalive 配置已启用(proxy_http_version 1.1 + Connection "")

[ ] socket 文件权限正确(listen.owner/listen.group)

[ ] SELinux/AppArmor 策略允许 Nginx 与后端通信

[ ] 日志级别设置为 warn 或 error

[ ] 健康检查已配置(被动或主动)

6.2 故障发生时的快速检查项

[ ] 查看 error.log,确认具体错误信息

[ ] 确认后端服务进程存活:systemctl status php-fpm

[ ] 确认端口/socket 监听:ss -tlnp | grep 9000

[ ] 测试后端可连接性:curl -v http://127.0.0.1:9000/health

[ ] 检查系统资源(CPU、内存、磁盘IO)

[ ] 检查 dmesg 中是否有 OOM Killer 记录

[ ] 检查 upstream 是否被标记为 down

6.3 复盘与预防检查项

[ ] 错误是否可复现

[ ] 根因是否已定位并解决

[ ] 是否有监控告警覆盖同类问题

[ ] 是否需要调整超时/缓冲区等参数

[ ] 是否需要增加资源或优化架构

[ ] 是否更新了 SOP 和运维文档

附录 A:错误日志关键字索引

关键字 根因 处理优先级
connect() failed (111) upstream 未监听端口 P0 - 立即处理
upstream prematurely closed upstream 崩溃 P0 - 立即处理
upstream timed out 后端响应超时 P1 - 优化超时
no live upstreams 所有 upstream 不可用 P0 - 立即处理
buffer is too small 缓冲区配置不足 P1 - 调整缓冲区
Permission denied 权限问题 P0 - 立即处理
connection reset upstream 强制断开 P1 - 检查 upstream 健康
broken header upstream 返回损坏响应 P1 - 检查 upstream

附录 B:命令速查卡片

# Nginx 基础操作
nginx -t          # 测试配置语法
nginx -s reload      # 优雅重载配置
nginx -s stop       # 快速关闭
nginx -s quit       # 优雅关闭
nginx -V         # 查看版本和编译参数

# 日志分析
tail -f /var/log/nginx/error.log | grep 502
awk'$9==502 {count++} END {print count}'/var/log/nginx/access.log
grep -C 5"502"/var/log/nginx/error.log

# 后端服务检查
systemctl status php-fpm
ss -tlnp | grep -E':(80|443|9000)'
ps aux | grep php-fpm
netstat -ant | grep :8080 | wc -l

# 健康检查
curl -v http://127.0.0.1:8080/health
SCRIPT_NAME=/ping cgi-fcgi -bind-connect /var/run/php-fpm/www.sock
nc -zv 127.0.0.1 9000 -w 3

# 性能监控
ss -s             # 连接统计
top -b -n 1 | head -20    # 系统资源
nginx -s reopen       # 重新打开日志文件(配合 logrotate)

附录 C:配置参数参考表

upstream 指令

指令 默认值 说明
server - 定义 upstream server,格式:address [parameters]
weight 1 权重,用于加权轮询
max_fails 1 失败次数阈值,超过后标记为不可用
fail_timeout 10s 失败超时时间,同时也是不可用持续时间
backup - 标记为备用服务器
down - 标记为永久不可用
keepalive - keepalive 连接池大小
keepalive_requests 1000 单连接最大请求数
keepalive_timeout 60s keepalive 空闲超时
slow_start 0 慢启动时间(商业版 Nginx Plus)

proxy 指令

指令 默认值 说明
proxy_pass - 指定 upstream 或 URL
proxy_http_version 1.0 HTTP 版本
proxy_connect_timeout 60s 连接超时
proxy_send_timeout 60s 发送请求超时
proxy_read_timeout 60s 读取响应超时
proxy_buffer_size 4k/8k 响应头缓冲区
proxy_buffers 8 4k/8k 响应体缓冲区
proxy_busy_buffer_size proxy_buffer_size 忙碌缓冲区
proxy_buffering on 是否启用缓冲
proxy_max_temp_file_size 1024m 临时文件总大小
proxy_temp_file_write_size proxy_buffer_size 单次写入临时文件大小
proxy_set_header Host $proxy_host 设置请求头
proxy_next_upstream error timeout 故障转移条件

本文档由运维团队基于多年生产环境排障经验整理,涵盖 Nginx 502 错误的识别、诊断、处理的完整方法论。如有补充或修正,请提交 PR 至内部文档仓库。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    88

    文章

    11825

    浏览量

    219611
  • 服务器
    +关注

    关注

    14

    文章

    10376

    浏览量

    91777
  • nginx
    +关注

    关注

    0

    文章

    196

    浏览量

    13224

原文标题:Nginx 502 Bad Gateway:从日志里挖出深藏的配置坑

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    nginx重启命令linux步骤是什么?

      1、验证nginx配置文件是否正确   方法一:进入nginx安装目录sbin下,输入命令./nginx -t   看到如下显示nginx
    发表于 07-11 17:13

    nginx错误页面配置

    16、nginx 错误页面配置nginx错误页面包括404 403 500 502 503 504等页面,只需要在server中增加以下配置
    发表于 07-26 06:54

    电瓶坏损成因、修复与保养方法

    电瓶坏损成因、修复与保养方法
    发表于 11-09 17:38 1323次阅读

    电感啸叫的成因与解决方法

    电子专业单片机相关知识学习教材资料——电感啸叫的成因与解决方法
    发表于 10-10 14:17 0次下载

    分享nginx 502的解决方法

    还好,我印象中多年前遇到过一次类似的问题,不过是linux代理linux,症状和该问题基本类似,当时的解决办法是,修改被代理的linux服务器nginx配置文件nginx.conf中worker_connections参数的值,当时记得是51200,改为4096就ok了。
    的头像 发表于 02-09 08:37 7308次阅读

    PHP出现502错误的问题如何解决详细资料说明

    本文档的主要内容详细介绍的是PHP出现502错误的问题如何解决详细资料说明
    发表于 03-14 17:17 6次下载
    PHP出现<b class='flag-5'>502</b><b class='flag-5'>错误</b>的问题如何解决详细资料说明

    科普系列:CAN总线错误帧及排查方法简介

    作者|蒹葭小编|吃不饱CAN帧有多种格式,错误帧作为CAN帧中独特的一种,了解其作用,类型与产生原因,对于进行测试以及开发有很大的帮助,本文将对错误帧的相关基础知识以及后续的分析排查进行介绍。01
    的头像 发表于 02-23 15:11 5510次阅读
    科普系列:CAN总线<b class='flag-5'>错误</b>帧及<b class='flag-5'>排查</b><b class='flag-5'>方法</b>简介

    如何用示波器排查CAN的各种错误帧呢?

    如何用示波器排查CAN的各种错误帧呢? 导言: 控制器局域网络(Controller Area Network,CAN)是一种常用的现场总线通信协议,广泛应用于汽车电子系统、工业自动化等领域。然而
    的头像 发表于 12-07 11:09 2455次阅读

    玩转Nginx日志管理:高效排查问题的终极指南

    Nginx日志对于统计、系统服务排错很有用。Nginx日志主要分为两种:access_log(访问日志)和error_log(错误日志)。通过访问日志我们可以得到用户的IP地址、浏览器的信息,请求
    的头像 发表于 12-30 13:50 1441次阅读

    云原生环境里Nginx的故障排查思路

    本文聚焦于云原生环境下Nginx的故障排查思路。随着云原生技术的广泛应用,Nginx作为常用的高性能Web服务器和反向代理服务器,在容器化和编排的环境中面临着新的故障场景和挑战。
    的头像 发表于 06-17 13:53 1191次阅读
    云原生环境里<b class='flag-5'>Nginx</b>的故障<b class='flag-5'>排查</b>思路

    电商API常见错误排查指南:避免集成陷阱

      在电商平台开发中,API集成是连接系统、实现数据交换的核心环节。然而,许多开发者在集成过程中常遇到错误,导致项目延迟、数据丢失或用户体验下降。本文将逐步介绍常见错误类型、排查方法
    的头像 发表于 07-11 14:21 2324次阅读
    电商API常见<b class='flag-5'>错误</b><b class='flag-5'>排查</b>指南:避免集成陷阱

    Nginx常见故障案例总结

    在互联网公司的运维生涯中,Nginx故障可以说是最常见也最让人头疼的问题之一。从简单的配置错误到复杂的性能瓶颈,从偶发的502到持续的高延迟,每一个故障背后都有其独特的原因和解决方案。
    的头像 发表于 09-18 14:51 1544次阅读

    Nginx常见故障排查手册

    Nginx502、504、连接超时,看起来都是“请求没成功”,但根因完全不是一类问题。502 更多是上游服务直接返回无效响应、连接被拒绝或进程挂了;504 更像是请求已经到上游,但超时窗口内没
    的头像 发表于 03-11 09:47 476次阅读

    MySQL磁盘空间问题的成因排查方法

    运维工程师经常会遇到这样的场景:MySQL 服务器的磁盘空间告警,但查看数据目录时发现数据库本身并不大。大量磁盘空间被未知文件消耗。通过排查发现,二进制日志(Binary Log)是主要的磁盘空间消耗者。
    的头像 发表于 04-13 13:57 159次阅读

    Nginx日志分析命令实践和常见问题排查思路

    日常运维工作中,日志分析是排查问题最直接的手段。Nginx 作为入口层代理,几乎所有请求都要经过它。当网站出现响应慢、500 错误502 网关超时、限流失效等问题时,第一反应应该是查
    的头像 发表于 04-15 14:12 261次阅读