引言
“服务连不上"这五个字背后可能是 DNS 解析失败、端口没监听、防火墙拦截、TLS 握手失败、路由黑洞或应用层 500——没有分层方法,就只能在瞎猜里打转。本文给一套自上而下又自下而上的排障工具箱:先用 ping/mtr/traceroute 确认"路通不通”,用 dig 确认"名字能不能解析",用 ss/lsof 确认"端口开没开",用 tcpdump 确认"包到底发没发、回没回",最后用 curl 落到应用层。每一层都有对应的命令,按层排查就不会漏。
前置:curl 与 HTTP 调试实战、HTTP 状态码与请求语义速查。终端工作流见 终端与 Shell 生态进阶。
目录
- 1. 分层排障:从物理层到应用层
- 2. 连通性:ping、mtr 与 traceroute
- 3. DNS 诊断:dig、host 与解析链路
- 4. 端口与连接:ss、netstat 与 lsof
- 5. 抓包:tcpdump 与 tshark
- 6. HTTP 调试:curl 与 wrk
- 7. 延迟与丢包定位
- 8. 带宽与吞吐测量
- 9. 典型故障的排障剧本
- 10. 速查表与一句话记忆
- 延伸阅读
1. 分层排障:从物理层到应用层
核心方法:把"连不上"分解成可独立验证的层,逐层证伪。
| 层 | 问题 | 工具 |
|---|---|---|
| 链路/物理 | 网卡、网线、Wi-Fi | ip link、ethtool |
| 网络/IP | 路由、可达性 | ping、mtr、ip route |
| 传输/TCP | 端口、握手、连接 | ss、nc、tcpdump |
| 名字/DNS | 解析 | dig、host、nslookup |
| 应用/HTTP | 请求响应 | curl、wrk |
| TLS | 证书、握手 | openssl s_client、curl -v |
第一个问题永远是:“从哪台机器、到哪台机器、用哪个协议、哪个端口”——不定义"源→目的→端口",任何工具都是乱枪打鸟。两种顺序:自下而上(链路 → IP → TCP → DNS → 应用,逐层确认)或自上而下(先 curl 看报错 → 按报错反推哪层)。
一张决策图:
curl 报 "Could not resolve host" → DNS 层(第 3 节)
curl 报 "Connection refused" → TCP 层,端口没监听(第 4 节)
curl 报 "Connection timed out" → 路由/防火墙(第 2、5 节)
curl 报 TLS 错误 → 证书/时间(第 6 节)
curl 卡住无响应 → 抓包看包到没到(第 5 节)
记忆:排障先定义"源→目的→端口",再分层证伪——报错信息本身就指明了哪一层。
2. 连通性:ping、mtr 与 traceroute
ping 是最基础的 ICMP 探测:
ping -c 4 example.com # 发 4 个包
ping -i 0.2 -c 100 host # 间隔 0.2s 发 100 个
ping -s 1400 -M do host # 探测 MTU(不分片)
ping 通了不代表服务可用:ICMP 可能被放行而 TCP 端口被封;ping 不通也不代表服务不可用(很多云环境禁 ICMP)。所以 ping 只用来判断"IP 层可达性",不是服务可用性。
mtr = ping + traceroute 的持续版,逐跳看丢包与延迟,是排障首选:
mtr -rwzc 100 example.com # -r 报告 -w 宽输出 -z ASN -c 100 次
mtr -t -P 443 example.com # TCP 模式(穿透只放行 443 的防火墙)
mtr 输出关键看两列:Loss%(丢包率)与 Avg(平均延迟)。中间跳丢包但后续跳不丢,通常是该跳路由器不响应 ICMP(限速),不是真丢包——只有"最后一跳丢包"才是真问题。
解读 mtr:
第 3 跳 Loss 20%,第 4 跳起 Loss 0% → 第 3 跳限速 ICMP,非真丢包
最后一跳 Loss 5% → 真丢包,网络问题
延迟逐跳 +5ms → 正常累积
某跳延迟突然 +200ms → 该跳有拥塞/绕路
traceroute 显示路径:
traceroute -T -p 443 example.com # TCP 模式(默认 UDP 常被拦)
traceroute -I example.com # ICMP 模式
常见结论:路径在某一跳后中断 → 该处有防火墙/路由黑洞;路径绕远 → BGP 路由问题(找云厂商)。
记忆:ping 只证 IP 层可达(不通≠服务不可用)、mtr 逐跳看丢包延迟、中间跳丢包≠真丢包(限速 ICMP),只有末跳丢才是问题。
3. DNS 诊断:dig、host 与解析链路
DNS 是"连不上"的头号嫌疑。dig 是最完整的诊断工具:
dig example.com # 默认 A 记录
dig example.com +short # 只出结果
dig example.com AAAA # IPv6
dig example.com MX # 邮件
dig @8.8.8.8 example.com # 指定 DNS 服务器
dig +trace example.com # 从根开始逐级追踪
dig +norecurse @a.gtld-servers.net example.com # 问权威
关键字段:
| 字段 | 含义 |
|---|---|
status: NOERROR | 解析成功 |
status: NXDOMAIN | 域名不存在 |
status: SERVFAIL | 服务器解析失败(上游问题) |
ANSWER SECTION | 结果记录 |
TTL | 缓存存活时间 |
flags: qr rd ra | 响应、递归、可用递归 |
排查顺序:先 dig +short 看有无结果;没有则 dig @8.8.8.8 换个 DNS 对比(有则本地 DNS 问题,没有则域名/权威问题);有结果但连不上说明不是 DNS,去 TCP 层;怀疑缓存用 dig +trace 看真实解析链;内网域名检查 search domain 与 /etc/hosts。
/etc/hosts 优先级:/etc/nsswitch.conf 决定查询顺序,通常 files dns——hosts 文件优先于 DNS,本地调试常改这里。
cat /etc/resolv.conf # 看用了哪些 DNS 服务器
cat /etc/nsswitch.conf | grep hosts # 看解析顺序
getent hosts example.com # 按系统实际顺序解析(比 dig 更贴近应用行为)
getent 比 dig 更准:dig 只问 DNS,getent hosts 走完整的 nsswitch 链路(含 hosts 文件、mDNS)——应用实际用的就是 getent 的路径。
记忆:连不上先查 DNS——dig +short 看结果、@8.8.8.8 对比、+trace 追链路;getent hosts 才反映应用的真实解析路径。
4. 端口与连接:ss、netstat 与 lsof
确认"服务到底有没有在听":
ss -tlnp # TCP 监听端口 + 进程(-t TCP -l listen -n 数字 -p 进程)
ss -tlnp 'sport = :8080' # 只看 8080
ss -tanp # 所有 TCP 连接(含 ESTABLISHED)
ss -s # 汇总统计
ss 已取代 netstat(更快、信息更全)。netstat 仍可用但需 net-tools 包:
netstat -tlnp # 同 ss -tlnp
netstat -an | grep 8080
常见状态解读:
| 状态 | 含义 |
|---|---|
| LISTEN | 在监听(服务已起) |
| ESTABLISHED | 已连接 |
| TIME_WAIT | 主动关闭后等待(正常,量大说明短连接多) |
| CLOSE_WAIT | 被动关闭未处理(应用 bug:没 close) |
| SYN_RECV | 收到 SYN 未完成握手(可能 SYN flood 或半开) |
| FIN_WAIT2 | 等对端 FIN |
CLOSE_WAIT 堆积是经典事故:说明应用收到 FIN 后没调用 close()——连接泄漏。TIME_WAIT 堆积则是短连接过多,可调内核参数或改用连接池。
# 统计各状态连接数
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn
lsof 查"哪个进程占了端口":
lsof -i :8080 # 谁在用 8080
lsof -i -P -n | grep LISTEN # 所有监听
lsof -p 12345 # 某进程打开的所有文件/连接
nc(netcat)测端口连通性(比 telnet 更可靠):
nc -zv host 443 # 测 TCP 443 通不通
nc -zvu host 53 # 测 UDP 53
nc -l 8080 # 本地监听测试
判断"连不上"是网络还是服务:nc -zv 通 → 服务在,问题在应用层;不通 → 端口没监听或被防火墙拦。
记忆:ss -tlnp 看监听、ss -tanp 看连接——CLOSE_WAIT 堆积是应用没 close 的 bug,TIME_WAIT 多是短连接太多。
5. 抓包:tcpdump 与 tshark
抓包是"看真相"的终极手段——日志会说谎,包不会。
sudo tcpdump -i eth0 -nn port 443 # 抓 443
sudo tcpdump -i any -nn host 10.0.0.5 and port 8080 # 指定主机+端口
sudo tcpdump -i eth0 -nn -w /tmp/cap.pcap port 443 # 写文件供分析
sudo tcpdump -i eth0 -nn -A port 80 | grep -i host # 看 ASCII 内容
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-syn != 0' # 只看 SYN
关键参数:
| 参数 | 含义 |
|---|---|
-i any | 所有网卡 |
-nn | 不解析主机名/端口名(快、准) |
-w file | 写 pcap 文件 |
-r file | 读 pcap 文件 |
-c N | 抓 N 个包后停 |
-s 0 | 抓完整包(不截断) |
-A / -X | ASCII / hex+ASCII 显示 |
BPF 过滤表达式(抓包前过滤,省资源):
host 10.0.0.5 # 某主机
net 10.0.0.0/24 # 某网段
port 443 # 某端口
src port 53 or dst port 53 # DNS
tcp and not port 22 # 排除 SSH
tcp[tcpflags] & (tcp-syn) != 0 # 只看 SYN
三大经典抓包结论:
1. 只看到 SYN、没有 SYN-ACK → 对端没响应/被防火墙丢(连接超时)
2. 看到 SYN、回 RST → 对端端口没监听(连接拒绝)
3. 看到 SYN、SYN-ACK,无 ACK → 客户端没完成握手(客户端侧问题)
tshark(Wireshark 命令行版)做深度分析:
tshark -r cap.pcap -Y 'http.request' -T fields -e http.host -e http.request.uri
tshark -r cap.pcap -z io,phs # 协议分层统计
tshark -r cap.pcap -Y 'tcp.analysis.retransmission' # 只看重传
抓包权限与性能:需要 CAP_NET_RAW(root 或 capability);高流量下 -w 直接落盘比 -A 打印快得多;生产抓包务必加过滤 + 限包数 + 落盘,别把磁盘写满。
记忆:抓包看真相——SYN 无响应是超时、回 RST 是端口没开、无 ACK 是客户端问题;生产抓包必加过滤、限包数、落盘。
6. HTTP 调试:curl 与 wrk
curl 是应用层的瑞士军刀,-v 看全流程:
curl -v https://example.com # 完整握手 + 请求响应
curl -v --trace-time https://example.com # 带时间戳
curl -o /dev/null -s -w 'dns=%{time_namelookup} conn=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total}\n' https://example.com
-w 的时间分解是定位"慢在哪层"的关键:
time_namelookup DNS 耗时
time_connect TCP 握手耗时(= connect - namelookup)
time_appconnect TLS 握手耗时(= appconnect - connect)
time_starttransfer 首字节 TTFB(= starttransfer - appconnect,含服务处理)
time_total 总耗时
诊断套路:DNS 占比高 → 查 DNS;connect 高 → 网络/路由;appconnect 高 → TLS/证书;TTFB 高 → 服务端处理慢。常用附加参数:curl -k(跳过证书校验,仅调试)、curl --resolve example.com:443:1.2.3.4(强制指定 IP,绕过 DNS 排障神器)、curl -x http://proxy:8080(走代理)、curl --http2 -v(强制 HTTP/2)。
TLS 诊断用 openssl:
openssl s_client -connect example.com:443 -servername example.com
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
看证书有效期、链、SNI 是否正确——证书过期是"突然连不上"的高频原因。
wrk 做压测:
wrk -t4 -c100 -d30s https://example.com # 4 线程 100 连接 30 秒
wrk -t4 -c100 -d30s --latency https://example.com # 带延迟分布
看 Requests/sec、延迟分位(p50/p99)——注意压测机自身的网络与 CPU 别成瓶颈。
记忆:curl -w 的时间分解定位慢在哪层(DNS/TCP/TLS/TTFB);–resolve 绕过 DNS、openssl s_client 查证书、wrk 看吞吐延迟分布。
7. 延迟与丢包定位
延迟高 vs 丢包是两类问题:
延迟高 → 路径绕远、拥塞、处理慢
丢包 → 链路质量、拥塞丢包、缓冲区溢出
定位流程:
1. mtr 逐跳:定位延迟/丢包出现在哪一跳
2. 末跳丢包 → 目标侧或最后一段链路
3. 中间跳丢包但后续正常 → ICMP 限速,忽略
4. 延迟抖动大 → 拥塞,看是否有队列/带宽瓶颈
5. 应用延迟高但网络正常 → 回到应用层(curl -w TTFB)
TCP 层面的延迟线索(tshark):tcp.analysis.retransmission 是重传(丢包信号)、tcp.analysis.zero_window 是零窗口(接收方处理不过来)、-z io,stat,1 看每秒流量。重传 = 丢包;零窗口 = 应用读得慢(接收缓冲满);窗口小 = 带宽延迟积利用不足。
延迟的物理下限:光速。跨太平洋单程约 60–80ms,任何"跨洋 RTT < 100ms"的承诺都要怀疑。CDN/边缘节点就是把内容搬到离用户近的地方。
记忆:mtr 定位延迟/丢包在哪一跳(中间跳丢包多为限速)、tshark 看重传/零窗口——重传是丢包、零窗口是应用读得慢,延迟有光速下限。
8. 带宽与吞吐测量
带宽测量:
iperf3 -s # 服务端
iperf3 -c server -t 30 # 客户端,30 秒
iperf3 -c server -u -b 100M # UDP 100Mbps
iperf3 -c server -P 4 # 4 条并行流
iperf3 的结果才是"链路真实带宽"——比用 curl 下大文件准(排除磁盘/应用影响)。
注意:单条 TCP 流的吞吐受**带宽延迟积(BDP)**限制:
吞吐上限 ≈ 窗口大小 / RTT
例:窗口 64KB、RTT 100ms → 64KB/0.1s ≈ 5.2Mbps(远低于链路带宽)
解决:调大窗口(net.ipv4.tcp_rmem/wmem)或开 BBR 拥塞控制
所以"千兆链路单流只跑 5Mbps"是正常的——需要并行流或调窗口。
测速别用错工具:链路带宽用 iperf3、HTTP 吞吐用 wrk/ab、下载速度用 curl + 大文件、磁盘 vs 网络瓶颈用 dd + 管道。
本地带宽验证:ip -s link 看网卡计数(RX/TX bytes、errors、dropped)——errors/dropped 非零说明链路或缓冲有问题;ethtool eth0 | grep -i speed 看协商速率。
记忆:iperf3 测链路带宽、单流吞吐受 BDP 限制(窗口/RTT)、网卡 errors/dropped 非零是链路信号。
9. 典型故障的排障剧本
剧本 A:服务连不上——curl -v 看报错类型;Could not resolve 查 DNS(dig/getent);Connection refused 用 ss -tlnp 看服务起没起;Connection timed out 用 mtr 看路径、nc -zv 测端口;TLS 错误用 openssl s_client 看证书/时间;卡住无响应用 tcpdump 看包到没到、有没有回。
剧本 B:服务变慢——curl -w 时间分解定位 DNS/TCP/TLS/TTFB 哪层慢;TTFB 高是应用层(查日志、DB、下游);connect 高用 mtr 看网络路径;偶发慢用 tcpdump/tshark 看重传、零窗口;全站慢查负载均衡/网关/DNS。
剧本 C:间歇性失败——先确认"间歇"的规律(时间点?特定客户端?特定后端?);ss -s 看连接状态分布(TIME_WAIT/CLOSE_WAIT 堆积?);抓包对比"成功"与"失败"请求的差异;多后端时用 curl --resolve 逐个直连测试;最后查负载均衡健康检查与超时配置。
剧本 D:DNS 相关——getent hosts 看应用实际解析结果;dig @8.8.8.8 对比判断是否本地 DNS 问题;dig +trace 查权威链路;检查 /etc/resolv.conf、search domain、/etc/hosts;容器环境检查容器 DNS(127.0.0.11 / CoreDNS)。
通用原则:先复现、再缩小范围、后定位;每次只改一个变量;记录时间点(便于对齐多机日志)。
记忆:排障剧本=复现→缩小→定位——先看报错类型定层,再逐层证伪;多后端逐个直连、成功/失败对比抓包、每次只改一个变量。
10. 速查表与一句话记忆
全篇速查:
| 层 | 命令 | 看什么 |
|---|---|---|
| IP 可达 | ping、mtr -rwzc 100 | 丢包率、逐跳延迟 |
| 路径 | traceroute -T -p 443 | 在哪跳中断 |
| DNS | dig +short、dig @8.8.8.8、getent hosts | 解析结果、真实链路 |
| 监听 | ss -tlnp | 端口开没开、哪个进程 |
| 连接 | ss -tanp、ss -s | 状态分布、CLOSE_WAIT |
| 端口通断 | nc -zv host 443 | 通不通 |
| 抓包 | tcpdump -i any -nn port X | SYN/RST/重传 |
| 深度分析 | tshark -Y、-z io,phs | 重传、零窗口 |
| HTTP | curl -v -w | 各阶段耗时 |
| TLS | openssl s_client | 证书、链、时间 |
| 带宽 | iperf3 -c | 链路真实带宽 |
| 压测 | wrk -t4 -c100 -d30s --latency | QPS、延迟分位 |
一句话记忆:网络排障先定义"源→目的→端口",再分层证伪——ping/mtr 证 IP 层(中间跳丢包多为 ICMP 限速,只有末跳丢才是问题)、dig/getent 证 DNS(getent 才反映应用真实路径)、ss -tlnp 证监听(CLOSE_WAIT 堆积是应用没 close 的 bug)、nc -zv 证端口、tcpdump 看真相(SYN 无响应是超时、回 RST 是端口没开、无 ACK 是客户端问题)、curl -w 时间分解定位应用层慢在哪(DNS/TCP/TLS/TTFB);报错信息本身就指明哪一层——先复现、再缩小、后定位,每次只改一个变量。
延伸阅读
- curl 与 HTTP 调试实战
- HTTP 状态码与请求语义速查
- 终端与 Shell 生态进阶:zsh、tmux 与高效命令行工作流
- 网络专题 — TCP/IP 协议栈与网络原理
- Linux 专题 — 内核网络参数与系统调优
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。