主题
完成 HA:VRRP 与真实切换
上一篇做完了 NAT 高可用的一半 —— 会话表同步。 但那一篇结尾有一张诚实的清单:
text
✓ 已验证 会话表实时同步,端口映射一致
✗ 未验证 虚拟 IP(VIP)
✗ 未验证 VRRP / BFD 自动切换
✗ 未验证 切换时的实际连接存活率这一篇把这三项补上。结论先说:做完之后,切换时已建立的连接一次都不断。
为什么会话同步只是一半
会话同步解决的是"备机知道有哪些连接"。但它没解决另一个问题: 流量凭什么会流到备机去?
内网主机的默认网关写的是 nat1 的地址。nat1 挂了,流量就停在那儿 —— 备机会话表再完整也没用,没人把包送给它。
需要一个会漂移的地址。
VRRP:让地址在两台设备之间漂移
VRRP(Virtual Router Redundancy Protocol,RFC 5798)的做法:
text
两台设备加入同一个 VR(虚拟路由器)组
↓
组内选出一个 Master(按优先级)
↓
Master 持有 VIP 和一个虚拟 MAC(00:00:5e:00:01:<vr_id>)
↓
Master 停止发通告 → Backup 的 master-down 定时器超时 → 接管关键细节:虚拟 MAC 在两台上是同一个。所以切换时内网主机 连 ARP 都不用重学 —— 它继续发往 00:00:5e:00:01:01, 只是接手的换了一台设备。
拓扑要求
主备必须在同一个二层网段上
这是 VRRP 的前提,也是本教程 HA 底座改过一次拓扑的原因。
最初的底座只有一条同步链路连着 nat2,做会话同步够用, 但 nat2 不在内外网段上,VRRP 无从谈起。现在的底座是:
text
h1 10.10.0.11 ──┬── nat1 .1 ──┬── s1 203.0.113.11
└── nat2 .2 ──┘
│ 同步链路 10.99.0.0/24
内网 VIP 10.10.0.254
外网 VIP 203.0.113.254两台 VPP 同时在内网段、外网段和同步链路上,一共三个接口。
配置
应用配置
bash
./labctl up ha
./labctl reset ha
./labctl apply ha 02分四步。
一、两台的 NAT 配置必须一致,地址池就是外网 VIP
bash
# 在 nat1 和 nat2 上都执行
vppctl nat44 ei plugin enable
vppctl set interface nat44 ei in host-eth1 out host-eth2
vppctl nat44 ei add address 203.0.113.254 # ← 就是那个会漂移的 VIP地址池用 VIP 是整个方案的枢纽
如果 nat1 的池是 203.0.113.1、nat2 的池是 203.0.113.2, 那么切换之后所有会话的外部地址都变了 —— 外网侧看到源地址突变, 连接必然中断。
池地址必须跟着 Master 一起漂移,外网侧才会毫无感知。
顺带一个前面章节的知识点在这里派上用场: nat44 会把池地址装进 FIB 当作本地地址, 所以持有 VIP 的那台自然会代答 ARP。
二、打开会话同步
bash
# nat2(备)
vppctl nat44 ei ha listener 10.99.0.2:8484
# nat1(主)
vppctl nat44 ei ha listener 10.99.0.1:8484
vppctl nat44 ei ha failover 10.99.0.2:8484 refresh-interval 2细节和坑见上一篇 —— 主机也需要本地 listener, 两边地址池必须一致,否则同步会被静默丢弃。
三、建两个 VRRP 组
内外网段各一个,因为两侧的地址都要漂移:
bash
# 内网 VR 1
vppctl vrrp vr add host-eth1 vr_id 1 priority 200 accept_mode 10.10.0.254 # nat1
vppctl vrrp vr add host-eth1 vr_id 1 priority 100 accept_mode 10.10.0.254 # nat2
# 外网 VR 2
vppctl vrrp vr add host-eth2 vr_id 2 priority 200 accept_mode 203.0.113.254 # nat1
vppctl vrrp vr add host-eth2 vr_id 2 priority 100 accept_mode 203.0.113.254 # nat2
# 两台都要启动协议
vppctl vrrp proto start host-eth1 vr_id 1
vppctl vrrp proto start host-eth2 vr_id 2| 参数 | 含义 |
|---|---|
priority | 越大越优先,nat1 给 200、nat2 给 100 |
accept_mode | 必须开 —— 不开的话 Master 只转发,自己不接收发往 VIP 的包,VIP 连 ping 都不通 |
interval | 通告间隔,默认 100(单位 10ms,即 1 秒) |
no_preempt | 高优先级节点恢复后不抢回 Master |
四、内网主机改用 VIP 做网关
bash
ip route replace default via 10.10.0.254 dev eth1确认状态
bash
./labctl vppctl ha show vrrp vrtext
[0] sw_if_index 1 VR ID 1 IPv4
state Master flags: preempt yes accept yes unicast no
priority: configured 200 adjusted 200
timers: adv interval 100 master adv 100 skew 21 master down 321
virtual MAC 00:00:5e:00:01:01
addresses 10.10.0.254选举要等几秒
master down 321 是 3.21 秒。刚 vrrp proto start 之后马上去看, 可能两边都显示 Backup —— 定时器还没到。等 3~5 秒再看。
我第一次测就是查得太早,以为外网那个 VR 没选出 Master。
验证:连接到底断不断
跑自检
bash
./labctl verify ha 02自检做两组对照实验,各建一条长连接(每秒一次心跳), 在中途触发切换,看心跳有没有断。
实验 A:VRRP + 会话同步
text
节点 切换前包数 切换后包数 增量
────── ────────── ────────── ──────
nat1 35 35 +0
nat2 17 52 +35
RESULT 成功 18 次,失败 0 次
✓ 已建立的连接全程存活,一次心跳都没丢
✓ 切换后流量确实转到了 nat2(增量更大)两件事同时被证明了:
- 流量真的转移了 —— 切换后 nat2 的转发包数 +35,nat1 +0
- 连接毫发无损 —— 18 次心跳全部成功
为什么要看包计数
只看"连接没断"是不够的。VRRP 用同一个虚拟 MAC,如果切换其实没成功, 流量可能仍然走着原来那台,连接自然也不会断 —— 那就测了个假阳性。
必须用两台的转发计数证明流量确实换了设备。 这是设计这个实验时最容易偷懒的地方。
实验 B:只有 VRRP,没有会话同步
同样的拓扑、同样的切换,只是不配 ha failover:
text
RESULT 成功 6 次,失败 9 次
[ 12] FAIL BrokenPipeError
[ 13] FAIL BrokenPipeError
[ 14] FAIL BrokenPipeError
✓ 连接在切换后断了 —— 证明光有 VRRP 不够VIP 漂过去了,包也到了备机。但备机的会话表里没有这条流, 回程包查不到转换关系,直接被丢。
text
┌────────────────────┬────────────────────────────┐
│ 配置 │ 切换后已建立的连接 │
├────────────────────┼────────────────────────────┤
│ VRRP + 会话同步 │ 成功 18 次,失败 0 次 │
│ 只有 VRRP │ 成功 6 次,失败 9 次 │
└────────────────────┴────────────────────────────┘NAT 的高可用是两件事,缺一不可
text
地址漂移(VRRP) → 让流量能到备机
状态同步(HA sync)→ 让备机认得这些流量只做前者:流量到了但被丢,症状是切换后连接全断、 备机 no translation 计数暴涨。
只做后者:备机什么都知道,但永远等不到流量。 这就是上一篇结束时的状态。
接口跟踪:更实用的切换触发条件
上面的实验用 vrrp proto stop 手工触发切换。真实故障通常是 某个接口挂了,而 VRRP 默认只看自己所在网段的通告。
设想:nat1 的外网口断了,但内网口还好。这时 nat1 仍会在内网段上 正常发通告,继续当 Master —— 而它已经出不去了,流量全黑洞。
track-if 解决这个问题:
bash
vppctl vrrp vr track-if add host-eth1 vr_id 1 \
track-index <外网口的 sw_if_index> priority 50意思是:如果被跟踪的接口 down,本 VR 的优先级降低 50。 降到低于对端后,对端抢占成为 Master。
优先级差值要算好
text
nat1 配置优先级 200,跟踪扣减 50 → 降到 150
nat2 配置优先级 100
150 > 100,仍然是 nat1 当 Master —— 跟踪等于没起作用扣减值必须大于两台的优先级差。上例应该扣 ≥ 101, 或者把 nat2 的优先级提到 160 以上。
这是配 VRRP 跟踪时最常见的错误。
还剩什么没做
诚实地说,这一篇之后仍有两块没覆盖:
text
✗ BFD 联动
VRRP 的默认通告间隔是 1 秒,master-down 约 3.2 秒 ——
也就是说切换要 3 秒左右。要做到亚秒级,需要 BFD
快速检测链路故障并联动 VRRP。VPP 有 bfd 插件,
但和 VRRP 的联动没在本教程里验证。
✗ 双主(split-brain)防护
同步链路断了,两台都会认为对方挂了,都当 Master。
两台同时用同一个 VIP 和同一个 NAT 池 → 端口分配冲突、
会话错乱。生产环境需要额外的仲裁机制
(多条心跳链路、或者第三方仲裁点)。第二条是真实部署里最需要小心的。本实验用一条专用同步链路, 它本身就是单点。
小结
| 解决什么 | 让流量能切到备机,配合会话同步实现无感切换 |
| 前提 | 主备必须在同一个二层网段上 |
| 配置 | 两侧各建一个 VR,priority 定主备,必须开 accept_mode |
| 枢纽 | NAT 地址池 = 外网 VIP,池地址跟着 Master 漂移 |
| 实测结果 | VRRP + 同步 → 18/18 心跳存活;只有 VRRP → 切换即断 |
| 验证要点 | 不能只看连接没断,要用两台的转发计数证明流量真的转移了 |
| 切换耗时 | 约 3 秒(默认定时器);要更快需要 BFD 联动 |
| 未覆盖 | BFD 联动、双主防护 |
第 3 章到此真正完整了:
text
行为画像 会话粒度、过滤、端口算法、每用户配额
会话同步 备机知道所有连接
VRRP 切换 流量能到备机,连接不断
选型 什么时候必须用 EI