Wireshark 抓包实战:定位 nginx 502 / 504 根因的完整排查链路
上周帮一个客户查 nginx 502,问题拖了三天——前两个运维看日志只看到 502,没有更多线索。我上去抓了个包,10 分钟定位:是后端 Java 应用开了 keepalive 但没设心跳,nginx 的 keepalive 连接过了空闲超时被中间防火墙切掉,复用时报 502。只看日志永远查不出来,必须抓包。
为什么 502/504 必须抓包
nginx 错误日志里 502 通常只写:
110 是 Linux 内核错误码,翻译成人话就是"连不上"。但为什么连不上,可能原因有十几个:
- 后端进程崩溃了
- 后端端口变了(健康检查没同步)
- 中间防火墙切了 keepalive 连接
- TCP TIME_WAIT 堆积占满端口
- MTU 不匹配导致大包丢失
- DNS 解析慢了
日志看不出来,抓包才能看见是谁发了 RST、谁超时了、有没有分片丢包。
第一步:用 tcpdump 抓原始包
生产服务器通常没有 Wireshark GUI,先用 tcpdump 抓到 .pcap 文件,再拉到本机分析。
# 抓 nginx 与后端的通信(假设后端在 8080 端口)
tcpdump -nn -i any 'port 8080' -w /tmp/nginx.pcap &
# 用 & 放后台,复现一次 502,然后 kill %1 停抓
关键参数说明:
-nn不解析域名和端口名,直接显示 IP 和数字端口,速度快且不触发 DNS 查询干扰-i any抓所有网卡,适合多网卡环境-w file.pcap保存原始包,后续用 Wireshark 打开
抓完记得及时停,不然 /tmp/nginx.pcap 会越来越大,压垮磁盘。
第二步:用 tshark 命令行过滤关键包
不需要 GUI 时,tshark 是最快的过滤工具。
# 只看 RST 包(谁发出来的决定了是客户端还是服务端问题)
tshark -r /tmp/nginx.pcap -Y 'tcp.flags.rst == 1' -T fields -e ip.src -e ip.dst -e tcp.seq
# 只看重传包(网络拥塞或丢包的铁证)
tshark -r /tmp/nginx.pcap -Y 'tcp.analysis.retransmission' -T fields -e ip.src -e ip.dst
# 只看 TIME_WAIT 状态的包
tshark -r /tmp/nginx.pcap -Y 'tcp.flags.fin == 1' -T fields -e ip.src -e ip.dst -e tcp.seq
# 只看大于 1460 字节的 TCP 载荷(MTU 问题信号)
tshark -r /tmp/nginx.pcap -Y 'tcp.len > 1460' -T fields -e ip.src -e ip.dst -e tcp.len
这四个过滤器覆盖了 80% 的 nginx 502/504 根因。
第三步:拉到本机用 Wireshark 深度分析
把 .pcap 文件拖到本机 Wireshark,重点看三个地方。
3.1 Follow TCP Stream —— 一锤定音
找到任意一条 nginx ↔ 后端的 TCP 会话,右键 → Follow → TCP Stream。
你会看到完整的六步对话:
Client (nginx) Server (backend)
SYN ─────────────────────────────────────→
←──────────────────────────────────── SYN-ACK
ACK ─────────────────────────────────────→
DATA (POST /api/xxx) ──────────────────→
(无响应,30s 后)
Client sends RST ─────────────────────→
最后这一行 RST 如果是 nginx 发的 → 后端超时(504);如果是后端发的 → 后端主动断连(502)。
3.2 Endpoint 统计 —— 看流量分布
Statistics → Endpoints,按字节数排序,一眼看出哪台机器是流量异常方。
如果后端 IP 的出站字节数接近 0 但入站正常 → 后端没有响应数据。
3.3 Conversations 视图 —— 看连接模式
Statistics → Conversations → IPv4,切换显示为 TCP,可以看到:
- 连接总数
- 每个连接的 Duration(持续时长)
- Packet 数 / Byte 数
翻车信号:大量连接 Duration 为 0,说明都是瞬时建立就断开的,典型 keepalive 配置错误或防火墙切连。
四个实战场景速查
场景 A:RST 来自后端
现象:Wireshark 里 nginx 发 SYN,后端回 RST。
原因:后端服务挂了,或端口监听地址不对(比如只监听了 127.0.0.1 没听 0.0.0.0)。
验证命令:
场景 B:RST 来自 nginx
现象:握手成功,nginx 发数据后长时间无响应,最后 nginx 发 RST。
原因:后端处理超时,nginx proxy_read_timeout 默认 60s,超时主动断。
修复方向:
location / {
proxy_read_timeout 120s; # 给后端更多时间
proxy_send_timeout 120s;
proxy_connect_timeout 10s;
}
场景 C:TIME_WAIT 堆积
现象:ss -tan | awk '{print $1}' | sort | uniq -c | sort -rn 看到 TIME-WAIT 几千个。
原因:nginx 作为主动关闭方,短时间内大量建连断连,TIME_WAIT 来不及回收。
影响:新连接建不上,表现为间歇性 502。
修复:
# Linux 4.19+ 安全启用(内核有 SYN 攻击检测保护)
sysctl -w net.ipv4.tcp_tw_reuse=1
# 扩大 ephemeral port 范围
sysctl -w net.ipv4.ip_local_port_range="1024 65535"
场景 D:MTU 黑洞
现象:小包能通,大包不通;telnet 能连上但 curl 超时。
验证:
# 看本地 MTU
ip link show | grep mtu
# 抓 SYN 包看 MSS 协商值(MTU - 40 = MSS)
tcpdump -nn -i any 'tcp[tcpflags] & tcp-syn != 0' -c 10
修复:两端 MTU 对齐,或开启 PMTU 发现(net.ipv4.tcp_mtu_probing=1)。
tshark 一键排障脚本
把上面四个场景串成一个脚本,一条命令出结论:
#!/bin/bash
# wh-examine.sh - Wireshark 502 快速诊断
PCAP=${1:-/tmp/nginx.pcap}
[ ! -f "$PCAP" ] && echo "用法: $0 <pcap文件>" && exit 1
echo "=== 1. RST 来源 ==="
tshark -r "$PCAP" -Y 'tcp.flags.rst == 1' -T fields -e ip.src -e ip.dst 2>/dev/null | head -5
echo -e "\n=== 2. 重传统计 ==="
tshark -r "$PCAP" -Y 'tcp.analysis.retransmission' 2>/dev/null | wc -l | xargs echo "重传包数:"
echo -e "\n=== 3. TIME_WAIT 相关 FIN 包 ==="
tshark -r "$PCAP" -Y 'tcp.flags.fin == 1' 2>/dev/null | wc -l | xargs echo "FIN 包数:"
echo -e "\n=== 4. 大包 (>1460B) 检查 ==="
tshark -r "$PCAP" -Y 'tcp.len > 1460' 2>/dev/null | wc -l | xargs echo "大包数:"
echo -e "\n=== 5. 异常连接(Duration=0 的 TCP 会话)==="
tshark -r "$PCAP" -Y 'tcp' -T fields -e ip.src -e ip.dst 2>/dev/null \
| sort | uniq -c | sort -rn | head -5
排查流程速查表
| 症状 | 优先看什么 | 关键过滤器 / 命令 |
|---|---|---|
| 间歇性 502 | RST 来源 | tcp.flags.rst == 1 |
| 固定 URL 超时 504 | TCP Stream 长度 | Follow TCP Stream |
| 高峰期才 502 | TIME_WAIT 堆积 | ss -tan \| awk '{print $1}' |
| 小包通大包不通 | MTU / MSS | tcp.len > 1460 |
| 连接建立后无响应 | 重传包 | tcp.analysis.retransmission |
写在最后
nginx 502/504 的本质是网络层发生了什么,应用层只记录了结果。抓包是把结果逆推到原因的唯一可靠方法。学会 Follow TCP Stream 和这四个过滤器,80% 的排障不再需要猜。