1. 问题现象与初步诊断
最近在维护一个日均PV超过500万的电商平台时,我们遇到了一个棘手的Nginx 502问题。每当促销活动开始,用户就会频繁遇到"502 Bad Gateway"错误页面。通过分析Nginx错误日志,我们发现以下关键线索:
code复制2023/08/15 14:30:22 [error] 1234#0: *5678 recv() failed (104: Connection reset by peer) while reading response header from upstream
2023/08/15 14:30:23 [error] 1234#0: *5680 upstream timed out (110: Connection timed out) while reading response header from upstream
这些错误有几个明显特征:
- 主要发生在流量高峰期(上午10点和晚上8点)
- 错误类型集中在连接重置和超时两类
- 后端服务器负载监控显示CPU使用率经常超过90%
提示:502错误本质上是一个"信号"而非"问题本身",它告诉我们Nginx与后端服务的通信出现了故障,但具体原因需要进一步排查。
2. 深入排查502错误的五个维度
2.1 后端服务健康状态检查
首先需要确认后端服务是否正常运行。我们使用以下命令检查PHP-FPM状态:
bash复制systemctl status php-fpm
netstat -anp | grep php-fpm
发现PHP-FPM进程虽然存在,但活跃连接数经常达到配置的最大值(pm.max_children = 50)。这说明后端处理能力已经达到上限。
2.2 超时配置分析
对比Nginx和PHP-FPM的超时配置发现严重不匹配:
| 配置项 | Nginx值 | PHP-FPM值 | 问题 |
|---|---|---|---|
| 读取超时 | proxy_read_timeout=60s | request_terminate_timeout=30s | PHP-FPM会先终止请求 |
| 连接超时 | proxy_connect_timeout=60s | - | - |
| 发送超时 | proxy_send_timeout=60s | - | - |
这种配置会导致PHP-FPM已经终止请求后,Nginx仍在等待响应,最终触发502错误。
2.3 网络连接排查
使用tcpdump抓包分析Nginx与PHP-FPM的通信:
bash复制tcpdump -i any port 9000 -w php-fpm.pcap
分析发现大量TCP RST(重置)包,表明连接被异常终止。进一步检查发现内核参数net.ipv4.tcp_tw_reuse未开启,导致TIME_WAIT状态连接堆积。
2.4 资源监控数据
通过Prometheus收集的系统指标显示:
- 内存使用率在高峰期达到95%
- 每秒上下文切换超过50000次
- 磁盘I/O等待时间经常超过100ms
这表明系统资源已经成为瓶颈。
2.5 慢请求分析
启用Nginx的$upstream_response_time日志字段,发现部分请求处理时间超过20秒。通过XHProf分析发现这些慢请求主要集中在下单和支付接口。
3. 优化方案与实施
3.1 配置调优
调整Nginx和PHP-FPM的关键参数:
nginx复制# Nginx配置
proxy_connect_timeout 5s;
proxy_read_timeout 15s;
proxy_send_timeout 15s;
keepalive_timeout 30s;
keepalive_requests 100;
ini复制; PHP-FPM配置
pm = dynamic
pm.max_children = 200
pm.start_servers = 30
pm.min_spare_servers = 20
pm.max_spare_servers = 50
pm.max_requests = 500
request_terminate_timeout = 20s
3.2 内核参数优化
bash复制# 调整系统参数
echo 'net.ipv4.tcp_tw_reuse = 1' >> /etc/sysctl.conf
echo 'net.core.somaxconn = 65535' >> /etc/sysctl.conf
echo 'vm.swappiness = 10' >> /etc/sysctl.conf
sysctl -p
3.3 架构改进
- 引入Redis缓存热点数据
- 将支付服务拆分为独立微服务
- 对静态资源启用CDN加速
- 实现自动扩缩容机制
3.4 监控体系建设
配置完整的监控告警系统:
- Nginx错误日志实时监控
- PHP-FPM进程状态监控
- 系统资源阈值告警
- 慢请求追踪系统
4. 验证与效果
优化后进行了为期一周的压测和观察:
| 指标 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| 502错误率 | 1.2% | 0.01% | 99% |
| 平均响应时间 | 850ms | 320ms | 62% |
| 最大并发量 | 1500 | 4500 | 200% |
| CPU使用率 | 95% | 75% | - |
5. 经验总结与避坑指南
- 不要盲目增加超时时间:这只会掩盖问题而非解决问题
- 配置一致性检查:确保Nginx和上游服务的超时设置匹配
- 监控先行原则:没有监控就无法证明优化效果
- 渐进式优化:每次只调整一个参数并观察效果
- 容量规划:根据业务增长定期评估系统容量
在实际操作中,我们发现php-fpm的pm.max_requests参数特别重要。设置过低会导致频繁进程重启,设置过高又可能引发内存泄漏。经过多次测试,500-1000是一个比较合理的范围。
另一个容易忽视的点是Nginx的keepalive配置。适当启用keepalive可以显著减少TCP连接建立的开销,但连接保持时间不宜过长,一般建议设置在30秒左右。