主题
会话高可用
这是 nat44-ei 最有分量的独有能力,也是某些场景下必须选 EI 而不能选 ED 的理由。
为什么 NAT 的高可用特别难
普通路由器做主备切换很简单:备机把路由学过来就行,因为路由是无状态的。
NAT 不行。NAT 的全部价值都在那张会话表里:
切换本身可能只要几百毫秒,但所有已建立的连接都会断。对用户来说, 这和"网络挂了"没有区别 —— 视频通话掉线、下载中断、SSH 会话消失。
会话高可用要解决的就是这个:让备机提前知道主机的每一条会话。
配置
启动 HA 底座
bash
./labctl up ha这个底座有两台 VPP:
text
h1 10.10.0.11 ──── nat1 ──── s1 203.0.113.11
│ 10.99.0.1
│ 同步链路
│ 10.99.0.2
nat2(备机)这个底座不开 polling
前两个底座为了低时延给 VPP 开了 polling,代价是吃满一个 CPU 核。 两台 VPP 都开就是两个核,4 核的实验机扛不住。
所以 HA 底座刻意用中断模式。时延会高一些,但 HA 实验关心的是 "会话有没有同步过去",不是微秒级时延。
应用配置
bash
./labctl apply ha 01
./labctl verify ha 01配置分四步,顺序很讲究:
bash
# ─── 1. 备机先就位 ───────────────────────────────
vppctl nat44 ei plugin enable
vppctl nat44 ei add address 203.0.113.1 # ← 关键:和主机相同的地址池
vppctl nat44 ei ha listener 10.99.0.2:8484
# ─── 2. 主机的 HA 配置 ───────────────────────────
vppctl nat44 ei plugin enable
vppctl nat44 ei ha listener 10.99.0.1:8484 # ← 主机也要有本地 listener
vppctl nat44 ei ha failover 10.99.0.2:8484 refresh-interval 2
# ─── 3. 主机的业务配置 ───────────────────────────
vppctl set interface nat44 ei in host-eth1 out host-eth2
vppctl nat44 ei add address 203.0.113.1
# ─── 4. 确认状态 ────────────────────────────────
vppctl show nat44 ei ha两个必须踩过才知道的坑
配 HA 最折磨人的地方是:配错了不会报错,只是不同步。 下面两个坑我在实验里都撞上了,都花了不少时间才定位。
坑一:主机也需要本地 listener
直觉上 listener 是备机用的(接收),failover 是主机用的(发送)。 所以很自然会只在备机配 listener。
结果主机的 HA 根本起不来:
bash
vppctl nat44 ei ha failover 10.99.0.2:8484
vppctl show nat44 ei hatext
NAT HA disabled ← 配了 failover 却显示 disabled原因是同步用的 UDP socket 由 listener 创建,主机没有 listener 就没有发送端点。 先配上本地 listener,failover 才生效:
bash
vppctl nat44 ei ha listener 10.99.0.1:8484 # 先这个
vppctl nat44 ei ha failover 10.99.0.2:8484 # 再这个text
LISTENER:
10.99.0.1:8484 path-mtu 512
FAILOVER:
10.99.0.2:8484 refresh-interval 2sec
RESYNC:
completed (0 ACK missed)坑二:备机必须有相同的地址池
这个坑更隐蔽。两边 HA 状态都正常,同步报文也在链路上跑,但备机会话数就是 0。
在备机上抓包能看到报文确实到了:
bash
./labctl vppctl ha clear trace # 注意:这条要在 nat2 上执行text
00:01:29:611765: ip4-input
UDP: 10.99.0.1 -> 10.99.0.2
UDP: 8484 -> 8484
00:01:29:611776: nat44-ei-ha
nat44-ei-ha: 0 events from 10.99.0.2
^^^^^^^^ 报文到了,但一个会话事件都没带心跳在跑,会话事件是空的。
原因是备机没有配地址池。同步过来的会话引用了外部地址 203.0.113.1, 备机不认识这个地址,于是把整条会话丢掉 —— 不报错,不计数,静默丢弃。
给备机补上同一个地址池,立刻就通了:
bash
vppctl nat44 ei add address 203.0.113.1 # 在备机上执行这是 HA 排错的第一检查项
"两边状态都正常但就是不同步" —— 先对比两边的地址池:
bash
./labctl vppctl ha show nat44 ei addresses # nat1
ssh chenzhong@192.168.49.182 \
'docker exec clab-natha-nat2 vppctl show nat44 ei addresses' # nat2两边必须完全一致。 少一个地址,用到那个地址的会话就全部同步不过去, 而且完全没有告警。
验证:端口映射必须逐条一致
配好之后,让 h1 建 6 条会话:
text
── 3) 建 6 条会话 ──────────────────────────
nat1(主)会话数:6
nat2(备)会话数:6
✓ 会话已同步到备机但会话数一致还不够。真正决定切换能不能无感的,是端口映射是否逐条相同:
text
── 4) 关键:端口映射是否逐条一致 ─────────────
nat1 的 内网端口→外部端口:
45001 58301
45002 41464
45003 52471
45004 38378
45005 40001
45006 39084
nat2 的 内网端口→外部端口:
45001 58301
45002 41464
45003 52471
45004 38378
45005 40001
45006 39084
✓ 两边的端口映射完全一致为什么"一致"才是重点
如果备机只知道"有这么一条会话",却自己重新分配了外部端口, 那么切换之后外网发回来的包目的端口对不上,连接照样断。
只有映射逐字节相同,切换才是无感的 —— 外网侧根本察觉不到对端换了一台设备。
同步协议
同步走 UDP,端口就是你配的那个(示例里是 8484),由一个专门的 graph node 处理:
text
00:05:49:442756: nat44-ei-ha
nat44-ei-ha: N events from 10.99.0.1几个参数:
| 参数 | 含义 | 建议 |
|---|---|---|
refresh-interval <秒> | 主机多久推一次会话刷新 | 生产建议 5~10 秒。太短占带宽,太长丢的会话多 |
path-mtu <字节> | 同步报文的分片上限,默认 512 | 同步链路 MTU 大时可以调大,减少报文数 |
两个手工命令:
bash
# 强制全量重同步(备机刚上线、怀疑不同步时用)
vppctl nat44 ei ha resync
# 清空 HA 状态
vppctl nat44 ei ha flushresync 不是万能的
实验里发现:如果会话是在备机配好地址池之前建立的, resync 也推不过去 —— 那些会话在备机侧依然会被丢弃。
所以正确的上线顺序是:先把备机完全配好,再让流量上主机。 反过来会留下一批永远同步不了的"僵尸会话",直到它们自己老化。
这一篇只做了 HA 的一半
必须说清楚:这一篇只验证了会话同步,没有验证故障切换。
一套能真正用的 NAT 高可用,除了会话同步还需要:
text
✓ 本篇已验证 会话表实时同步,端口映射逐条一致
○ 下一篇补上 虚拟 IP(VIP)—— 主备共用一个网关地址
○ 下一篇补上 VRRP —— 检测故障并自动漂移 VIP
○ 下一篇补上 切换时已建立连接的实际存活率
✗ 仍未覆盖 BFD 联动(做到亚秒级切换)
✗ 仍未覆盖 双主(split-brain)防护会话同步单独存在是没有意义的
备机把所有会话都学到了,但内网主机的默认网关写的还是主机的地址 —— 主机一挂,流量就停在那儿,备机再"知情"也没用。
下一篇用 VRRP 把地址漂移这一半补上, 并用一组对照实验证明:两半都在,切换时连接一次都不断; 少任何一半,切换即断。
ED 有对应功能吗
没有。对比两个插件的命令族:
bash
vppctl nat44 ei ha ?text
nat44 ei ha failover nat44 ei ha failover <ip4-address>:<port> [refresh-interval <sec>]
nat44 ei ha flush nat44 ei ha flush
nat44 ei ha listener nat44 ei ha listener <ip4-address>:<port> [path-mtu <path-mtu>]
nat44 ei ha resync nat44 ei ha resyncnat44-ed 下没有任何 ha 子命令。
所以如果你的需求里有"NAT 切换时已建立的连接不能断",那就只能用 EI。 这不是权衡,是硬约束 —— 哪怕你更想要 ED 的端口利用率和 twice-NAT。
小结
| 解决什么 | 主备切换时已建立的连接不断 |
| 配置顺序 | 备机(含地址池)→ 主机 listener → 主机 failover → 主机业务 |
| 坑一 | 主机也需要本地 listener,否则 show ... ha 显示 disabled |
| 坑二 | 备机地址池必须和主机一致,否则会话静默丢弃且无计数 |
| 验证要点 | 不只看会话数,要比对端口映射是否逐条一致 |
| 同步协议 | UDP,refresh-interval 控制频率,path-mtu 控制分片 |
| ED 有吗 | 没有。这是选 EI 的硬理由 |
下一篇:完成 HA:VRRP 与真实切换 —— 把另一半补上。