ElIauk

Linux 网络排查:ss、tcpdump、curl

先分清楚是哪一层 “接口连不上”是一个太笼统的描述。请求从客户端到服务端,至少要经过 DNS 解析、TCP 握手、TLS 握手、HTTP 请求、应用处理五段,任何一段出问题,表现都可能是超时。排查的第一步不是抓包,而是用分层工具把问题缩小到某一层。 常用的组合是:getent hosts 看域名解析

评论
Linux 网络排查:ss、tcpdump、curl

先分清楚是哪一层

“接口连不上”是一个太笼统的描述。请求从客户端到服务端,至少要经过 DNS 解析、TCP 握手、TLS 握手、HTTP 请求、应用处理五段,任何一段出问题,表现都可能是超时。排查的第一步不是抓包,而是用分层工具把问题缩小到某一层。

常用的组合是:getent hosts 看域名解析,ss 看本机监听和连接状态,nc 测端口通不通,curl -v 看端到端请求,tcpdump 在怀疑网络丢包时抓包,mtr 看链路质量。工具不在多,关键是从便宜到贵、从应用到链路依次排除。

ss:先看连接状态

ss 已经基本取代 netstat,输出更快,字段也更清晰:

ss -lntp
ss -s
ss -tan state established '( sport = :8080 )'
ss -tan state time-wait | wc -l
ss -tnp dst 10.0.0.12:3306

-l 看监听,-t 看 TCP,-n 不解析域名,-p 显示进程。Recv-Q 在 LISTEN 状态下表示全连接队列里还没被应用 accept 的连接数,持续大于 0 说明应用处理不过来或 accept 线程卡住;Send-Q 在 LISTEN 状态下是 backlog 上限。ESTABLISHED 多不一定是问题,TIME_WAIT 多也通常是主动关闭方的正常现象,真正要警惕的是 CLOSE_WAIT 持续增长,那说明应用没有正确关闭连接。

tcpdump:只在需要时抓包

抓包能看到 TCP 握手、重传、RST,是判断“网络问题还是应用问题”的终极手段:

tcpdump -i any -nn -s 0 -c 100 \
  'tcp port 8080 and host 10.0.0.12' \
  -w /tmp/8080.pcap

tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-syn|tcp-rst) != 0'

第一条把符合条件的报文写到文件,再用 Wireshark 分析;第二条只看 SYN 和 RST,适合快速判断连接是被拒绝还是超时。-s 0 抓完整包,-c 限制数量,避免抓太多把磁盘写满。生产环境抓包有性能开销,尽量加精确过滤条件、限制时长,抓完立即停止。

如果看到 SYN 发出去了但没有 SYN-ACK,问题可能在防火墙、安全组或对端没监听;看到 SYN 后立刻 RST,通常是对端端口关闭或拒绝策略;看到大量重传,检查链路丢包和 MTU。

curl:端到端验证

curl -v 能看到 DNS、连接、TLS、请求头、响应码的完整过程,是最常用的验证工具:

curl -v --connect-timeout 2 --max-time 5 \
  http://10.0.0.12:8080/actuator/health

curl -v --resolve order.example.com:443:10.0.0.12 \
  https://order.example.com/actuator/health

--resolve 可以绕过 DNS,直接把域名指到某个 IP,用来判断“是 DNS 解析错了,还是后端有问题”。看耗时分布用 -w:

curl -s -o /dev/null -w \
  'dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total}\n' \
  https://order.example.com/actuator/health

time_connect 高说明 TCP 握手慢,通常是网络或防火墙;time_appconnect 高说明 TLS 握手慢,检查证书链和 OCSP;time_starttransfer 高说明服务端处理慢。把总耗时拆开,比盯着“接口 3 秒”有用得多。

常见坑

1. ping 通就认为端口通

ICMP 和 TCP 是两套东西,防火墙完全可能放行 ICMP、拒绝 8080。端口是否可达要用 nc -zv host port 或 curl 验证,ping 只能说明网络层可达。

2. 服务监听在 127.0.0.1

ss -lntp 显示 127.0.0.1:8080,容器外或另一台机器当然连不上。需要对外提供服务时监听 0.0.0.0,但要注意安全组和防火墙只放行必要来源。

3. CLOSE_WAIT 越积越多

CLOSE_WAIT 表示对端已经关闭,本端还没调用 close。常见于连接池配置错误、异常分支没有关闭流、HTTP 客户端没有复用连接。看 ss -tan state close-wait 对应的进程,再查代码里的资源释放。

4. 容器里抓不到包

容器默认只有自己的网络命名空间,tcpdump 抓不到宿主机或其他容器的流量。需要抓哪个网卡就用 -i 指定,或者在宿主机上抓 docker0、veth 对。Kubernetes 环境可以用 nsenter 进入目标容器的网络命名空间。

5. DNS 解析慢但 nslookup 很快

应用可能走了不同的 resolver,或者 resolv.conf 里配了多个 nameserver,第一个超时才切第二个。Java 还会缓存 DNS 结果,networkaddress.cache.ttl 配置不当会导致 IP 变更后仍然连旧地址。用 getent hosts 验证系统解析路径,再看 JVM 的 DNS 缓存配置。

6. conntrack 表满

NAT 场景下连接数超过 nf_conntrack_max,新连接会被丢弃,表现是间歇性超时。dmesg | grep conntrack 能看到 table full, dropping packet,sysctl net.netfilter.nf_conntrack_count 看当前用量。先排查连接泄漏,再考虑调大上限。

排查步骤

按“解析 → 监听 → 端口 → 请求 → 链路”的顺序走:

getent hosts order.example.com
ss -lntp | grep 8080
nc -zv 10.0.0.12 8080
curl -v --connect-timeout 2 http://10.0.0.12:8080/actuator/health
mtr -n -c 20 10.0.0.12

解析正常、端口通、curl 也通,问题就在应用内部,转去看日志和线程栈;端口不通,检查防火墙和安全组;curl 通但偶发超时,用 tcpdump 看是否有重传或 RST。每一步都记录时间点和源 IP、目标 IP,别在一堆终端里来回猜。

小结

网络排查的核心是分层和证据:ss 看本机状态,curl 看端到端,tcpdump 看链路上的包,mtr 看路径质量。先用低成本工具缩小范围,再决定要不要抓包。大多数“网络问题”最后都能定位到监听地址、防火墙规则或连接没有释放。

参考

评论

推荐阅读

订阅邮件

订阅更新,及时收到最新文章。

作者