Linux 网络排障实战:从 ss、tcpdump 到 conntrack 与内核参数调优 原创
服务器网络出问题,最常见的话术是「ping 不通」「端口连不上」「请求超时」。但 ping 通不代表 TCP 能握手,TCP 能握手不代表应用层能返回——每一层都有自己的排查工具。这篇把四层模型从下到上捋一遍,配合 ss、tcpdump、conntrack、sysctl 四个工具,给出一套可以照着走的决策路径。
一、先定位层:从 L3 到 L7 的三连问
收到「连不上」的反馈,先别急着改配置。三个命令快速定位问题在哪一层:
# L3 网络可达性
ping -c 3 -W 2 target_ip
# L4 TCP 握手
nc -zv -w 3 target_ip 443
# 或
ss -tan state syn-sent '( dport = :443 )'
# L7 应用层
curl -v --max-time 5 https://target_ip/ -k
ping 通但 nc 不通 → 防火墙或端口没监听;nc 通但 curl 失败 → 应用层问题(证书、协议、后端);ping 都不通 → 路由或安全组问题。先分清层,再上对应工具。
二、ss:看清当前的连接状态
netstat 已被 ss 全面替代,速度差一个数量级。常用组合:
# 谁在监听 443
ss -tlnp | grep :443
# 当前所有 TIME_WAIT(高并发服务的隐患)
ss -tan state time-wait | wc -l
# 按目标端口统计
ss -tan '( dport = :3306 )' | awk '{print $1}' | sort | uniq -c
# 查看连接的拥塞窗口、RTT
ss -ti
关键状态解读:
| 状态 | 含义 | 常见异常 |
|---|---|---|
| SYN-SENT | 客户端发出 SYN 没收到 ACK | 对端防火墙 DROP、路由不通 |
| SYN-RECV | 服务端回了 SYN+ACK 等 ACK | SYN 攻击、半连接队列满 |
| ESTABLISHED | 正常连接 | 数量过多 → 连接池泄漏 |
| CLOSE-WAIT | 对端关了,本地还没 close | 应用代码忘 close → 句柄耗尽 |
| TIME-WAIT | 主动关闭方的等待期 | 几万级 → 短连接过多 |
实战里最常踩的坑是 CLOSE-WAIT 堆积:看到上千个 CLOSE-WAIT 基本就是应用 bug,代码里拿到连接后没有 finally close。重启治标,改代码治本。
三、tcpdump:抓包验证猜想
ss 告诉你「现状是什么」,tcpdump 告诉你「过程发生了什么」。三个高频场景:
# 场景 1:验证 SYN 到底发没发出去 / 回没回来
tcpdump -i any -nn 'tcp port 443 and host 1.2.3.4' -c 20
# 场景 2:定位 RST 来源(谁重置了连接)
tcpdump -i any -nn 'tcp[tcpflags] & (tcp-rst) != 0' -c 50
# 场景 3:抓 HTTP 请求看响应码
tcpdump -i any -nn -A 'tcp port 80' | grep -E '^(GET|POST|HTTP)'
抓包结果的标准读法:
- 只有
S没有S.→ SYN 没回应,对端或链路丢包 S → S. → R→ 对端立刻 RST,端口没监听或被 REJECTS → S. → . 之后 N 秒没数据→ 应用层卡死,查后端- 看到
[S]反复重传 → 中间链路丢包,mtr定位
四、conntrack:被低估的连接跟踪表
NAT、Docker、K8s、iptables 都依赖 conntrack。表满了之后新连接直接被丢,现象是「偶发超时」,最难排查。
# 当前连接数 vs 上限
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
# 满了会看到日志
dmesg | grep -i 'conntrack'
# nf_conntrack: table full, dropping packet
# 临时调大
sysctl -w net.netfilter.nf_conntrack_max=1048576
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
典型事故:容器节点 QPS 一上来就丢新连接,ss 看 ESTABLISHED 不多,但 nf_conntrack_count 顶到了默认 262144。把 max 调到百万级、把 TIME_WAIT 超时从默认 120s 降到 30s,立刻恢复。
五、内核参数:高并发服务的必调项
默认内核是为通用场景设计的,跑 Web / 网关 / 数据库要针对性调。常用最小集合:
# /etc/sysctl.d/99-net-tuning.conf
net.core.somaxconn = 4096 # listen backlog
net.ipv4.tcp_max_syn_backlog = 8192 # 半连接队列
net.ipv4.tcp_tw_reuse = 1 # TIME_WAIT 复用(仅出站安全)
net.ipv4.tcp_fin_timeout = 15
net.ipv4.ip_local_port_range = 1024 65535 # 出站端口范围
net.ipv4.tcp_keepalive_time = 300
net.core.netdev_max_backlog = 16384 # 网卡队列
执行 sysctl --system 生效。注意 tcp_tw_recycle 在 4.12 已被移除,且 NAT 环境下开启会丢连接,不要再设。
六、一页决策图
把上面的工具串成一条路径,下次故障直接对照走:
| 现象 | 第一怀疑 | 验证命令 | 常见处置 |
|---|---|---|---|
| ping 不通 | 路由 / 安全组 | mtr、traceroute | 改路由或 ACL |
| SYN 没回应 | 对端丢包 | tcpdump 看 S/S. | 防火墙 DROP → ACCEPT |
| SYN 立即 RST | 端口没监听 | ss -tlnp | 启动服务或改 bind |
| 握手成功但无响应 | 后端卡死 | ss -ti、strace | 查应用锁/慢查询 |
| 偶发新连接失败 | conntrack 满 | nf_conntrack_count | 调 max + 降 timeout |
| CLOSE-WAIT 堆积 | 应用没 close | ss -tan state close-wait | 修代码 + 重启 |
| TIME_WAIT 上万 | 短连接过多 | ss -s | 连接池 / Keep-Alive |
结语
网络排错的难点不在工具,在于能否快速把「连不上」翻译成「哪一层的哪个状态不对」。ss 看现状、tcpdump 看过程、conntrack 看内核表、sysctl 调参数,四件套配合决策表,95% 的网络问题都能在十分钟内定位到根因。剩下 5% 通常需要配合应用日志,那就是下一篇要讲的链路追踪了。