把「连不上」这条报障拆成四层
一句话总结
网络故障诊断的 90%,先确定“卡在哪一层” 就解决了。不先确定层就打开工具,只会白白浪费时间。
为什么需要这个
接到“API 连不上”的报告时,人们通常会这样做:ping 一下,打开防火墙规则看看,检查 DNS,翻应用日志。没有顺序。结果同一个地方看了两遍,没看过的地方一直没看。
熟练的人做法不同。先锁定层,然后只用适合那一层的一个工具。
工作原理
实际工作中用到的层不必是 OSI 七层,四层就足够了。
| 层 | 问题 | 检查工具 | 失败时的样子 |
|---|---|---|---|
| 名称 | 这个名称解析成哪个 IP | getent hosts, dig, resolvectl query |
Name or service not known |
| 可达 | 数据包能否到达那个 IP | ping, traceroute -U, ip route |
Network is unreachable、无响应 |
| 端口 | 那个 IP 的那个端口是否开放 | nc -zv, ss -ltn, curl --connect-timeout |
Connection refused / timed out |
| 响应 | 端口开着,但回答不对劲 | curl -v, curl -w、应用日志 |
5xx、缓慢、响应体错误 |
关键在于:每一层的失败都有各自不同的样子。 只要准确读出这个样子,层就确定了。
记住下面这张按 errno 区分的判别表,光看报告里的那句话就能分出层。
| 消息 | errno | 实际发生了什么 | 先看哪里 |
|---|---|---|---|
Name or service not known |
EAI_NONAME | 名称解析失败,连套接字都没打开 | nsswitch.conf、resolv.conf、/etc/hosts |
Network is unreachable |
ENETUNREACH | 路由表中没有路径 | ip route,尤其是 IPv6 路由 |
No route to host |
EHOSTUNREACH | 收到 ICMP unreachable 或 ARP 无响应 | 目标主机电源、ARP、REJECT 规则 |
Connection refused |
ECONNREFUSED | 目标返回了 RST | 目标主机上的进程及其绑定地址 |
Connection timed out |
ETIMEDOUT | SYN 重传全部用完仍无响应 | 防火墙 DROP、安全组、accept 队列 |
这里最常见的错误是把 refused 归咎于防火墙。refused 表示收到了 RST;既然收到了 RST,就证明数据包已经通过了路由、安全组、NAT 和网络策略。实际环境中的防火墙几乎总是 DROP 策略,被拦的端口会表现为 timeout。看到 refused 却去翻防火墙,等于重新检查一道已经通过的关卡。
时间也是证据。在 Linux 默认值(net.ipv4.tcp_syn_retries=6)下,无响应的连接会在 1+2+4+8+16+32+64 = 127 秒后放弃。如果应用的超时写的是 30 秒,实际却在 127 秒后才失败,就说明这个超时设置没有生效。
在现场遇到的样子
“本地可以,只有远程不行。” 十有八九是绑定地址的问题。如果 ss -ltnp 显示在 127.0.0.1:8080 上监听,那么发往 Pod IP 的连接会被内核用 RST 拒绝——也就是 refused。反过来,如果连 Pod IP 也是 timeout,这时才开始查网络策略。这一次分岔就能把排查范围缩小一半。
下一步要做的事
从最底层的名称解析开始。亲手确认 /etc/hosts 和 nsswitch.conf 为什么优先于 dig,以及为什么 dig 完全不看这两者。