Skip to content

负载均衡映射

静态映射是一对一:一个公网端口对应一台内网服务器。 这一篇讲一对多 —— 同一个公网端口,按权重分流到一组后端。

它适合什么、不适合什么

先把预期摆正。这不是要取代 LVS、HAProxy 或云上的四层负载均衡器:

text
  ✓ 适合                                  ✗ 不适合
  ──────────────────────────────────      ────────────────────────────────
  两三台后端,想省一台设备                  需要健康检查(后端挂了自动摘除)
  后端数量稳定、很少变                      后端频繁上下线
  已经有 VPP 在做网关,顺手加个分流          需要按 URL / Header 分流(那是七层)
  对 pps 有要求,不想多一跳                 需要连接数均衡而不是哈希均衡

最关键的短板是没有健康检查。 VPP 只按权重分流,不会探测后端死活。 后端宕了,落到它身上的连接就是失败 —— 这一点必须在选型时想清楚。

配置

应用配置

bash
./labctl reset base
./labctl apply base 06
bash
vppctl nat44 add load-balancing static mapping \
  protocol tcp external 203.0.113.1:8080 \
  local 10.10.0.11:9000 probability 50 \
  local 10.10.0.12:9000 probability 50

所有后端必须写在同一条命令里

只给一个 local 会被直接拒绝:

text
nat44 add load-balancing static mapping: at least two local must be set

看上去 VPP 还提供了一个单独加后端的子命令:

bash
nat44 add load-balancing back-end protocol tcp \
    external 203.0.113.1:8080 local 10.10.0.12:9001 probability 25

但在 VPP 26.06 上,无论加还是删、带不带 vrf 0,它都返回:

text
nat44 add load-balancing back-end: Mapping or back-end not exist.

即使那条映射明明就在 show nat44 static mappings 里。所以实际操作时, 改后端列表的唯一可靠方式是整条映射删掉重建

bash
vppctl nat44 add load-balancing static mapping <原参> del
vppctl nat44 add load-balancing static mapping <新参>

这意味着调整后端会打断已有会话,做变更时要选时间窗口。

映射建好后:

bash
./labctl vppctl base show nat44 static mappings
text
NAT44 static mappings:
 TCP external 203.0.113.1:8080
  local 10.10.0.11:9000 vrf 0 probability 50
  local 10.10.0.12:9000 vrf 0 probability 50

验证分流

跑自检

bash
./labctl verify base 06

自检连 20 次,靠「你是谁」服务回话里的主机名判断落到了谁身上。

text
── 2) 连 20 次,看分流 ──────────────────────
          9 h1
         11 h2
✓ 两个后端都收到了流量,分流生效

分布不均是正常的,样本量要够

这里有个很容易误判的地方。后端是按报文五元组哈希选的,不是轮询。 样本少的时候偏差会大得吓人 —— 实测数据:

text
  连接次数    h1    h2      偏差
  ────────   ────  ────    ──────────────
     12       10     2     严重偏斜
     20        9    11     接近了
     20       15     5     又偏了
     60       32    28     基本收敛

如果你上线后连了十几次发现"全落在一台上",先别急着报 bug, 把样本量加到几十上百次再看。

权重不是精确配额

probability 50 / 50 表达的是期望,不是保证。哈希决定了每一条具体的流去哪, 只有在流足够多时才会逼近设定的比例。

想要精确的连接数均衡,需要的是有状态的负载均衡器,不是哈希分流。

affinity:让同一个客户端粘住同一个后端

很多应用有会话状态(购物车、登录态、WebSocket),要求同一个客户端的多次连接 落到同一台后端。加 affinity <秒数>

bash
vppctl nat44 add load-balancing static mapping \
  protocol tcp external 203.0.113.1:8080 \
  local 10.10.0.11:9000 probability 50 \
  local 10.10.0.12:9000 probability 50 \
  affinity 60

效果非常明显。同样连 20 次:

text
── 3) 打开 affinity,看会话保持 ──────────────
  affinity 60:同一个客户端在 60 秒内粘在同一个后端上
         20 h1
✓ 20 次全部落在同一个后端 —— affinity 生效

── 4) 关掉 affinity,确认能切回去 ─────────────
         15 h1
          5 h2
text
  ┌──────────────┬──────────────────────────┐
  │ 配置          │ 20 次连接的落点            │
  ├──────────────┼──────────────────────────┤
  │ 无 affinity   │  9 h1   11 h2            │
  │ affinity 60   │ 20 h1                    │
  │ 再关掉        │ 15 h1    5 h2            │
  └──────────────┴──────────────────────────┘

affinity 的代价

粘性和均衡是矛盾的。affinity 打开后:

  • 均衡度下降 —— 大客户后面藏着几千个用户时,这几千个全压在一台后端上
  • 后端故障影响面变大 —— 粘在故障后端的客户端会持续失败,直到 affinity 超时
  • 超时时间要权衡 —— 太短起不到保持作用,太长则故障恢复慢

选值时想清楚"我要保持多久":Web 会话通常几分钟够了, 没必要设成一小时。

其他可用选项

负载均衡映射支持和普通静态映射一样的修饰符:

bash
nat44 add load-balancing static mapping protocol tcp|udp \
    external <addr>:<port> \
    local <addr>:<port> [vrf <table-id>] probability <n> \
    [local ... probability ...]... \
    [twice-nat|self-twice-nat] \
    [out2in-only] \
    [affinity <timeout-seconds>] \
    [del]
选项用途
twice-nat源地址也改写,见下一篇。后端路由不指向 NAT 时必需
out2in-only只对入方向生效,后端主动出去时不用这条映射
vrf <id>后端在指定 VRF 里,多租户场景

后端权重不必相同

probability 是相对权重,不必加起来等于 100:

bash
local 10.10.0.11:9000 probability 70 \
local 10.10.0.12:9000 probability 30

新机器性能强就给高一点。灰度发布时也可以先给新版本 5,观察没问题再调大 —— 但记得每次调整都要删掉重建,会断已有连接。

排错

全落在一台后端上

先加大样本量到 60 次以上。仍然全在一台,检查是不是不小心带了 affinity

bash
./labctl vppctl base show nat44 static mappings

某台后端完全收不到流量

映射里的地址端口写对了吗?后端服务真的在监听吗?先在后端本机自测:

bash
ssh chenzhong@192.168.49.182 \
  'docker exec clab-natbase-h2 nc -w 2 127.0.0.1 9000'

改了后端列表但不生效

back-end 子命令在 26.06 上不可用(见上文)。必须整条删掉重建。 确认一下你的 del 命令参数和当初 add 的完全一致 —— 参数对不上就删不掉。

小结

命令nat44 add load-balancing static mapping protocol tcp external A:P local B:Q probability N local ...
后端数至少两个,且必须写在同一条命令里
分流方式五元组哈希,probability 是期望权重不是精确配额
会话保持affinity <秒>,代价是均衡度下降、故障影响面变大
改后端只能整条删掉重建,会断已有会话
最大短板没有健康检查,后端挂了不会自动摘除

下一篇:twice-NAT —— 源和目的一起改,以及它治不了的发夹弯。

实验环境基于 netlab + containerlab + VPP 26.06