network - troubleshooting
12. 网络排障
0. 本章先解决什么问题
网络问题最容易被一句话糊弄过去:
网络不通。
网络慢。
服务挂了。
这些说法都太粗。真正排障时,需要把一次通信拆成层次、阶段、证据和假设。
本章要建立一个可复用的方法:
先定位失败阶段
再映射到协议层
再收集最小证据
最后验证假设
学完以后,你应该能把“访问不了”“超时”“偶发慢”“连接被重置”“只有某些用户失败”拆成可以逐步检查的问题。
这张图怎么读
这张图把“网络慢”拆成可观察的阶段:DNS、TCP、TLS、请求发送、服务处理、首字节、响应下载。排障时不要先争论原因,先拿到每段耗时,慢在哪一段,问题空间就会立刻缩小。
1. 第一原则:先问失败发生在哪个阶段
一次典型 HTTPS 请求可以拆成:
- 构造 URL
- DNS 解析
- 路由选择
- ARP/下一跳交付
- TCP 连接
- TLS 握手
- HTTP 请求发送
- 服务处理
- HTTP 响应返回
- 连接复用或关闭
每个阶段失败,应用看到的现象不同。
| 阶段 | 常见现象 |
|---|---|
| DNS | 域名解析失败、解析慢、解析到旧 IP |
| 路由/链路 | 目标不可达、丢包、跨网段不通 |
| TCP | refused、connect timeout、reset |
| TLS | 证书错误、握手失败、协议不兼容 |
| HTTP | 4xx、5xx、重定向、缓存异常 |
| 应用处理 | 首字节慢、业务错误、响应体异常 |
| 连接管理 | 空闲断开、CLOSE_WAIT、TIME_WAIT、连接池耗尽 |
排障第一步不是猜原因,而是定位阶段。
2. 第二原则:区分“可达”和“可用”
不同测试证明不同层次:
| 测试 | 证明什么 | 不证明什么 |
|---|---|---|
| ping 通 | 某种 ICMP 路径可达 | 目标端口开放、应用可用 |
| TCP 端口能连 | 传输层入口可达 | HTTP/TLS/业务正确 |
| TLS 握手成功 | 安全通道能建立 | 应用返回正确 |
| HTTP 200 | 应用返回成功状态 | 内容一定符合预期 |
| 业务数据正确 | 整条链路当前可用 | 未来不会抖动 |
“能 ping 通但不能访问服务”并不矛盾;“端口能连但请求失败”也不矛盾。
3. 第三原则:同一环境测试
很多排障误判来自测试环境不一致。
你在宿主机测试
程序在容器里运行
你在公司网络测试
用户在家庭网络访问
你用命令行测试域名
程序使用内部 DNS 缓存
你访问公网入口
服务内部调用走私有网络
所以要明确:
| 问题 | 为什么重要 |
|---|---|
| 请求从哪里发起 | 路由、DNS、NAT、防火墙都可能不同 |
| 使用哪个域名/IP | 解析结果和入口层可能不同 |
| 经过哪些代理 | Header、超时、缓存、错误码可能被改变 |
| 使用什么协议版本 | HTTP/1.1、HTTP/2、HTTP/3 行为不同 |
| 手动测试和程序是否同环境 | 否则证据不能直接替代 |
4. 常用证据工具怎么理解
这里不强调命令细节,而强调每类工具提供什么证据。
| 工具类型 | 看到什么 | 用途 |
|---|---|---|
| DNS 查询工具 | 域名解析记录、TTL、解析器结果 | 判断域名是否解析正确 |
| ping | ICMP 往返和丢包 | 粗略看网络层可达性 |
| traceroute/tracert | 路径上的部分跳点 | 判断大致路径和中途异常 |
| TCP 连接测试 | 端口是否能建立连接 | 判断服务入口是否可连 |
| HTTP 客户端 | 状态码、Header、阶段耗时 | 看应用协议行为 |
| netstat/ss | 本机连接状态 | 看 LISTEN、ESTABLISHED、TIME_WAIT、CLOSE_WAIT |
| 抓包工具 | 实际包序列 | 验证 SYN、ACK、重传、RST、TLS 握手 |
| 日志/指标/追踪 | 系统内部行为 | 定位应用、网关、上游耗时 |
工具不是越多越好。每次只问:我现在需要证明哪一个假设?
5. 超时要分类
“timeout”不是一种原因,而是一类结果。常见超时:
| 超时类型 | 含义 | 方向 |
|---|---|---|
| DNS timeout | 等不到解析结果 | DNS 服务器、网络、配置 |
| connect timeout | TCP 握手没完成 | 路由、防火墙、目标不可达、SYN 丢失 |
| TLS handshake timeout | 安全通道没建立 | 证书协商、协议、网络、中间设备 |
| read timeout | 连接已建立但读不到响应 | 服务处理慢、响应丢失、上游慢 |
| write timeout | 数据写不出去或对端不读 | 发送阻塞、接收方慢、连接异常 |
| idle timeout | 空闲连接被关闭 | NAT、代理、网关、连接池策略 |
| request timeout | 整体请求超过上限 | 可能包含多个阶段 |
排障时要把整体超时拆成阶段耗时。否则会把服务处理慢误判成网络不通,或把握手失败误判成应用错误。
6. 错误现象映射表
| 现象 | 常见方向 |
|---|---|
| 域名不存在 | DNS 记录、拼写、区域配置 |
| 解析到错误 IP | 缓存、TTL、CNAME、不同解析器 |
| Connection refused | 目标端口无监听、服务未启动、策略拒绝 |
| connect timeout | 路由、防火墙、目标不可达、SYN 被丢 |
| reset by peer | 对端主动 RST、协议不匹配、连接被中间设备关闭 |
| broken pipe | 本端继续写已关闭连接 |
| 400 | 请求格式、参数、Header 错 |
| 401/403 | 认证或权限问题 |
| 404 | 路由、路径、资源不存在 |
| 429 | 限流 |
| 502 | 代理到上游异常 |
| 503 | 无可用实例、过载、维护 |
| 504 | 网关等上游超时 |
| 响应旧内容 | HTTP/CDN/浏览器缓存 |
| 偶发慢 | 丢包、重试、队列、连接池、上游抖动 |
这张表只给初始方向,不能替代证据。下一步必须验证。
7. 抓包时看什么
抓包的价值是看到真实网络事件,而不是应用加工后的错误。
7.1 TCP 建连
正常三次握手:
SYN ->
<- SYN, ACK
ACK ->
如果只有:
SYN ->
SYN ->
SYN ->
说明 SYN 没得到有效响应,方向可能是目标不可达、防火墙丢弃、中间路径问题。
如果看到:
SYN ->
<- RST
常见含义是目标端口拒绝连接。
7.2 数据传输
关注:
是否有大量 Retransmission
ACK 是否正常增长
窗口是否很小
是否出现 Zero Window
是否有 RST
这些能帮助区分:
网络丢包
接收方读慢
对端主动断开
中间设备异常
7.3 TLS 和 HTTP
如果 TLS 握手前就失败,应用层 HTTP 不会出现。
如果 TLS 成功后 HTTP 返回 5xx,说明请求至少已经进入应用协议链路。
抓包时要尊重边界:
TLS 加密后,抓包能看到连接和握手元数据;
HTTP 明文内容通常看不到,除非在终止 TLS 的节点观察。
8. 慢请求分析:延迟、吞吐、丢包、排队
慢不一定是带宽不足。
| 概念 | 含义 | 常见表现 |
|---|---|---|
| 延迟 | 单次往返需要多久 | 首次响应慢、交互慢 |
| 吞吐 | 单位时间传多少数据 | 下载/上传慢 |
| 丢包 | 包没有到达 | 重传、窗口下降、抖动 |
| 抖动 | 延迟波动大 | 实时体验不稳定 |
| 排队 | 中间设备或应用排队 | 延迟突然升高 |
| 队头阻塞 | 前面缺口阻塞后续交付 | 某些流量被拖住 |
慢请求拆解:
DNS time
connect time
TLS time
request send time
server processing time
time to first byte
content download time
如果首字节之前慢,优先看连接、握手、服务处理、上游依赖。
如果首字节之后慢,优先看响应体大小、吞吐、丢包、窗口、客户端读取速度。
小实验:做一张最小请求瀑布表
选一个你能稳定访问的 HTTPS 地址,不急着抓包,先把一次请求拆成阶段记录:
| 阶段 | 你要记录什么 | 异常时的第一方向 |
|---|---|---|
| DNS | 解析结果、TTL、解析耗时 | DNS 配置、递归解析器、缓存 |
| TCP | connect 是否成功、耗时 | 路由、防火墙、端口监听、SYN 丢失 |
| TLS | 握手是否成功、证书信息 | 证书链、SNI、协议版本、套件 |
| HTTP send | 请求头/请求体是否发出 | 客户端阻塞、代理限制、连接异常 |
| First byte | 首字节等待多久 | 服务排队、上游依赖、网关等待 |
| Download | 响应体下载多久 | 带宽、丢包、窗口、客户端读取慢 |
做完这张表后,再写一句结论,要求禁止使用“网络慢”这种笼统词。合格结论应该像:
DNS/TCP/TLS 都在正常范围内,首字节等待从 80ms 升到 2.4s,优先查网关到上游服务的排队和应用处理耗时。
这个练习的价值是把 vague symptom 变成 phase-specific evidence。能做到这一步,排障已经比“猜一个原因试一下”稳很多。
反例:本机命令成功,不代表真实运行环境成功
排障时常有人说:
我在本机 curl 成功,所以网络没问题。
这个结论经常跳太远。一次请求是否成功,取决于发起环境:
| 差异 | 可能影响 |
|---|---|
| DNS 配置不同 | 解析到不同地址 |
| 出口 IP 不同 | 被目标白名单、限流或风控区别对待 |
| 代理配置不同 | 本机直连,运行环境走代理或网关 |
| 证书信任库不同 | 本机信任,运行环境不信任 |
| 协议版本不同 | 本机支持新 TLS/HTTP 版本,运行环境不支持 |
| 网络路径不同 | 本机可达,运行环境所在子网不可达 |
| 超时设置不同 | 命令默认等待更久,程序更早超时 |
| 请求头不同 | 目标按 Host、SNI、User-Agent、鉴权头路由 |
正确做法是让证据尽量贴近真实发起点:
在同一机器上测
在同一网络隔离环境里测
使用同一域名、端口、协议、SNI、Host、请求头
使用接近真实程序的超时和代理配置
对比 DNS/TCP/TLS/HTTP 每阶段结果
本机测试只能证明“本机这条路径成功”。它是有用证据,但不能替代真实运行环境的证据。
9. 建立排障记录
严肃排障要留下记录。否则多人协作时会反复问同样问题。
一份最小记录:
时间:
发起方:
目标域名/IP/端口:
协议:
错误信息:
是否可复现:
DNS 结果:
TCP 连接结果:
TLS 结果:
HTTP 状态码:
请求耗时分解:
相关日志:
已排除项:
下一步假设:
这不是形式主义。它能防止排障在“猜一个、试一下、忘了刚才试过什么”里打转。
10. 三个实际排障模板
10.1 访问不了某个域名
- 域名能否解析?
- 解析到哪个 IP?
- IP 是否符合预期?
- TCP 目标端口能否连接?
- TLS 是否握手成功?
- HTTP 是否有状态码?
- 错误是否只在某个网络环境出现?
10.2 偶发 504
- 504 由哪一层返回:CDN、网关、代理?
- 请求是否到达应用?
- 应用处理时间是否超过网关超时?
- 下游依赖是否慢?
- 是否有重试放大流量?
- 连接池是否耗尽?
- 超时配置是否层层递减且合理?
证据链模板:504 要先证明是哪一层等超时
504 的字面意思通常是“某个网关等待上游超时”,但关键是:
哪个网关?
等待哪个上游?
请求是否已经进入真正处理逻辑?
最小证据链可以这样写:
客户端:
status = 504
total = 31s
connect = 20ms
tls = 40ms
first_byte = 31s
入口层:
有请求记录
upstream_time = 30s
upstream_status = timeout
处理层:
是否存在同一 request id
如果存在,处理到哪一步
如果不存在,问题在入口到处理层之间
依赖层:
同时间段是否有连接池等待、队列堆积、慢调用
根据证据,504 至少可以分成几类:
| 证据形态 | 更可能的方向 |
|---|---|
| 客户端 connect/TLS 已快,TTFB 接近网关超时 | 中间层等待上游 |
| 入口层没有请求记录 | 请求没到入口,查 CDN/代理/路由 |
| 入口层有记录,处理层无记录 | 转发、负载均衡、连接池或队列 |
| 处理层有记录且耗时接近超时 | 处理逻辑或下游依赖慢 |
| 处理层很快完成,但入口仍 504 | 响应路径、连接复用、网关状态异常 |
看到 504 不要直接说“处理慢”。先找返回 504 的那一层,再证明它在等谁。
10.3 长连接空闲后第一次请求失败
- 中间 NAT/代理是否有 idle timeout?
- 客户端连接池是否复用了已被关闭的连接?
- 服务端是否主动回收空闲连接?
- 是否需要心跳或更短的空闲回收?
- 失败后重试是否安全?
这些模板的共同点是:先定位阶段,再验证机制。
11. 联系实际:从“网络慢”到可执行结论
假设有人说“今天系统很慢”。一个可执行的拆解方式是:
- 慢的是所有用户,还是某些地区/网络?
- 慢的是所有接口,还是某些路径?
- DNS、TCP、TLS、首字节、下载哪段变慢?
- 是否出现 5xx、重传、丢包、连接池耗尽?
- 入口层、应用层、下游依赖指标是否同时变化?
- 最近是否有 DNS、证书、网关、发布、缓存策略变更?
最后的结论应该长这样:
不是“网络慢”四个字,
而是“某地区用户解析到某 CDN 节点后,首字节等待升高;源站日志显示上游处理正常,CDN 回源连接耗时异常,已切换该区域调度并观察”。
结论越具体,下一步动作越清楚。
失败指纹表:网络症状到协议阶段
| 现象 | 首先定位的阶段 | 关键证据 | 常见下一步 |
|---|---|---|---|
| 域名偶尔解析到不同地址 | DNS 解析和缓存 | 解析结果、TTL、递归解析器、权威记录 | 对比不同网络/解析器,确认是否为缓存或调度策略 |
| 连接超时 | TCP 建连或路径可达 | SYN 重传、路由、丢包、防火墙记录 | 区分目标不可达、端口被拦、回程路径异常 |
| TLS 失败 | 证书、SNI、协议版本、信任链 | 证书链、域名匹配、有效期、TLS alert | 区分证书配置、客户端策略和中间层终止 |
| 首字节时间长 | 服务处理或上游排队 | TTFB、服务 trace、upstream 日志、队列长度 | 查源站、网关、负载均衡和应用处理 |
| 下载慢但 TTFB 正常 | 传输吞吐、拥塞、窗口、客户端接收 | throughput、重传、RTT、TCP window | 查链路质量、拥塞控制、接收端消费速度 |
| 只某些地区慢 | 路由、CDN、DNS 调度、运营商路径 | 分地区 traceroute、CDN 命中、解析结果 | 区分源站慢和边缘/路径慢 |
12. 学完本章你能解决什么问题
学完本章,你应该能:
- 把一次网络请求拆成 DNS、路由、TCP、TLS、HTTP、应用处理、连接关闭等阶段。
- 区分可达、可连接、握手成功、HTTP 成功、业务正确这些不同层次。
- 根据 timeout、refused、reset、502、503、504 等现象定位初始方向。
- 选择合适证据工具,而不是盲目堆命令。
- 用抓包判断 SYN、ACK、重传、RST、窗口等关键事件。
- 分析慢请求是延迟、吞吐、丢包、排队、缓存还是上游依赖问题。
- 写出可协作的排障记录,把“网络问题”变成可验证、可推进的技术问题。