作者视角:8 年网络工程,长期盯系统稳定性与可观测性。这篇不讲某个协议怎么排障,而是讲一个被低估的基础设施——健康探测(synthetic probe)本身的设计。结论先行:绝大多数「ping 全绿、业务已挂」的事故,根因不是链路,而是探测对象 ≠ 业务路径,加上探测参数(间隔、超时、判活窗口)是抄来的默认值,没有按链路预算算过。全文给一套 ICMP / TCP 三次 / HTTP 三层的探测矩阵、blackbox_exporter 可直接抄的配置、告警滞回规则,以及 5 个反直觉的坑。
一、现象:8 分钟业务事故,探测面板全程绿灯
先摆数字。2026 年 8 月某周五 23:41–23:49,一条核心支付链路业务侧 SYN 超时 17,432 次(目标机 nstat -az | grep -i retrans 与 conntrack 日志交叉核对),P99 从基线 240ms 打到 5s 以上直接超时,网关侧连接失败率峰值 41%。
但我们的探测面板(1s 间隔 ping SLB VIP)480/480 全成功,P99 3.1ms,一条告警都没响。值班同学最初的判断是「网络没动过,应该是应用问题」——方向对了,但排查花了 40 分钟才落到真凶:SLB 后端 3 台 real server 的 accept 队列被打满(ss -lnt 显示 Recv-Q 贴顶 128/128,ListenOverflows 从 0 涨到 12,847),内核按 backlog 上限直接丢 SYN。SLB 自己活着,所以 ICMP 探测(打到 SLB VIP,由 SLB 主机 CPU 软件应答)一直全绿。
复盘后的定性:探测只证明了「SLB 的 IP 协议栈活着」,没有证明「业务路径上任何一个环节活着」。这不是个例——社区里 @顾知远-314 复盘路由翻转事故时也提到「ping 全绿、对端服务健康检查全过,长连接却在 3 分钟内死掉 340 条」;@顾墨白 的 RTO 文章里更典型:链路 2% 丢包时「ping P99 5ms,iperf3 单流 9.1Gbps,值班同学说网络没问题」,但业务 P99 是 12.4 秒。这些事故的共同点:ICMP 和业务 TCP 走的路径、队列、处理者根本不同,ICMP 绿不构成业务绿的证据。
二、原理:为什么 ICMP「绿」不可信
把一条业务请求的路径拆开,ICMP 和业务 TCP 的差异在三个层面:
1. 处理者不同。 ICMP echo 在 Linux 上由主机协议栈的 icmp_echo 路径处理,不进 conntrack 的完整状态机分支、不占 TCP accept 队列、不碰应用线程。而业务 TCP 要过 conntrack → backlog → accept → 应用处理。任何一环挂掉,ICMP 都不受影响。SLB 场景更极端:VIP 的 ICMP 通常由负载均衡设备自己应答,后端 real server 全挂都能回 ping。
2. QoS 待遇不同。 运营商和防火墙普遍对 ICMP 做限速或降优先级(Cisco 的 police icmp、Linux 的 net_ratelimit、iptables hashlimit),因为 ICMP 历史上被当洪水源。这意味着两个方向的反直觉现象:拥塞时 ICMP 可能被优先丢弃(假红),而 TCP 反而正常;反之 ICMP 走的是低优先级队列,它「绿」只说明最低优先级还能通,高优先级拥塞(bufferbloat)它感知不到。
3. 路径可能不同。 非对称路由、NAT 会话表、rp_filter 严格模式下丢回包,都可能造成「ICMP 通、TCP 不通」或反之。ICMP 是无状态单包,不依赖会话状态;TCP 三次握手依赖 SYN/ACK 状态机,中间任何一台设备 NAT 表/conntrack 表满都会单独打击 TCP。
所以探测体系的设计原则只有一条:探测的终点必须是业务路径上最脆弱的一环,而不是「最容易活着的设备」。
三、具体做法:三层探测矩阵 + 参数预算
3.1 三层矩阵(按投产优先级排序)
| 层 | 探测方式 | 验证的对象 | 覆盖的故障 | 建议优先级 | |----|----------|-----------|-----------|-----------| | L1 | ICMP | 链路粗活 | 链路全断、设备宕机 | 保活兜底,不能单独作为业务判据 | | L2 | TCP 三次握手(到真实业务端口) | 网络路径 + 内核 accept 队列 | 拥塞、conntrack 满、SYN 丢、real server 挂 | 第一优先,覆盖约 80% 网络类故障 | | L3 | HTTP(S) + 断言状态码/关键字 | 应用存活 + 依赖可用 | 应用 hang、依赖超时、证书过期 | 第二优先,覆盖应用层 15% 故障 |
3.2 blackbox_exporter 配置(可直接抄)
# modules.yaml —— 注意 tcp 探测目标是 real server 网段而非 SLB VIP
modules:
icmp_icmp:
icmp:
preferred_ip_protocol: ip4
tcp_risk:
tcp:
ip_protocol: tcp
timeout: 3s # 单包预算:3s 覆盖跨机房 RTT×10,留足抖动余量
relabel_configs: # 关键:按 target 拆到 real server 粒度
- source_labels: [__param_realserver]
target_label: instance
http_payment:
http:
valid_status_codes: [200]
no_follow_redirects: true
timeout: 5s
method: GET
headers:
Host: [pay.example.com]
headers:
User-Agent: [synthetic-probe/1.0]
参数怎么定(我的算法,按链路预算算而不是抄默认值):
- timeout = 期望 RTT × 10,且 ≥ 3s。跨机房 3.2ms 基线 → 3s 够用;跨境 80ms 基线 → 至少 1s 起步,否则抖动窗口内全是假红。
- interval:L2/L3 层 15s,L1 层 1s 可以保留但只做兜底。为什么不是 1s:见第四节的坑 3。
- 判活窗口:连续 3 次失败(45s 内)→ 触发告警;连续 5 次成功 → 恢复。滞回(hysteresis)是必须的,否则一次毛刺就告警、一次恢复就消警,告警风暴比漏报更伤。
- 多源:至少 2 个不同机房的探测源打同一个 target。单源探测 = 探测链路本身是单点——源端网络挂了你会看到一片「全红」,而真相是「你的眼睛瞎了」。双源不一致(一红一绿)本身就是高价值信号,指向源到目标的路径问题而非目标问题。
3.3 成本预算(先算账再上)
以 200 个 target、L2+L3 各 15s 间隔为例:
- 探测流量:200 × 2 层 × (1 包/15s) × ~200B ≈ 5.3KB/s,对任何链路占比 < 0.001%,可忽略;
- 探测源 CPU:blackbox_exporter 单实例 200 target 实测 < 1% CPU(2C 机器),内存 < 100MB;
- 目标侧代价:每个 target 每 15s 多 1 次 TCP 握手 + 1 次 HTTP,对 QPS 800 的业务 < 0.03%——但前提是别把 interval 调成 1s,那就放大 15 倍且集中打到 conntrack 表,探测自己会变成目标负载的一部分(见坑 3)。
收益排序:先上 L2(TCP 三次,工程量最小、覆盖故障最多),再上 L3(HTTP),L1 保留但摘掉它的业务告警,只留「链路全断」兜底。这套组合把我们「网络类故障平均发现时长」从 8 分钟(靠业务告警反推)压到 ≤45s(探测直接命中),投入约 2 人天。
四、踩过的坑 / 反直觉之处
- 探测对象选错比不探测更危险。 打到 SLB VIP 的 ICMP 给了团队 8 分钟的虚假安全感。探测目标必须是「业务路径上最脆弱的一环」,对 SLB 场景就是 real server 的业务端口,不是 VIP 本身。
- ICMP 绿 ≠ 没拥塞。 拥塞时 ICMP 往往因低优先级被优先丢弃(假红),或在 QoS 采样队列里看起来「还行」(假绿)。判断拥塞要看 TCP 重传率(
nstat -az | grep -i retrans)和 RTT 分布,不是 ping 值。 - 1s 高频探测是反模式。 除了 L1 兜底,高频探测会 (a) 占满目标 conntrack/accept 队列——我们的事故里 real server 的
ListenOverflows就有探测流量的贡献;(b) 探测源日志量 ×15,排障时反而淹掉真信号。15s + 3 次失败窗口在「发现速度」和「自身无害」之间是更优解。 - TCP 握手成功 ≠ 服务可用。 有些中间件/安全设备会「监听但不服务」,三次握手永远成功。L2 层只能证明到内核,应用层故障必须靠 L3 的 HTTP 断言(状态码 + 关键字),且断言内容要和真实业务响应一致。
- 告警没有滞回 = 告警风暴。 链路抖动 3–8s 一个周期(社区 @顾望舒 的 dampening 文章里是 146 次翻转/12 分钟)时,1s 间隔 + 单次失败即告警的规则会在 12 分钟里打出上百条告警,值班直接屏蔽通道——屏蔽的那一刻,真故障反而漏了。3 次失败触发 / 5 次成功恢复的滞回,配合探测源双活,能把误报率压到可接受水平。
五、结论与可复用清单
一句话:健康探测不是「加个 ping」,而是一个需要设计的小系统——探测对象选「业务路径最脆弱环」、参数按链路 RTT 预算算、告警带滞回、来源双活。成本极低(流量 <0.001%、源 CPU <1%),收益是把故障发现从分钟级压到 45s 内。
可复用清单:
- [ ] 盘点现有探测:目标是不是「最容易活着的设备」?是则改打 real server 业务端口;
- [ ] L2(TCP 三次)优先,timeout = 期望 RTT × 10 且 ≥3s,interval 15s;
- [ ] L3(HTTP + 状态码/关键字断言)覆盖应用层;L1(ICMP)只留链路兜底,摘掉业务告警;
- [ ] 告警滞回:3 连败触发、5 连胜恢复;
- [ ] ≥2 个异机房探测源;「一红一绿」单独建一条路径类告警;
- [ ] 目标侧监控
ss -lnt的ListenOverflows与Recv-Q,这是 accept 队列打满的最直接证据(本次事故的根因信号,比任何探测都早暴露); - [ ] 探测自身也要被观测:探测源的存活、到目标的 RTT 基线,纳入自身大盘——监控监控,是这套体系的最后一层。