网络心智模型:分层、路由、连接、DNS、TLS 与按层验证

一句话模型

网络故障要按层验证:先用证据确认请求走到了哪一层,再判断是解析、路由、连接、握手还是应用的问题,而不是从应用日志猜。

核心概念

1. 分层与封装

网络按 L2 链路、L3 网络、L4 传输、L7 应用分层,每层把上层数据加上自己的头部再交给下层。以太网帧有 MAC,IP 包有源和目的地址,TCP/UDP 有端口和校验和,HTTP/TLS 有方法和证书。分层的价值是每层可以独立实现和替换,排障时也可以逐层取证。

边界在于分层是模型,不是现实。NAT 会改写地址和端口,隧道会再包一层,负载均衡会终止连接,MTU 会让大包在小包能通过时被丢弃。所谓“三层问题”和“七层问题”经常互相伪装:L7 的 502 可能来自 L4 连接被重置,L4 的超时可能来自 DNS。

失败时的表现是症状出现在错误的层:应用报“请求超时”,实际是 DNS 解析慢;Ingress 报 502,实际是后端端口没监听;TLS 握手失败,实际是证书链缺中间证书。排障的第一步是确认当前证据属于哪一层。

2. IP、路由与寻址

IP 负责端到端的逻辑寻址,路由表决定下一跳。Linux 用最长前缀匹配选择路由,直连网段通过 ARP(IPv4)或 NDP(IPv6)解析 MAC,非直连流量发给网关。策略路由、多张路由表、VRF 和容器网络会让“默认路由”不再是唯一答案。

边界在于:能路由不等于能到达。防火墙、安全组、网络策略、反向路径过滤和不对称路由都可能在转发路径上丢包;ARP 冲突、邻居表项过期和网关不可达会表现为间歇性中断。IPv6 还引入了 RA、NDP 和双栈优先级问题。

失败时的表现是 Network is unreachable、No route to host、ARP 冲突告警、跨网段单向通,以及只有某个源地址或某个节点访问失败。用 ip route get、ip neigh、traceroute 和抓包确认路径,比反复重启网络服务有效。

3. 端口与连接

一个 TCP 连接由源 IP、源端口、目的 IP、目的端口四元组唯一标识。服务端在地址和端口上 listen,内核维护 accept 队列;客户端从临时端口范围选择源端口。ss 读的是内核 socket 表,能看到 LISTEN、ESTABLISHED、TIME_WAIT 等状态和收发队列。

边界在于:端口开放不等于服务可用。监听在 127.0.0.1 的服务外部访问不到;backlog 满会拒绝或丢弃新连接;NAT 和连接跟踪会消耗端口与表项;大量短连接会把临时端口耗在 TIME_WAIT。容器和 Pod 还有独立的网络命名空间,宿主机上看到的结果不一定代表容器内。

失败时的表现是 Connection refused(收到 RST,通常是没有监听或被策略拒绝)、Connection timed out(没有回包,可能是丢包、路由或防火墙)、Address already in use(端口被占用),以及连接数上涨但吞吐不涨。refused 和 timeout 是不同证据,不能混为一谈。

4. DNS

DNS 把名字解析成地址。解析器先看 /etc/hosts 和 nsswitch.conf,再按 /etc/resolv.conf 里的 nameserver、search 域和 ndots 发起查询;递归解析器负责 Root、TLD 和权威服务器的查询,并按 TTL 缓存。Kubernetes 里 CoreDNS 提供集群内名字解析,Service 名字和 Headless Service 的返回行为不同。

边界在于:DNS 只解决“名字到地址”,不保证地址可达。解析成功但端口不通、解析到旧 IP、search 域拼接出意外名字、ndots 导致先查集群域再查外部域,都是常见问题。UDP 响应超过 512 字节或截断时会转 TCP,防火墙只放行 UDP 就会表现为间歇失败。

失败时的表现是 Name or service not known、Temporary failure in name resolution、解析耗时高、不同节点解析结果不同,以及应用启动时正常、运行一段时间后失败(缓存或连接池)。用 dig、getent hosts、resolvectl 分别验证解析器和 NSS 路径。

5. TCP 状态机

TCP 通过三次握手建立连接、序列号和确认保证可靠传输、滑动窗口做流控、拥塞控制适应网络。关闭连接有 FIN 四次挥手,主动关闭方进入 TIME_WAIT;异常情况用 RST 立即终止。重传、乱序、重复确认和零窗口都是状态机的正常输出。

边界在于:TCP 的“可靠”只保证数据最终按序交付,不保证低延迟。丢包会触发重传,表现为延迟升高而不是应用报错;中间设备可能改写超时、丢弃空闲连接或拦截 RST;keepalive 的默认时间通常远长于应用的超时。SYN 队列、accept 队列和 conntrack 表满,都会在握手阶段失败。

失败时的表现是连接超时、重传率高、connection reset by peer、大量 TIME_WAIT 或 SYN_RECV,以及“小请求正常、大请求卡住”。用 ss -ti、nstat、tcpdump 和内核计数器确认是丢包、重传、队列还是对端关闭。

6. TLS

TLS 在 TCP 之上提供加密、身份认证和完整性。握手阶段协商版本和密码套件、验证证书链、交换密钥;SNI 让一个 IP 承载多个域名;ALPN 协商 HTTP/2 等协议。mTLS 还要求客户端提供证书。证书链、信任库、主机名和有效期共同决定握手是否成功。

边界在于:TLS 失败经常伪装成网络失败。证书过期、缺少中间证书、主机名不匹配、客户端不信任私有 CA、系统时间偏差、协议版本或密码套件不兼容,都会让连接在握手阶段断开。反向代理终止 TLS 时,后端看到的是明文,问题可能出在代理到后端的第二段连接。

失败时的表现是 certificate has expired、unable to get local issuer certificate、handshake failure、protocol version 错误,或者浏览器报错但 curl -k 正常。用 openssl s_client -connect host:443 -servername host 看完整证书链和握手结果。

7. NAT、MTU 与 K8s 网络

NAT 通过改写地址和端口让私有网络访问外部,连接跟踪(conntrack)记录五元组映射;MTU 决定单个帧能承载的最大 IP 包,隧道和 overlay 会额外消耗头部。Kubernetes 中 CNI 负责给 Pod 分配地址和配置路由,Service 通过 iptables/IPVS/eBPF 做虚拟 IP 转发,NetworkPolicy 在数据面实现隔离。

边界在于:这三者经常联合制造“偶发、单向、只影响大包”的故障。NAT 端口耗尽会让新连接失败;conntrack 表满会丢弃新流;MTU 不匹配会让握手和小请求正常、大响应卡死(PMTUD 被黑洞时尤其隐蔽)。跨节点 Pod 通信还依赖隧道、路由和防火墙的正确配合。

失败时的表现是 nf_conntrack: table full、NAT 源端口耗尽、跨节点访问偶发超时、ping 小包正常但大包失败、Service 访问时通时不通。排查要同时看 conntrack 使用量、Pod 与节点的 MTU、CNI 路由和 Service 后端。

概念关系

组件 读什么 写什么 失败后的现象
应用与 socket 域名、四元组 请求数据、连接状态 超时、连接被重置
DNS 名字、search 域、ndots A/AAAA/SRV 记录 解析失败、解析到旧地址
路由与邻居 目的 IP、路由表 下一跳、ARP/NDP 表项 无路由、ARP 冲突、单向通
TCP 序列号、窗口、确认 重传、状态迁移 超时、重传、RST
NAT 与 conntrack 五元组 地址端口映射、表项 端口耗尽、表满丢包
TLS 证书链、SNI、ALPN 会话密钥 握手失败、证书错误
CNI 与 Service Pod IP、Endpoint veth、路由、转发规则 跨节点不通、Service 偶发超时
负载均衡与 Ingress Host、路径、后端 转发与连接复用 502、504、503

请求从应用 socket 出发,先经过 DNS 得到地址,再由路由和邻居找到下一跳,通过 TCP 建立连接,可能穿过 NAT、隧道和负载均衡,最后完成 TLS 握手并进入应用。每一层都有独立的失败模式和证据,按层验证比从日志猜更快。

常见误解

读完自测

合上页面,先回答,再展开对照。

  1. curl 报连接超时,如何按层缩小范围?先看哪些证据?
  2. 为什么 ping 通但 curl 仍然超时?至少举两个机制。
  3. Kubernetes 中 Pod 访问 Service 偶发超时,MTU 和 conntrack 各会表现成什么?
答案
  1. 先用 getent hosts 或 dig 确认 DNS,再用 ip route get 和 ping 确认路由与可达性,用 ss 看连接状态和队列,用 curl -v 区分 TCP、TLS 和 HTTP 阶段,必要时在两端 tcpdump 看 SYN、重传和 RST。
  2. 可能 ICMP 被放行但目标端口被防火墙拒绝或丢弃;可能 DNS 解析慢导致整体超时;也可能 MTU 黑洞让握手小包通过而后续大包丢失;还可能是 TLS 握手或代理层失败。
  3. MTU 问题通常表现为小请求正常、大响应卡住或 TLS 握手后传输停滞,且常跨节点出现;conntrack 表满或 NAT 端口耗尽表现为新连接随机失败、已有连接可能仍正常,内核日志会出现 table full 或插入失败计数。

相关条目