14人参与 • 2026-01-27 • Linux
监控告警:nginx 502错误率飙升到5%。
看了眼后端服务,运行正常,没有报错。重启nginx,好了一会又开始502。
排查了3个小时,最后发现是upstream配置的问题。记录一下排查过程。
监控数据:
特点:
tail -f /var/log/nginx/error.log
发现大量这样的错误:
upstream timed out (110: connection timed out) while connecting to upstream upstream prematurely closed connection while reading response header
关键信息:是upstream连接的问题,不是后端服务本身的问题。
# 查看后端服务进程 ps aux | grep java # 查看端口监听 ss -tlnp | grep 8080 # 直接测试后端 curl -i http://127.0.0.1:8080/health
后端服务正常,直接访问返回200。
# 查看nginx到后端的连接数
ss -ant | grep 8080 | wc -l
# 查看连接状态分布
ss -ant | grep 8080 | awk '{print $1}' | sort | uniq -c发现问题了:
850 established
120 time_wait
50 syn_sent有50个连接卡在syn_sent状态,说明nginx到后端的新连接建立不上。
# 查看后端服务的accept队列 ss -lnt | grep 8080
输出:
state recv-q send-q local address:port listen 129 128 0.0.0.0:8080
问题找到了! recv-q是129,send-q是128。
这说明accept队列满了(128是默认值),新连接无法被接受。
客户端 → syn → 服务端(半连接队列) 服务端 → syn+ack → 客户端 客户端 → ack → 服务端(全连接队列/accept队列) 应用程序 accept() → 取出连接
当accept队列满了,新的完成三次握手的连接无法进入队列,客户端会收到超时或rst。
后端是spring boot应用,默认配置:
server:
tomcat:
accept-count: 100 # tomcat的accept队列而系统层面的限制是net.core.somaxconn = 128,取两者较小值,所以实际accept队列只有128。
流量高峰时:
# 查看当前值 sysctl net.core.somaxconn # 临时修改 sysctl -w net.core.somaxconn=65535 # 永久修改 echo "net.core.somaxconn = 65535" >> /etc/sysctl.conf sysctl -p
server:
tomcat:
accept-count: 1000 # accept队列大小
max-connections: 10000 # 最大连接数
threads:
max: 500 # 最大工作线程数upstream backend {
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
keepalive 100; # 保持连接数,减少新建连接
}
server {
location / {
proxy_pass http://backend;
proxy_connect_timeout 5s; # 连接超时
proxy_read_timeout 60s; # 读取超时
proxy_send_timeout 60s; # 发送超时
proxy_http_version 1.1; # 使用http/1.1
proxy_set_header connection ""; # 配合keepalive
}
}如果单实例撑不住,可以部署多实例:
upstream backend {
least_conn; # 最少连接数策略
server 127.0.0.1:8080 weight=1;
server 127.0.0.1:8081 weight=1;
server 127.0.0.1:8082 weight=1;
keepalive 100;
}系统参数(/etc/sysctl.conf):
net.core.somaxconn = 65535 net.ipv4.tcp_max_syn_backlog = 65535 net.core.netdev_max_backlog = 65535
spring boot配置:
server:
tomcat:
accept-count: 2000
max-connections: 20000
threads:
max: 500
min-spare: 50nginx配置:
upstream backend {
server 127.0.0.1:8080;
keepalive 200;
}
server {
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header connection "";
proxy_connect_timeout 5s;
proxy_read_timeout 60s;
}
}| 指标 | 优化前 | 优化后 |
|---|---|---|
| 502错误率 | 5% | 0.01% |
| accept队列溢出 | 频繁 | 无 |
| 连接建立时间 | 不稳定 | 稳定<5ms |
# 查看nginx错误日志 tail -f /var/log/nginx/error.log # 查看连接状态 ss -ant | grep <端口> # 查看监听队列 ss -lnt | grep <端口> # 查看队列溢出统计 netstat -s | grep -i listen # 查看系统参数 sysctl net.core.somaxconn # 实时监控连接数 watch -n 1 'ss -ant | grep <端口> | wc -l'
| 502原因 | 排查方向 |
|---|---|
| upstream timed out | 后端处理慢或连接队列满 |
| connection refused | 后端服务没启动 |
| no live upstreams | 所有后端都不可用 |
| prematurely closed | 后端主动断开连接 |
这次的坑:后端服务看起来正常,但accept队列满了,新连接进不来。
教训:
somaxconn=128太小,生产环境必须调大keepalive可以减少新建连接,降低队列压力以上就是线上nginx频繁502的排查过程与解决方案的详细内容,更多关于线上nginx频繁502排查的资料请关注代码网其它相关文章!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论