生产故障案例集
真实生产事故合集,按"现象 → 排查 → 根因 → 修复 → 预防"五段式。
案例 1:偶发 502,每分钟几次
现象
- Nginx error.log 偶发
upstream prematurely closed connection - 时间随机,没有规律
- 后端服务正常,没崩
排查
# 看错误频率
grep "prematurely closed" /var/log/nginx/error.log | wc -l
# 看错误时间分布
grep "prematurely closed" /var/log/nginx/error.log | awk '{print $1, $2}' | uniq -c
抓包发现:Nginx 通过 keepalive 连接发请求时,连接已被后端关闭,导致 RST。
根因
后端 Node 的 keepAliveTimeout(5s)小于 Nginx 的 keepalive_timeout(60s)。Nginx 拿了快过期的连接发请求,正好碰上后端关闭。
修复
// Node
server.keepAliveTimeout = 65 * 1000; // 比 Nginx 大
server.headersTimeout = 66 * 1000;
或 Nginx 端开重试:
proxy_next_upstream error timeout http_502;
proxy_next_upstream_tries 2;
预防
- 上下游 keepalive 时间必须 后端 > 前端代理
- 监控 502 错误率,超阈值告警
案例 2:reload 后部分请求 502
现象
执行 nginx -s reload 后几秒内偶发 502,之后恢复正常。
排查
看 error.log:
upstream timed out
no live upstreams while connecting to upstream
nginx -t 配置无误。
根因
新 worker 启动时还没解析完上游 DNS(server backend.example.com),请求过来时 upstream 列表为空。
老 Nginx 解析 DNS 只在启动时一次,新 worker 启动期间有几百毫秒窗口。
修复
# 显式配 resolver,让 Nginx 用动态 DNS
resolver 1.1.1.1 8.8.8.8 valid=30s ipv6=off;
upstream backend {
server backend.example.com resolve;
}
或者使用 IP 而非域名作 upstream。
预防
- 上游用 IP 或 K8s service 内部域名(短路径)
- 监控 reload 后短期 5xx 突增
案例 3:高并发下连接数飙升然后 500
现象
QPS 涨到一定阈值后,error.log 大量:
worker_connections are not enough
500 Internal Server Error
排查
ss -s
# Total: 65000+ TCP
# 每 worker 连接接近 worker_connections 上限
ss -tn state time-wait | wc -l
# 几万个 TIME_WAIT
根因
worker_connections 1024太小- 上游没用 keepalive,每请求新建 TCP → TIME_WAIT 堆积
- 本地端口耗尽
修复
events {
worker_connections 65535;
}
upstream backend {
server 10.0.0.1:8080;
keepalive 100;
}
location /api/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
系统层:
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.ip_local_port_range="10000 65535"
预防
- 压测找到 worker_connections 上限
- 监控 connections 使用率
案例 4:SPA 部署后偶发白屏
现象
用户报告偶尔打开页面白屏,刷新就好。
排查
浏览器 console:
Refused to execute script from 'app.abc123.js' because its MIME type ('text/html') is not executable
根因
发版后 CDN 部分节点还缓存着旧 index.html,引用的旧 hash JS 文件源站已删。Nginx 找不到旧 JS,try_files fallback 到 index.html,返回 HTML 给浏览器当 JS 执行。
修复
# JS / CSS 找不到就 404,不要 fallback
location ~* \.(js|css|woff2?|png|jpg|svg)$ {
try_files $uri =404;
expires 1y;
}
发版策略改为:
- 先发新版(保留旧 JS 文件)
- 等 CDN 全部刷完 + 用户老 HTML 缓存过期
- 清理 7 天前的旧 JS
预防
- 静态资源 404 监控
- 发版保留 N 个版本,不立即删
- 双写过渡
案例 5:CPU 100% 但 QPS 不高
现象
单台 Nginx CPU 一个核占满,其他核空闲。
排查
top -H -p $(pgrep nginx | head -1)
# 单线程 worker 跑满
只有 1 个 worker:
worker_processes 1;
根因
配置写死 worker_processes 1,老配置没改。
修复
worker_processes auto;
worker_cpu_affinity auto;
预防
- 配置 review checklist 强制
auto - 监控单核 CPU 使用率(不只看平均)
案例 6:CC 攻击打挂源站
现象
某天下午突然源站 CPU 100%、Nginx 大量 503,Node 服务被打死。 access.log 大量来自固定 IP 段的请求,UA 单一。
排查
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head
# Top IP 每秒上千请求
应急修复
临时封 IP 段:
deny 1.2.3.0/24;
deny 5.6.7.0/24;
加全局限流:
limit_req_zone $binary_remote_addr zone=global:10m rate=30r/s;
server {
limit_req zone=global burst=50 nodelay;
limit_req_status 429;
}
长期方案
- 接入 CDN / Cloudflare WAF
- fail2ban 自动封禁
- 关键接口加图形/滑动验证
- 监控 QPS 异常告警
案例 7:证书过期全站挂
现象
某天凌晨用户全部报 NET::ERR_CERT_DATE_INVALID。
根因
Let's Encrypt 证书 90 天有效期。certbot 自动续期任务在某次系统升级中坏了,几次续期失败没人看告警。
紧急修复
sudo certbot renew --force-renewal
sudo systemctl reload nginx
预防
- 监控证书剩余有效期(Prometheus blackbox_exporter)
- 30 天告警、7 天紧急告警
- certbot renew 日志监控
- 多通道告警(不要只邮件)
案例 8:WebSocket 连不上 / 频繁断
现象
前端报 1006 close code,断线重连不停。
排查
看 Nginx 配置,发现 /ws/ location 没配 Upgrade 头。
根因
WebSocket 升级握手 Nginx 默认不转 Upgrade/Connection 头。
修复
location /ws/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
}
预防
- WebSocket 路由必须配 snippet 模板
- 监控 WS 异常断开率
案例 9:上传大文件 413
现象
前端上传 50MB 文件,Nginx 直接返回 413 Request Entity Too Large。
根因
client_max_body_size 默认 1MB。
修复
# 全局或 location 级
location /api/upload {
client_max_body_size 100m;
client_body_buffer_size 1m;
client_body_timeout 300s;
proxy_pass http://backend;
}
后端(Node)也要相应调大:
app.use(express.json({ limit: '100mb' }))
案例 10:SSE 流式输出客户端等很久才收到
现象
后端 LLM 流式输出,期望 token 实时显示。但用户看到全部内容一次性出现。
根因
Nginx proxy_buffering on(默认),把流式响应攒着一次性发给客户端。
修复
location /api/stream {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off; # 关键
proxy_cache off;
proxy_read_timeout 3600s;
# SSE 必备
add_header X-Accel-Buffering no;
}
案例 11:日志写满磁盘
现象
系统报 No space left on device,所有写操作失败。
排查
df -h
du -sh /var/log/* | sort -h | tail
# /var/log/nginx/access.log 50G
紧急修复
# 立即释放(不要 rm,nginx fd 还持有)
sudo truncate -s 0 /var/log/nginx/access.log
sudo nginx -s reopen
根因
logrotate 配错或没生效。
预防
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
监控 /var/log 使用率,80% 告警。
案例 12:reload 后某些配置没生效
现象
改了 worker_processes、events { worker_connections },nginx -s reload 后通过 ps / top 看 worker 数没变。
根因
worker_processes、worker_connections 这类只在启动时读取,reload 不重启 worker 不生效。
修复
sudo systemctl restart nginx
# 而不是 reload
但 restart 会中断连接。可用热升级 kill -USR2 平滑切换。
预防
- 文档明确哪些配置 reload 生效、哪些需要 restart
- 变更评审时确认
案例 13:CORS 偶发失败
现象
同一 API 跨域请求有时成功有时失败,浏览器报 CORS preflight 错。
根因
CDN 缓存了第一个用户的响应(含 Access-Control-Allow-Origin: https://a.example.com),其他 Origin 用户拿到这个缓存被拒。
修复
add_header Vary Origin always; # 必加,告诉缓存按 Origin 分别存
add_header Access-Control-Allow-Origin $http_origin always;
always 关键字让 4xx/5xx 响应也加这个头。
案例 14:upstream 健康检查"假阳性"
现象
某后端实例其实已挂,但 Nginx 还在转发请求过去,导致大量 502。
根因
开源 Nginx 没有主动健康检查,依赖被动判断(请求失败 max_fails 次才标记 down)。max_fails 默认 1,但 fail_timeout 默认 10s,也就是 10s 内还会有些请求路由到挂的实例。
修复
- 用 Tengine / Nginx Plus 的主动健康检查
- 或用 K8s readinessProbe + Service(Nginx 之外)
- 调小
fail_timeout
upstream backend {
server 10.0.0.1:8080 max_fails=2 fail_timeout=5s;
server 10.0.0.2:8080 max_fails=2 fail_timeout=5s;
}
通用排查清单
遇到 Nginx 问题先按这个顺序看:
nginx -t配置语法tail -f /var/log/nginx/error.logsystemctl status nginxss -tnlp | grep nginx端口监听ps aux | grep nginx进程数 + 内存curl -I http://127.0.0.1本地直接访问- 上游:
curl -I http://upstream-ip:port - 抓包:
tcpdump -i any -nn host upstream-ip and port 8080
延伸阅读
- 模块 03 各篇文档
- Nginx 错误码完整列表
- SRE 工作手册:故障复盘 — 故障案例方法论