Linux 网络排查命令速查:连接数暴涨到 2 万那晚,我是这样用 ss、tcpdump、mtr、dig 一层层揪出真凶的
📝 摘要:服务器突然抽风、502、新连接建不出,网络排查工具一大堆却不知先敲哪条?本文按「连通性 → 端口连接 → DNS → 抓包 → 网卡流量」分层速查 ss、tcpdump、mtr、dig、lsof、nc、ip 等核心命令,重点讲 ss 怎么按状态数连接,并复盘一次 TCP 连接从 5k 暴涨到 2 万的实战,顺带拆穿 TIME_WAIT、CLOSE_WAIT、%util 三个经典误解。
半夜告警炸群:支付超时、登录转圈、接口抽风式 502。你 SSH 上机器,top 看着不高,日志翻不出堆栈,这时候——你第一条命令敲什么?
大多数人卡就卡在这:网络排查的命令一抓一大把(ping、netstat、tcpdump、ss、dig……),但手忙脚乱地乱敲,和按层次一条链路查下去,是两种完全不同的体验。这篇把这套工具按「排查顺序」串成一份速查表,最后用一次真实的连接数暴涨事故,演示怎么从现象一路查到根因。
一、先建立一张"分层排查"地图
网络问题几乎都能套进 TCP/IP 的分层模型里排查。与其记一堆命令,不如先记住从下往上、从近到远这条主线,每一层配一两个趁手的命令:
| | |
|---|
| | ip a |
| | ping |
| | ss |
| | dig |
| | tcpdump |
| | iftop |
💡 这张表是"分层地图",用来快速定位问题落在哪一层;但后文的讲解顺序按实战命中率来——线上问题十有八九落在「连接层」,所以下面从最常用的 ss 讲起,而不是死板地从网卡往上铺。真正上手排查时仍记住一点:先证伪最底层(网卡、连通性),再往上查应用层,能避免一上来就 tcpdump 抓一堆看不懂的包。
本文默认你已经会用 curl 做 HTTP 层的探测和计时——那块是另一个大主题,这里不展开,详见《curl 实战:程序员必备的接口调试与性能排查利器》。
二、端口与连接:ss 才是主角(netstat 该退休了)
排查线上问题,十次有八次落到「连接」这一层——端口通不通、连接堆在什么状态、谁占满了连接池。这层的主角是 ss,不是很多人肌肉记忆里的 netstat。
2.1 为什么用 ss 不用 netstat
结论:netstat 只在老机器上应急,新机器一律 ss。连接一多的时候,netstat 自己都可能卡住,ss 才是你要的。
2.2 ss 速查
# 一眼看全局:各类 socket 总数 + TCP 各状态计数(排查连接暴涨第一条)ss -s# 列 TCP 连接:-t TCP / -u UDP / -a 全部 / -n 不解析端口名 / -p 显示进程ss -tanp# 只看监听端口(服务起没起、监听在哪个地址)ss -tlnp# 按状态过滤:只看 TIME-WAIT / ESTABLISHED / CLOSE-WAITss -tan state time-waitss -tan state establishedss -tan state close-wait# 按端口过滤:连到 8123(比如某个数据库)的所有连接ss -tanp '( dport = :8123 or sport = :8123 )'# 按对端 IP 过滤ss -tanp dst 10.0.1.5# 王牌一条:按状态给连接分组计数(定位「连接堆在哪个状态」)ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn# 数某个状态有多少条(记得减掉表头)ss -tan state time-wait | wc -l
ss -s 的输出长这样(示意):
Total: 22185TCP: 22037 (estab 812, closed 20800, orphaned 3, timewait 20790)
一眼就能读出关键信息:总连接 22037,其中timewait 就占了 20790——这是个强烈的信号,后面第八节会拿它当破案线索。
2.3 看懂 TCP 状态:TIME_WAIT 和 CLOSE_WAIT 到底谁的锅
ss 输出里的状态列,是排查的核心。两个最容易堆积、也最容易背锅的状态一定要分清:
| | |
|---|
ESTAB | | |
TIME-WAIT | | 通常是你这端在疯狂主动断连(短连接高频),多数无害 |
CLOSE-WAIT | | ⚠️ 应用 Bug:代码没关连接 / 连接泄漏,越堆越多迟早耗尽 fd |
SYN-SENT | | 大量堆积 = 连不上对端(对端挂了 / 防火墙 / 端口没开) |
SYN-RECV | | 大量堆积 = 可能被 SYN flood,或对端回不来 |
一句话记忆:TIME-WAIT 是"你太勤快地关连接",CLOSE-WAIT 是"你忘了关连接"。前者调参数,后者改代码。
TCP 十一种状态的完整状态机源自 RFC 793,排查时不用背全,但 ESTAB / TIME-WAIT / CLOSE-WAIT / SYN-* 这几个高频状态的含义必须张口就来。
三、连通性与丢包:ping、traceroute、mtr
端口层之外,第二高频的是「到底通不通、在哪丢包」。
# 基础连通性(-c 次数,别忘了很多云主机默认禁 ICMP,ping 不通不等于服务不通)ping -c 4 example.com# 路径追踪:看数据包经过哪些跳、哪一跳开始变慢traceroute example.com# mtr = ping + traceroute 合体,持续统计每一跳的丢包率和延迟(排跨网/跨境问题神器)mtr -rwzbc 100 example.com# -r 报告模式 / -w 宽输出 / -z 显示 ASN / -b 同时显示 IP 和域名 / -c 100 探测 100 次
mtr 的杀手锏是分段定位丢包:如果丢包从第 6 跳才开始、且一路持续到目的地,那问题大概率在第 6 跳那个运营商节点,而不是你的机器或对端服务。
⚠️ 中间跳丢包不一定是真丢包:很多路由器对 TTL 耗尽的 ICMP 限速(deprioritize),会显示某一跳丢包但末跳正常——只有"末跳持续丢包"才是真丢包,中间跳单独丢包往往是幻觉。
跨境上传慢、大文件传输卡这类"看着像后端锅、实为链路丢包"的实战,可参考 《上传 20MB 视频花了 11 分钟:真凶不是 Nginx,也不是后端,是跨境丢包》。
四、DNS:dig、nslookup、host
"代码没动、就是连不上",十次里有几次是 DNS 解析出了岔子(解析超时、解析到旧 IP、解析到内网/外网错了地址)。
# 最常用:只要解析结果,干净利落dig +short example.com# 指定 DNS 服务器查(排查”是不是本机 DNS 缓存/配置的问题”)dig example.com @1.1.1.1# 只看 answer 段,别的噪音都去掉dig example.com A +noall +answer# 从根域一路追下来,看解析链路在哪断(排查解析不一致)dig +trace example.com# 反向解析:IP 查域名dig -x 10.0.1.5# 轻量版(nslookup 更老但到处都有;host 输出最简洁)nslookup example.comhost example.com
排查套路:先 dig +short 看解析结果对不对,不对再 dig @公共DNS 对比——如果换个 DNS 就正常,那是本机 /etc/resolv.conf 或内网 DNS 的问题;如果换谁都错,那是权威记录本身配错了。
域名明明能解析、curl 也通,就是浏览器打不开?那可能是代理/fake-ip 层的坑,和 DNS 解析本身无关,排查思路见 【待发布后补充引用关系:《curl 通、关掉代理也通,就浏览器打不开:一次 Clash TUN + fake-ip 的三层排查》】。
五、端口探测与占用:nc、telnet、lsof
# 探端口通不通(-z 只探测不发数据 / -v 详细 / -w 2 超时 2 秒)nc -zv -w 2 10.0.1.5 8123# 老古董但哪都有:telnet 10.0.1.5 8123# 谁占了这个端口?(排查”端口已被占用 / Address already in use”)lsof -i :8123ss -tlnp '( sport = :8123 )' # ss 也能干同样的活# 某个进程开了哪些网络连接lsof -i -nP -p# 本机所有 ESTABLISHED 连接 + 对应进程lsof -i -nP | grep ESTABLISHED
nc -zv host port 是验证"端口层通不通"最快的一条命令——比起 curl 还要发 HTTP 请求,nc 只做 TCP 握手,能干净地把「网络不通」和「应用层报错」区分开。
六、抓包:tcpdump 最小必备姿势
前面几层都定位不了,就得看报文真相了:到底谁先发的 RST?握手卡在哪一步?
# 抓指定主机+端口,-nn 不解析 IP 和端口名(否则反向解析能卡死你)tcpdump -i any -nn -c 20 host 10.0.1.5 and port 8123# 存成 pcap 拖回本地用 Wireshark 慢慢看(线上抓包首选,别在终端直接肉眼看)tcpdump -i any -nn host 10.0.1.5 and port 8123 -w /tmp/cap.pcap# 看内容(-A 以 ASCII 打印,排查明文协议;-X 十六进制+ASCII)tcpdump -i any -nn -A host 10.0.1.5 and port 80# 只抓 SYN 包(排查握手建不起来 / 谁在发起连接)tcpdump -i any -nn 'tcp[tcpflags] & tcp-syn != 0'# 只抓 RST 包(排查连接被谁重置了)tcpdump -i any -nn 'tcp[tcpflags] & tcp-rst != 0'
三条铁律:
- 一定加
-nn:不解析主机名和端口名,否则 tcpdump 每抓一个包都去做一次反向 DNS,现场直接卡住。 - 线上优先
-w 存文件:别在终端裸看,抓下来用 Wireshark 分析,过滤和追踪流(Follow TCP Stream)方便一万倍。 - 过滤条件写精准:
host x and port y,不然高流量机器上瞬间几十万个包,信息全淹了。
七、网卡、路由与流量:ip、ethtool、iftop
最底层的"物理"排查,以及"带宽被谁吃了"。
# 网卡地址 / 路由 / ARP 邻居(ip 已全面取代 ifconfig、route、arp)ip -br a # 简洁版,一行一个网卡ip r # 路由表ip neigh # ARP 邻居表ip -s link # 收发包统计,看 errors/dropped# 网卡协商速率 / 双工 / 链路状态(排查”网卡跑在 100M 没跑到千兆”)ethtool eth0# 网卡级错误统计:丢包、CRC 错误、ring buffer 溢出ethtool -S eth0 | grep -Ei 'err|drop|discard'# 实时看谁在吃带宽(按连接维度)iftop -i eth0# 按网卡看总进出带宽nload# 综合流量监控iptraf-ng
ip -s link 里的 errors/dropped 和 ethtool -S 里的 drop 计数,是排查"偶发丢包、莫名重传"时容易被忽略的一层——网卡 ring buffer 溢出、协商速率不对,应用层是完全无感的。
💡 容器里没有这些命令怎么办? 容器镜像往往精简掉了 ss/tcpdump。不用往容器里装,直接在宿主机上"钻进"容器的网络命名空间执行:
PID=$(docker inspect -f '{{.State.Pid}}' <容器名>)nsenter -t $PID -n ss -tanp # 用宿主机的 ss 看容器的连接nsenter -t $PID -n tcpdump -nn -i any
八、实战:连接数从 5k 冲到 2 万,ss 一条链路揪出真凶
光有速查表不够,来看一次真实事故怎么用这套工具串起来破案(细节已脱敏)。
现象:一个 C 端在线服务(OLTP 主接口)间断性 502、抽风式不可用。top 看 CPU 不算高,进程也没挂,但新请求就是进不来。
第一步——先看连接层(ss -s):
TCP: 22037 (estab 812, closed 20800, orphaned 3, timewait 20790)
平时这台机器 TCP 连接常态几千,现在冲到2.2 万,而且一眼就看出结构不对:estab 才 812,timewait 却有 2 万。连接被大量快速地建立又关闭——这不是正常业务流量该有的形状。
第二步——按状态分组确认(ss分组计数):
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn# 20790 TIME-WAIT# 812 ESTAB# 3 SYN-SENT
TIME-WAIT 独大,说明是本机在疯狂主动关连接。谁在关?
第三步——按端口定位是谁(ss端口过滤):
ss -tanp '( dport = :8123 )' | head
一过滤发现,海量连接指向下游某个 8123 端口的服务(一个 OLAP 数据库)。再顺着进程一看,是应用的健康检查在每秒几百次地去 ping 这个下游依赖,每次都新建连接、用完就关——于是 TIME-WAIT 像滚雪球一样堆到 2 万,把本机指向下游的 ephemeral 端口和连接资源逼近上限;叠加下游查询本身已经 hang 住,应用既拿不到可用连接、也建不出新的出站连接,对外表现就是"抽风式 502"。
第四步——旁证(tcpdump/ 监控):抓包确认这些连接都是短命的建连→关连,和 grafana 上的 TCP_alloc、TCP_tw 曲线暴涨完全对上。根因(下游数据库磁盘写满导致查询 hang、连接被占满)最终锁定。
这条链路的价值在于:ss -s 一眼看出连接结构异常 → 分组计数确认状态 → 端口过滤锁定下游 → 抓包/监控闭环。从现象到嫌疑人,ss 一个工具就走完了大半。
这次事故的完整复盘(OLAP 数据库混进 OLTP 主链路、健康检查打爆连接池的连锁反应)见 《OLAP 数据库混进 OLTP 链路:一次 ClickHouse 拖死 API 101 分钟的复盘》。
九、踩坑记录:那些年我们误解的网络命令
坑 1:以为 tcp_fin_timeout 能调短 TIME-WAIT
经典误区。Linux 上TIME-WAIT 的时长是内核里写死的 60 秒(TCP_TIMEWAIT_LEN),net.ipv4.tcp_fin_timeout 调的是FIN-WAIT-2状态,不是 TIME-WAIT。想缓解 TIME-WAIT 堆积,方向是 net.ipv4.tcp_tw_reuse(仅对主动发起的出站连接安全)。
⚠️ 另一个参数 tcp_tw_recycle 千万别开——它在 NAT 环境下会导致丢包,而且已在内核 4.12 中被移除。这段的权威解释见 Vincent Bernat 的 《Coping with the TCP TIME-WAIT state on busy Linux servers》,把 TIME-WAIT 的成本和调优讲得最透。参数语义可查 man 7 tcp。
坑 2:把 CLOSE-WAIT 堆积也当成"调参数"的问题
CLOSE-WAIT 堆积100% 是应用的锅——对端已经关了连接,你的代码却没调用 close()。调任何内核参数都没用,得去查代码:数据库连接、HTTP client、文件句柄是不是没在 finally 里关。CLOSE-WAIT 只增不减,就是连接/句柄泄漏的铁证。
坑 3:%util 100% 就以为磁盘/网卡到顶了
虽然这条是 IO 侧的老梗,但网络排查里同样适用一个思维:%util是"繁忙时间占比"而非"利用率"。单队列设备哪怕只有一个请求在飞,只要它一直在飞,%util 就能显示 100%,但设备其实很闲。看到 100% 别急着下"到顶了"的结论,用队列深度、await 这些指标交叉验证。
坑 4:ping 不通就断定"网络不通"
大量云主机、安全组默认禁 ICMP。ping 不通完全可能只是 ICMP 被墙,而 TCP 端口好好的。判断"端口层通不通",要用 nc -zv host port 或 curl,别拿 ping 当唯一依据。
坑 5:tcpdump 不加 -nn,现场被自己卡死
不加 -nn,tcpdump 会对每个包的 IP 做反向 DNS、对端口查 /etc/services,高流量下光解析就能把命令拖到不动,还额外制造 DNS 流量污染现场。线上抓包,-nn是肌肉记忆。
十、场景 → 命令速查表
排查时按"现象"直接查命令,不用从头想:
| | |
|---|
| ss -s | ss -tan | awk 'NR>1{print $1}' | sort | uniq -c |
| ss -tan state close-wait | wc -l | lsof -i -nP -p <PID> |
| nc -zv -w2 host port | ss -tlnp |
| mtr -rwzbc 100 host | tcpdump -w |
| dig +short 域名 | dig 域名 @1.1.1.1 |
| tcpdump -nn 'tcp[tcpflags] & tcp-rst!=0' | |
| iftop -i eth0 | nload |
| ip -s link | ethtool -S eth0 | grep -i drop |
| nsenter -t <PID> -n ss -tanp | nsenter -t <PID> -n tcpdump |
十一、总结
网络排查的关键不在于记住多少命令,而在于建立"分层、从下往上"的顺序感,让每个工具各就各位:
- 连接层用
ss(告别 netstat):ss -s 看全局、分组计数看状态、端口过滤锁嫌疑,这一套能解掉大半线上连接类问题; - 连通性用
mtr(比 ping/traceroute 更能定位丢包),记住"只有末跳持续丢包才是真丢"; - DNS 用
dig +short / dig @公共DNS 对比,快速区分本机配置还是权威记录的问题; - 报文真相用
tcpdump -w 抓下来给 Wireshark,-nn 别忘; - 状态含义分清:TIME-WAIT 是"关太勤"(调参数),CLOSE-WAIT 是"忘了关"(改代码)。
把这份速查表存起来,下次半夜告警时,你敲的第一条命令就不再是 top 之后的一片茫然,而是 ss -s。
延伸阅读
- 《curl 实战:程序员必备的接口调试与性能排查利器》 —— HTTP 层的探测与计时,和本文互补
- 《上传 20MB 视频花了 11 分钟:真凶不是 Nginx,也不是后端,是跨境丢包》 ——
mtr 定位丢包的实战 - 【待发布后补充引用关系:《curl 通、关掉代理也通,就浏览器打不开:一次 Clash TUN + fake-ip 的三层排查》】 —— DNS / 代理层的排查
- 《AI 服务 502 雪崩排查:从 Nginx 超时到连接池耗尽,查了两次才找到真凶》 —— 连接池耗尽的另一种姿势
- 权威参考:
man 8 ss、man 7 tcp、tcpdump 官方 man、Vincent Bernat: Coping with TCP TIME-WAIT
🏷️ 标签:Linux 网络排障 ss tcpdump TCP 运维实战