LabHub
学习 学习路径 课程

网络排障

把「连不上」这条报障拆成四层

在 LabHub 中继续学习

一句话总结

网络故障诊断中,90% 的问题都可以通过**先确定“故障停在哪一层”**来解决。不先判断层次就打开各种工具,只会让时间白白流逝。

分层图: 先确定“故障停在哪一层” · 先确定故障所在的层次 · 关键在于,每一层的故障都有不同的表现。 · 返回了 RST

为什么需要分层诊断

接到“API 连不上”的报障后,人们通常会这样做:先 ping,再打开防火墙规则,然后检查 DNS,接着翻找应用程序日志。整个过程没有顺序,因此,同一个地方会检查两遍,而漏掉的地方始终没有人看。

经验丰富的人采用不同的方法:先确定故障所在的层次,然后只使用与该层对应的一种工具。

它是如何工作的

实际工作中无需套用完整的 OSI 七层模型,下面四层就足够了。

层次 问题 检查工具 失败时的表现
名称 这个名称会解析成哪个 IP getent hostsdigresolvectl query Name or service not known
可达性 数据包能否到达该 IP pingtraceroute -Uip route Network is unreachable、无响应
端口 该 IP 上的指定端口是否开放 nc -zvss -ltncurl --connect-timeout Connection refused / timed out
响应 端口开放后,响应是否异常 curl -vcurl -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/hostsnsswitch.conf 的检查顺序先于 dig,以及为什么 dig 完全不会读取这两个文件。