如果我把这个弄坏会怎样?
一个你信任的模型,只有在你能向它提出从未被问过的问题时才值得拥有
Michel Wijnberg
这个系列的前八篇讲的是把模型做对:在不成为网络一部分的前提下发现网络、逐跳复现转发、拒绝 猜测,以及用最难受的方式发现我自己的工具一直在画虚构的东西。
那些全都是准备工作。一个仅仅准确的网络模型,是一张非常昂贵的照片。花掉那些力气的理由, 是为了能向它提出那个你没法向真实网络提出的问题:
如果我把这个弄坏会怎样?
这个问题决定了维护窗口。总得有人说清楚:凌晨三点拔掉那块板卡,网络扛不扛得住。通常他是靠脑子 里的模型和对上一次故障的记忆来回答的。接下来要讲的东西之所以有意思,不是因为 Osprey 有个仿真 器,而是因为故障不必先发生,您就已经能对它进行推理了。
你能改动的七件事
Osprey 的仿真模式会把在线模型取过来、克隆一份、施加变更,然后重新计算。它允许你改动的东西 清单很短,而这个”短”是刻意的:
| 变更 | 作用 |
|---|---|
link_failure | 断掉一条链路 |
node_failure | 断掉一台路由器 |
cost_change | 给一条链路重新赋度量值,正反方向各自独立 |
hypothetical_link | 增加一条并不存在的链路,带开销和速率 |
hypothetical_node | 增加一台并不存在的路由器 |
srlg | 让一个共享风险组失效:一次操作,N 条相关联的链路同时断 |
peer_failure | 断掉一条 BGP 会话 |
其他任何东西都会被以 unknown mutation type 拒绝。没有区域重构变更,没有重分发变更,也没有
级联故障变更,因为这些我一个都没法在不编造数据的前提下实现。这一点我后面还会回来讲。
一根线缆,以及网络对它的反应
这是实验室里的真实一例。nrt1-cr1 ↔ sea1-cr1 是 AS 200 里一条跨太平洋的骨干链路,在 OSPFv2 下开销 10,
是 Osprey 在这个租户的两个 OSPF 实例上持有的 275 条链路之一。我右键点了它,选了 Simulate Failure:
看顶上那三个数字。**没有任何东西变得不可达。56 条路径变了。没有出现新的单点故障。**整个评估 在服务端只花了 57 毫秒。
现在再看 Failed Links 那个标题,因为它在做一件很多人会漏掉的事:2 links。我点了一根线 缆,Osprey 断掉了两条链路,因为那根线缆把 OSPFv2 和 OSPFv3 当作 两个互相独立的协议实例来承载,各有各的开销。让这根线失效,就 是让它在两边都失效。一个按每根线缆建一条边的工具,必须决定要结束它两条命中的哪一条。
有意思的是那 56 条的拆分:
- 15 条上升:路径变贵了。
sea1-cr1 → nrt1-cr1从开销 1 变成开销 11,直连链路被一条三跳的路径取代。 - 41 条改道:路径换了跳数,而开销完全没动。
第二个数字才是值得盯着看的。四十二个源/目的对在网络里走了另一条路,而且一分钱代价都没付,因为 一条等价路径本来就在那儿。当你把冗余表达成一次测量而不是一个形容词时,它看起来就是这样。“我们 有多样化的路径”是一个说法。“56 个受影响的对里有 41 个以相同开销改道”是一个数字,而且正是这个 数字告诉你维护窗口需不需要安排在凌晨 3 点。
这里没有任何东西被敲进过路由器。实验室没有真的断掉一条链路。我问的是模型。
屏幕顶上的那句拒绝
现在看第一张截图里那条琥珀色横幅,因为它是一次承认,也正是我信任面板其余部分的原因:
simulated paths are shown as an SPF projection (source-rooted least-cost tree) so before and after stay comparable; the live path panel shows the hop-by-hop forwarding chain, which can differ where an intermediate router’s own routing table disagrees with the source’s view
第三篇文章论证的是:以源为根的走廊是 IP 转发的错误模型,并且拿测量 数据撑腰:2,839 个跨区域路由器对里有 360 个,其走廊里含着一个任何报文都不会走的跳。我把那个引 擎换成了会遍历每台路由器自己路由表的引擎,并拿全部 4,032 对做了验证。
然后,在仿真里,我刻意不用它。
理由写在代码里,那也是这个产品里我最引以为傲的一句话:
// The panel shows the hop-by-hop forwarding chain (path_chain.go): every
// router's OWN routing table, read from the per-area LSDBs. A what-if topology
// has no such tables. The Type-3 summaries the surviving ABRs would
// re-originate after the mutation are exactly the thing that cannot be
// synthesised, and inventing them would make the simulation's numbers agree with
// nothing. So both simulation sides stay on the source-rooted SPF projection,
// consistently with each other, and say so. A labelled projection is honest; a
// baseline that disagrees with the baseline is not.
要遍历每台路由器自己的表,就需要知道变更之后每台路由器的表会是什么样。在 OSPF 里,这取决 于幸存的 ABR 会重新产生哪些 Type-3 summary-LSA:那些 LSA 并不存在,因为故障还没发生。我可以猜 它们。我没法猜对,而一条建立在猜出来的 summary 之上的逐跳链,会带着那个已验证引擎的全部权 威,却一点验证都没有。
所以比较的两侧都停留在那个明确标注过的投影上。“之前”那张图是被刻意做差的,好让它仍然和”之后” 那张图可比。一个”56 条路径变化”,如果实际上是”36 条真变化加上 20 条因为两侧用了不同引擎而产生 的假象”,那它就不是一份 diff。那是带着数字的噪声。
EIGRP:天花板是我的数据,不是协议
在 EIGRP 租户里弄坏点什么,Osprey 会停下来,而不是给你一个投影:
the simulated change affects the observed EIGRP chain (forward and reverse). Osprey cannot predict DUAL re-convergence: the topology tables it reads carry the DUAL distances, not the metric components (bandwidth, delay) a recomputation needs. After a real event the live view shows the new chain.
EIGRP 没有可供重新计算的链路状态数据库。Osprey 手里有的,是从 CISCO-EIGRP-MIB 读来的每台路
由器自己的拓扑表,而那十二列带的是 DUAL 的距离(feasible distance、computed distance、
reported distance),不是这些距离所依据的分量。
要在变更之后重算 DUAL,你需要最小带宽、总时延、可靠性、负载、MTU 和跳数。这些在设备上是存在
的;我在 e-ams1-cr1 上用 show ip eigrp topology 10.64.0.0/15 确认过。它们只是不在 Osprey
所读的那张 MIB 表里。
这个区分是特意写进代码注释里的:
// Scoped to what Osprey READS, deliberately not to what SNMP can carry: … A future
// CLI enricher could lift part of this ceiling, so the sentence must not read as a
// permanent property of the protocol.
**“这个协议无法被仿真”和”我目前没有采集那些输入”**之间有实质区别,而一个把两者混为一谈的 产品,是在悄悄告诉你别再费心问了。这是一个数据采集层面的天花板,而且是可以掀掉的。等我掀掉它, 这条消息就会消失。
它底下还有一条更小、更锋利的规则。如果变更是纯粹的移除(一条链路或一个节点失效),而被移除的 东西可被证明不在观测到的那条链上,Osprey 会继续显示真实的链,并说明理由:“observed live EIGRP chain: the simulated failure does not touch it (EIGRP re-convergence itself is not modelled)”。 在别处拿掉容量,永远不可能改善一条本来就没用到它的距离矢量路径。但一次开销变更或一条新链路 可能从任何地方把路径吸引过去,所以那些一律算作”碰到了”。这个引擎恰在必须拒绝的时候拒绝, 而不是一刀切地拒绝。
变更清单里没有什么,以及为什么
这七种变更,是我能在不编造输入的前提下实现的那些。缺席的那些,都是有明确理由地缺席:
- **区域重构。**挪动一个 ABR 或者重画一条区域边界,会改变”到底存在哪些 summary-LSA”。那不是对 拓扑的一次变更,那是另一张拓扑。
- **重分发变更。**它们取决于 route-map 和 prefix-list,而 Osprey 对这些毫无可见性。我等于是在 给一份我读不到的策略建模。
- **级联故障。**要预测第二次故障,需要队列和 TCP 的动力学,而一个拓扑工具没有资格声称自己能对 那些建模。标出风险;别去预测级联。
这几样每一个演示起来都会很漂亮。每一个都会是一个背后空无一物的数字。
要点
仿真是一个拓扑产品要么把建模的功夫兑现、要么把它暴露出来的地方。数据模型里抄过的每一条近路,都 会在这里以”自信的错误答案”的形式冒出来,因为一个假设场景没有任何基准真相可以对照。故障还没发 生,所以没有任何东西能反驳你。这恰恰是它成为最值得小心对待的功能的原因。
诚实的版本,单看截图不那么震撼,而在凌晨 3 点相当有用得多:七件你能改的事、四个出来的数字,以及 一条说明这些数字由哪个引擎产出的横幅。
下一篇:一条链路断了,但网络里到底哪些部分真的依赖它? 影响半径。