先给结论:丢包监控本质上不是一个采集问题,而是一个指标可信度问题。你能采到丢包率,而这个丢包率在三种情况下会系统性骗你------分母太小、被均值抹平、以及逐跳探测的假阳性。不先解决可信度,后面所有定位都是在错误输入上推理。
有个案例很典型:视频会议被投诉卡顿,而带宽利用率不到 40%、设备资源正常、接口无告警,只在一条出口链路看到 0.8% 的丢包率。0.8% 这个数字,对批量传输可以忽略,对实时音视频已经是不可用。同一份数据,取决于你怎么读它。
核心要点
- 丢包要按数据模型来组织:errors / discards × 入向 / 出向 四个格子,不是一个大数字。
- errors 与 discards 是两套归因模型:前者指向物理层,后者指向拥塞或策略,混用会导致方向性错误。
- 丢包率有三个工程缺陷:分母不稳定、均值掩盖尖峰、不携带方向信息。
- 逐跳探测必须内置假阳性验证规则,否则中间跳的限速会持续误导排查。
- TCP 重传率的定位是"确认"而非"定位" ,它的价值在于证伪,不在于指路。
一、先把丢包组织成四个格子
接口计数器天然是两个维度:类别 (errors / discards)与方向(入向 / 出向)。四个格子各自指向不同的归因路径,这才是丢包数据的正确结构。
| 格子 | 物理含义 | 归因方向 | 观察方式 |
|---|---|---|---|
| 入向 errors | 收到的帧本身损坏(CRC、对齐错误) | 本端物理层、对端发送侧、线路 | 看增量与端口集中度 |
| 出向 errors | 发送时检测到错误 | 本端发送侧硬件或线缆 | 看增量,与流量无关 |
| 入向 discards | 帧正常但被丢弃 | 设备过载、缓冲不足、入向策略 | 与设备资源曲线对齐 |
| 出向 discards | 帧正常但队列溢出被丢 | 出向拥塞、队列调度策略 | 与带宽波峰对齐 |
四个格子一旦分开,六种成因会立刻收敛到一到两种。很多团队之所以排查慢,是因为把四个计数器合成一个"丢包数"在采------聚合发生在错误的位置,信息就永久丢失了,事后再想分辨也来不及。
二、丢包率的三个工程缺陷
这不是说丢包率没用,而是说它单独使用时不可靠。
缺陷一:分母不稳定。 丢包率 = 丢包数 / 发包数。低流量链路上每分钟只发几百个包,丢几个就能算出很高的百分比;高流量链路上 0.1% 的绝对数量可能远超前者。所以比率必须与绝对包数一起存、一起看,不能只保留比率。
缺陷二:均值掩盖尖峰。 5 分钟均值 0.2% 完全可能藏着一段 3 秒的 30% 丢包。对实时业务来说,那 3 秒就是用户感受到的全部。所以口径要用分位数(P95 / P99)或者短窗口峰值,而不是均值。
缺陷三:不携带方向信息。 "丢了 5000 个包"这句话无法支持任何动作。是设备自己丢的,还是上游丢的?是入向还是出向?缺了方向,丢包率就只是一个现象描述,不是判断依据。
工程判断:如果只能保留三个丢包相关指标,我会选------出向丢弃增量、入向错误增量、TCP 重传率。前两个决定归因方向,第三个决定是否值得继续查。
三、逐跳探测:必须内置一条验证规则
逐跳探测(traceroute / mtr)是定位丢包位置最有效的手段,但它有一个会让排查彻底跑偏的特性:中间跳的丢包率经常是假的。
原因是很多网络设备对"发往自己"的探测包做了限速(ICMP rate-limit、控制平面策略),原因是这些包要被送到控制平面处理,属于慢路径。设备为了保护 CPU 会主动丢弃一部分,于是探测结果显示"该跳丢包 38%",而实际上转发路径上一个包都没丢。
判断规则是一个三元组,三条同时成立才认定为真丢包:
python
# 逐跳探测 + 三元组验证规则
def classify_hop(hop):
"""三条同时成立才判为真丢包,否则判为限速假阳性"""
checks = {
'endpoint_same_or_worse': hop.end_loss >= hop.loss * 0.8, # 1) 末端同向劣化
'bidirectional': hop.reverse_loss >= hop.loss * 0.5, # 2) 反向探测也丢
'protocol_independent': hop.udp_loss >= hop.loss * 0.5, # 3) 换 UDP 仍丢
}
if all(checks.values()):
return 'REAL_LOSS'
failed = [k for k, v in checks.items() if not v]
return f'LIKELY_RATE_LIMIT (failed: {",".join(failed)})'
# 说明:
# 中间跳被限速时,末端通常是 0% ------ 第一条就会失败,直接判为假阳性。
# 只做单向探测是常见的错误做法,缺了第二条会误判单向故障。
更稳妥的架构决策是:把逐跳探测的结果只当成"候选位置",真伪由端到端探测和接口计数来裁定。也就是说,逐跳负责缩小范围,不负责下结论。
四、定位流程的分层设计
把定位拆成两级,可以避免"拿着一个被污染的输入往下走"。
第一级是归因分层,纯数据驱动: 先看四个格子哪个在增长,直接决定走物理层路径还是拥塞/策略路径。这一步不需要探测,只需要采集口径正确。
第二级是位置收敛,需要探测参与: 用逐跳探测缩小范围,再用三元组规则过滤假阳性,最后用接口计数在候选设备上确认。
两级分开的价值在于:如果第一级就已经指向"物理层劣化"(错误计数与流量无关地增长),那么第二级根本不需要做逐跳探测,直接去查端口、线缆、光模块。跳过第一级去做逐跳,是排查耗时的主要来源。
思考与总结
这套东西回头看,最值得记住的是两个判断:
第一,聚合并不能省存储,它省掉的是判断能力。 把 errors / discards / 入向 / 出向合成一个"丢包数",看板是好看了,但归因路径也断了。数据模型的粒度应当对齐"你要做的决策",而不是对齐"页面的整洁度"。
第二,探测结果需要一条显式的证伪规则。 逐跳探测的中间跳假阳性不是偶发问题,而是设备的正常设计行为。把它当成异常来对待,只能靠一条固定的验证规则,不能靠人的经验------因为经验会疲劳,规则不会。
参考来源
- IETF RFC 792------ICMP 协议规范
- IETF RFC 2330------IP 性能指标框架(IPPM)
- IETF RFC 5357------TWAMP 双向主动测量协议
- Google SRE Book------Monitoring Distributed Systems
一句话总结
把丢包数据按"类别 × 方向"组织成四个格子,让丢包率始终带着绝对包数和分位数一起出现,再给逐跳探测配一条固定的证伪规则------丢包定位的准确性来自数据模型与验证规则,而不是来自更贵的工具。