环路会让一个广播帧永远转下去,而且越转越多——这叫广播风暴。 生成树(STP)的解法是「主动阻塞几条边」,把图变成树,代价是要牺牲链路。
3.2.4 说「查不到就泛洪」,这一节讲这个规则在有环时会出什么事。 核心是一个指数:每跳复制一份,几跳之后就不可收拾。
一、环路为什么致命
因为交换机「不认识自己发出去的帧」:
| 原因 | 说明 |
|---|---|
| 没有 TTL | 以太网帧头里没有「跳数」字段 |
| 广播必须泛洪 | 目的地址是 ff-ff-ff-ff-ff-ff,只能全送 |
| 泛洪不看方向 | 从哪个口来,就往所有别的口去 |
第一行是关键差别:IP 头里有 TTL,转一圈减到 0 就丢;以太网帧没有这个字段。 所以「绕回来」这件事,二层根本发现不了。 三条合起来的结果是「指数增长」:帧每绕一圈就多一份,两圈四份,十圈一千份。 交换机的 CPU 和带宽很快被这些副本占满,正常流量一个都过不去。 这种故障的表现很典型:所有端口的灯一起狂闪,网络完全不通,而且不会自己恢复。 因为它不是「拥塞」,是「自激振荡」——只要环还在,风暴就在。
二、STP 怎么拆环
三步,全部自动完成:
| 步骤 | 动作 | 结果 |
|---|---|---|
| 1 | 选一个根桥 | 桥 ID 最小的那个 |
| 2 | 每台算出「到根最短」的端口 | 那个口叫根端口 |
| 3 | 每条链路选一个指定端口,其余阻塞 | 得到一棵树 |
第一步的「桥 ID」是「优先级 + MAC」:优先级默认 32768,一样大就比 MAC,小的赢。 所以「根桥是谁」通常是「MAC 最小的那台」——这意味着换一台设备就可能换根,网络会抖一下。 第三步的产物就是「一棵树」,边数正好是「节点数减一」: 多出来的边全被阻塞(blocking),不转发数据帧。 注意「阻塞」不是「拔掉」——被阻塞的端口仍然收 BPDU,随时准备在主链路断了之后接管。 这个「随时接管」是有代价的:传统 STP 收敛要 30 到 50 秒, 因为要等「老化计时器」走完才敢切换。 所以 RSTP 把状态压缩到几个,收敛能到秒级;这在「不能断网」的场景里是必需的。
三、要牺牲多少链路
全互联的边数是平方级,生成树是线性级:
| 节点数 | 全互联边数 | 生成树边数 | 被阻塞 |
|---|---|---|---|
| 3 | 3 | 2 | 1 |
| 5 | 10 | 4 | 6 |
| 8 | 28 | 7 | 21 |
| 12 | 66 | 11 | 55 |
最后一列就是「为了无环要浪费的链路数」: 12 个节点全互联有 66 条边,生成树只用 11 条,浪费 55 条。 所以「STP 保证了不出环」的代价是「大部分链路闲着」。 数据中心受不了这个浪费,于是有了替代方案:链路聚合(把多条线绑成一条逻辑链路,用起来)、 TRILL/SPB(用路由的方式转发,允许多路径)、 以及现在的「三层到边缘」(干脆让交换机只做路由)。 思路都是同一个:既想无环,又不想浪费。
四、动手 Demo:环路为什么必须被拆掉——广播风暴的账
先算「每跳复制一份」会涨到多少,再算「生成树要牺牲几条边」。 第一张表看指数,第二张表看代价。
for hop in (1, 2, 3, 4, 6, 8, 10, 16, 20):
n = 2 ** hop
print('%2d 跳:%10d 份,按 64 字节算 %.0f MB'
% (hop, n, n * 64 / 1024.0 / 1024.0))
for n in (3, 5, 8, 12):
full = n * (n - 1) // 2
print('%2d 节点:全互联 %3d 条,生成树 %2d 条,阻塞 %3d 条'
% (n, full, n - 1, full - (n - 1)))
实跑输出:
--------------------------------------------------------------------
环路为什么必须被拆掉——广播风暴的账
--------------------------------------------------------------------
**交换机只认「目的 MAC 查不到就泛洪」,它不知道「这个帧已经绕了一圈」。**
**所以只要有环,一个广播帧就会永远转下去,而且越转越多。**下面把「跳数 → 帧数」算出来。
转发跳数 帧副本数 总字节(按 64 字节一帧)
---------------------------------------------------
1 2 128 B
2 4 256 B
3 8 512 B
4 16 1 KB
6 64 4 KB
8 256 16 KB
10 1024 64 KB
16 65536 4 MB
20 1048576 64 MB
**每经过一台交换机就复制一份,所以副本数按 2 的跳数次方涨**:
**10 跳就是 1024 份,20 跳是一百多万份。**
**而这一切的起点只是「一个广播帧」**——**ARP 请求、DHCP 发现,都是广播。**
**后果不是「慢」,是「死」**:**交换机的 CPU 全用来转发副本,正常流量一个都过不去。**
**这种故障有个专门的名字:广播风暴(broadcast storm)。**
**它的特征是「所有灯一起狂闪,网络完全不通」,而且不会自己恢复**——**因为环还在,风暴就在。**
**所以二层必须主动拆环,标准做法是生成树(STP)**:
**选举一个根桥,每台非根桥选一个「到根最近」的端口转发,其余端口阻塞。**
**结果是一棵没有环的树,边数正好是「节点数减一」。**
节点数 全互联边数 生成树边数 被阻塞的边
----------------------------------------------------
3 3 2 1
5 10 4 6
8 28 7 21
12 66 11 55
**最后一列就是「为了无环要牺牲的链路数」**:**节点越多,牺牲越多。**
**所以数据中心后来不爱用 STP,改用能同时用多条链路的方案(如链路聚合、TRILL、SPB)**——
**本质上都是「既想无环、又想不浪费」。**
每经过一台交换机就复制一份,所以副本数按 2 的跳数次方涨:10 跳 1024 份、20 跳一百多万份。 而这一切的起点只是「一个广播帧」——ARP 请求、DHCP 发现,都是广播。 后果不是「慢」,是「死」:交换机的 CPU 全用来转发副本,正常流量一个都过不去。 这种故障叫广播风暴,特征是「灯一起狂闪、完全不通、不会自愈」。 第二张表说明「无环的代价是浪费」:12 个节点全互联 66 条边,生成树只用 11 条。 所以后来的方案(链路聚合、TRILL、三层到边缘)都在解决同一个矛盾:既想无环,又想不浪费。
30 秒实验
- 把仿真里那个「2 的 hop 次方」改成「3 的 hop 次方」——假设每台交换机向 3 个口泛洪, 再看 10 跳变多少。
- 算一下:20 节点全互联要多少条边?生成树要几条?
- 想一下:为什么「被阻塞的端口仍然要收 BPDU」,而不是彻底关掉?
常见误区
- 以为环路只是「绕远路」。 以太网帧没有 TTL,绕不回来,会一直复制下去。
- 以为 STP 会把多余的线「拔掉」。 只是阻塞转发,端口仍然收 BPDU,随时准备接管。
- 以为「树形拓扑」是设计偏好。 它是「不出环」的唯一解,代价是浪费链路。
自测三问(点开对答案)
1. 为什么二层环路会「指数增长」? —— **因为以太网帧没有 TTL,交换机也不认识自己发出去的帧。**每绕一圈复制一份, 所以按 2 的跳数次方涨。 2. STP 的三步是什么? —— **选根桥、每台算根端口、每条链路选指定端口,其余阻塞。**结果是一棵树,边数是节点数减一。 3. STP 的代价是什么? —— **大部分链路被阻塞、闲着。**12 个节点全互联 66 条边,只用 11 条,浪费 55 条。下一节看:一台交换机怎么被切成好几台用。
- ☐ (本节完,下一节 3.2.6 VLAN)