← 全部文章

估计你测不到的东西

一份从链路计数器推断出来的流量矩阵、我决定不做的那个流采集器,以及我自己实验室诚实的边界

Michel Wijnberg

上一篇是有意在最后一个问题前停住的。Osprey 能告诉您断掉 nrt1-cr1 ↔ sea1-cr1 会改变 56 条 路径、不会孤立任何东西。运维人员接下来会问的那个问题,才是决定这次变更是否安全的:

流量会去哪,有没有东西会溢出?

没有人只凭路径条数就批准一次变更。真正拍板的数字是容量:接手这些流量的链路装不装得下。这一篇 讲的是,当网络里没有任何东西在直接测量这个数字时,您能诚实地往它靠近到什么程度,以及这个答案 从哪里开始就不该再拿来倚靠了。

要回答它,就得知道从每一个源到每一个目的地各有多少流量:一份流量矩阵。几乎没有人有。


我决定不做的那个东西

拿到流量矩阵的教科书做法是流导出:NetFlow、sFlow、IPFIX。路由器采样流、把记录送到采集器,然 后你把它们聚合成源-目的需求量。

我计划过。这个仓库里有一份 1,139 行的设计文档,写的是一个带 LSDB 感知去重的流采集器。它在自 己的第一行就标着:

Status: SHELVED (2026-03-12). Deferred indefinitely after cross-plan feasibility review.

并列了五条理由。真正拍板的是其中两条:

  • **数据量。**在 500 台路由器规模下每周 70–220 GB,大约是整个数据库其余部分的一百倍。 PostgreSQL 是这个产品里唯一的数据存储,这是刻意的;吞下一条流水线意味着要么加第二套存储,要 么让数据库垮掉。
  • **边际价值。**实际可用的流量可见性,大约有 80% 本来就能从 SNMP 接口计数器拿到,而那些数据本 来就在采。

这不是技术上做不到。这是一个判断:最后那 20% 要付出一个新子系统、一份新的运维负担和一类存储风 险,而我认为不值。理性的人可以有不同意见;有些网络确实需要流数据。这里重要的是,这个决定连同 它的理由都被写了下来,好让任何评估 Osprey 的人都能自己核对:他们的处境是不是和我一样。

所以:没有流记录。剩下的,就是那个有意思的问题。


从链路愿意透露的东西里反推矩阵

Osprey 确实有的,是每一条链路的负载,而且是正经测出来的:64 位的 ifHCInOctets / ifHCOutOctets 计数器,按周期轮询,做差得到每秒比特数,做回绕修正,再除以接口速率得到利用率 百分比。

那是一组按链路的总量。而您想要的是一组按对的需求量。从前者恢复后者是一个欠定的反问 题:许多不同的流量矩阵会产生完全相同的链路负载。它有一个众所周知的方法:Tomogravity (Zhang、Roughan 等,2003)。

它分两步走,Osprey 两步都实现了:

// computeTrafficEstimate estimates traffic redistribution after topology
// mutations using the gravity model (Zhang/Roughan et al., "Tomogravity" 2003).
//
// Without a full traffic demand matrix, per-pair demands are estimated using
// the gravity model: demand(i,j) ∝ V(i)·V(j)/V_total, where V(i) is the
// total traffic volume at device i (derived from SNMP interface utilization).
// These gravity demands are then calibrated against observed per-link loads
// so that the model's predictions match reality.

引力那一步假设两台路由器之间的流量,正比于各自总承载量的乘积,形式和牛顿引力一样,或者说和 两个经济体之间的贸易模型一样。它是一个先验,不是一次测量,而且它会在特定方面出错:它没有”这一 对邻居很忙”或者”那一对很闲”的概念。

层析那一步才让它变得可用。引力猜测会被缩放,使得当所有估计出来的需求量都按 IGP 实际选出来 的路径去走时,得到的每链路负载与实测的负载相符。先验被证据修正了,而证据是这里唯一不是猜出 来的东西。

然后,也只有到这一步之后,校准过的需求量才会在故障后的路径上重新走一遍(按 ECMP 加权,所以一对 流量四分的组合,会给每条链路各贡献四分之一),而差值就是预测出来的重分布。


三个刻意不炫的选择

一个估计器里所有有意思的工程,都在你阻止它变得自信的那些地方。

**做全局校准,而不是按链路校准。**诱人的做法是给每条链路独立算一个缩放因子。它更贴合数据,而且 糟糕得多:

// Compute a GLOBAL calibration factor: total observed bps / total gravity sum.
// Per-link calibration can amplify noise when gravitySumPerLink is small
// relative to observed traffic, producing extreme scaling factors that
// inflate per-pair demands unrealistically. Global calibration distributes
// the error uniformly, producing more stable and realistic results.

一条引力和几乎为零、却测到一点点流量的清闲链路,会产生一个巨大的缩放因子,进而把每一对穿过它的 流量都吹起来。更紧的拟合,换来的是偶发的胡说八道。一个全局因子把误差摊匀,而且永远不会炸。

**把任何单一对的上限压在总量的 5%。**这是对”一个估计出来的需求量最多能占网络多大比例”的硬上限, 因为反问题的失效模式,就是某一对把一切都吸走。

**拒绝报告小的变化。**预测出的位移如果小于链路利用率的 0.5%,就会被丢掉;开销变更那条路径上是 0.1%,因为它同时也承载假设链路和假设节点,会把一个新中转节点的影响稀薄地摊到许多条链路上。低于 这个值,这个数字就和计数器抖动没法区分了,而把它打印出来,等于邀请别人 对噪声采取行动。

这几条每一条都会让输出看起来不那么精确。精确不是目标;目标是让屏幕上显示的每个数字,都是你能靠 上去的那种。


现在说说我的实验室帮不上忙的地方

前面八篇里的一切,都是拿一个能反驳我的实验室验证过的。4,032 对路由器对照真实路由表核对过。360 条虚构走廊被找了出来。三种协议、三条发现路径,对同一个单点故障给出了一致的答案。

而对流量来说,这个实验室几乎没用,我想把原因说准确。

这个实验室里的路由器几乎什么都不转发。它们跑协议、交换 LSA 和 BGP 更新,基本上就这些了。实测数 据是:

测量项数值
有利用率数据的接口1,279
…利用率低于 0.05% 的1,241
全网最高利用率一个 10 Mbps 端口上的 0.431%
全网最高接口速率约 43 kbps
368 个标称 10 Gbps 接口上的峰值约 24 kbps,也就是 0.00024%

如果您知道该往哪儿看,就能在上一篇文章那张仿真截图里看到 这个后果。失效链路的标题写着 “2 links, 6Kbps displaced”,六千比特,而面板里没有 Traffic Redistribution 区块,也没有任何拥塞风险。不是因为代码没跑,而是因为每一处预测出的位移都落在了 那个 0.5% 的噪声底线之下,被正确地丢弃了。

管路部分是可验证正确的:计数器被读取、速率被做差、引力需求被构造、校准被执行、重分布在故障后的 ECMP 路径上被算出来,而噪声底线拒掉了它该拒的东西。这个实验室没法告诉我的,是这个估计到底 好不好,因为验证一个估计器需要一份用来对照的基准真相,而这里的基准真相意味着:带着已知源-目 的矩阵的真实流量。

一个没有流量的实验室产不出这种东西。加合成负载也修不好:那等于我用自己挑的一份矩阵去造流量,然后 表扬估计器成功还原出了我刚喂给它的那份矩阵。那不是验证,那是一种非常慢的检查我自己算术的方式。


那么,您该信它多少?

下面是诚实的阶梯,按数字越来越不结实的顺序排列:

  1. 链路利用率,实时和历史:实测。64 位计数器、做差、回绕修正、对照接口速率做过合理性检查。这 是数据。
  2. 一次变更之后哪些路径会变:从拓扑算出来的。确定性的,而且底下那份拓扑正是拿 4,032 对路由器 验证过的那一份。
  3. 有多少流量会挪到每条链路上估计出来的,来自一个被实测链路负载修正过的引力先验。在方向 上有用,用真实证据校准过,但不是一次测量。

第 3 阶确实很有价值。它是”这十二条链路一起吸收了这次故障”和”这一条链路吸收了大部分,而它已经在 70% 了”之间的差别。它同时也是整个系列里唯一一个我没法在旁边写上验证数字的台阶,而用和”4,032 比 4,032”同样的口吻去呈现它,会是不诚实的。

在做得到的地方,产品确实画出了这条线。当一个 BGP 对等体的流量只能从前缀数量的比例推出来、而不是来 自一个匹配上的 SNMP 接口时,那一行会带一个提示,明确写着 “Traffic estimated from prefix count ratios (no SNMP interface match)“,就挨着那些标着 SNMP、来自计数器的行。同一张表,分了等级,这 正是整个系列反复落到的那个模式,而这已经是它第三次以同样的形状出现了。一条跨域路径把它的各段分成 resolved / inferred / opaque第四篇);一处端口标注把它 的四种判定从”陈述事实”一路分到”明确的歧义”(第六篇);上面那三阶 则给一个流量数字分了级。三把梯子,一个习惯:当一个答案底下的证据参差不齐时,就地分级,而不是给整件 事发一个笼统的置信度。


重申一遍实验室是干什么用的

第七篇文章论证过:实验室不是为了让 Osprey 好看,而是为了证明 Osprey 是错的。这一篇是那个没人喜欢的推论:一个实验室只能证伪它有能力施加压力的那些东西。

我这个实验室在拓扑、协议语义和转发上反驳我的本事特别强,因为它有 192 台真实路由器和真实的路由表, 我可以去读、去比对。它没有能力在流量上反驳我,因为它根本不承载流量。

对于你的产品打印出来的每一个数字,知道自己处在这两种情形中的哪一种,就是”一个值得信任的工具”和 “一个只是很自信的工具”之间的大部分差别。我很清楚 Osprey 里哪些断言由测量支撑、哪些由在已验证模型 之上的计算支撑,以及哪些由一个我相信、但在这里没法证明的估计器支撑。

这一篇就是第三类。这一类恰好只有一个,而现在您知道它在哪儿了。


下一篇是这个系列的最后一篇:模型是正确的,而且它还是一个关于此刻的模型。那么,网络在坏掉之前 一小时是什么样子的?网络是有记忆的