主题
性能真相与本实验的局限
全书从第 0 章就在警告:这套环境不能用来测性能。 最后一篇把这句话讲透 —— 为什么不能,以及如果真要测该怎么测。
顺便,这一篇里所有数字都是在本环境实测的。它们衡量的不是"VPP 能跑多快", 而是不同做法之间的相对差异,那个是有意义的。
先看一个能说明问题的数字
bash
vppctl clear runtime
# 空闲 2 秒
vppctl show runtimetext
Name State Calls Vectors Packet-Clocks Vectors/Call
af-packet-input polling 8565925 0 1.87e2 0.00两秒内调用了 856 万次,处理了 0 个包。
这就是 polling 模式:CPU 不停地问网卡"有包吗",没包也在问。 一个核就这么烧掉了。第 0 章说"polling 会吃满一个 CPU 核", 这行输出是它的量化形式。
Vectors/Call:VPP 性能的核心指标
回顾第 0 章讲的向量处理:VPP 的性能优势来自一批包共享一次代码加载。 这个"一批"有多大,就是 Vectors/Call。
text
Vectors/Call = 1 每次只处理一个包,完全没有批处理收益
Vectors/Call = 256 满载,i-cache 加载成本被摊薄到极致实测本环境在约 10 万 pps 下:
text
Name State Calls Vectors Packet-Clocks Vectors/Call
ip4-input active 36699 254342 3.62e2 6.93
nat44-ed-in2out active 36531 200006 6.15e2 5.47只有 5~7。 离 256 差得很远。
原因就在 AF_PACKET:它是 Linux 的通用抓包接口,逐帧交付 (我们还特意选了 TPACKET v2 来降时延,见第 0 章), 一次 poll 拿不到多少包,自然攒不出大批次。
真实部署用 DPDK 或 AF_XDP 时,一次可以从网卡队列里批量取走上百个包, Vectors/Call 能上到几十甚至逼近 256。这是本环境和生产最本质的性能差距。
这个指标怎么用
调优 VPP 时,先看 Vectors/Call:
text
持续接近 1 → 收包路径有问题,或者流量本来就稀疏
上升到几十 → 批处理在起作用,性能正常
接近 256 → 满载,该考虑加 worker 了它比 pps 更能说明"VPP 有没有在好好干活"。
快路径 vs 慢路径:47 倍的差距
第 1 章说过慢路径比快路径贵得多。具体贵多少, show runtime 的 Packet-Clocks 列给了答案。
实验 A:同一条流打 20 万包(全部命中会话,走快路径)
text
vector rates in 1.0608e5
ip4-input 36699 254342 3.62e2 6.93
nat44-ed-in2out 36531 200006 6.15e2 5.47实验 B:2 万条新流(每个包都新建会话,全部走慢路径)
text
vector rates in 2.9189e4
nat44-ed-in2out 15052 20001 1.42e3 1.33
nat44-ed-in2out-slowpath 15051 20000 7.03e3 1.33并排看:
text
┌────────────────┬──────────────────┬──────────────────┐
│ │ 已建立的流 │ 每包新建会话 │
├────────────────┼──────────────────┼──────────────────┤
│ 吞吐 │ 106,080 pps │ 29,189 pps │
│ in2out 时钟 │ 615 clocks/包 │ 1,420 clocks/包 │
│ slowpath 时钟 │ — │ 7,030 clocks/包 │
│ 单包总成本 │ 615 │ 8,450 │
│ Vectors/Call │ 5.47 │ 1.33 │
└────────────────┴──────────────────┴──────────────────┘
新建会话比转发已有会话贵 8450 / 615 ≈ 14 倍
实际吞吐掉到 27%评估 NAT 设备要看 CPS,不是 bps
这组数据解释了一个反直觉的事实:NAT 设备的瓶颈通常不是带宽,是新建会话速率。
text
一条视频流:几百 Mbps,但只有一条会话 → NAT 几乎没有负担
一万个用户刷网页:带宽不大,但每秒新建几万条会话 → NAT 压力巨大所以选型和压测时,CPS(Connections Per Second)比吞吐更关键。 只测 iperf 打满带宽,测不出 NAT 的真实瓶颈。
Vectors/Call 在慢路径场景下掉到 1.33 也印证了这一点 —— 建会话是串行化的工作,批处理帮不上忙。
polling vs interrupt:4 倍时延差
本实验底座默认开 polling,代价是吃满一个核。这个代价换来了什么?
bash
vppctl set interface rx-mode host-eth1 polling # 或 interrupt
# ping 30 次text
┌────────────┬──────────────────────────────┬──────────────┐
│ 收包模式 │ RTT min/avg/max (ms) │ CPU │
├────────────┼──────────────────────────────┼──────────────┤
│ polling │ 0.077 / 0.088 / 0.193 │ 吃满一个核 │
│ interrupt │ 0.330 / 0.424 / 0.597 │ 空闲时几乎为零 │
└────────────┴──────────────────────────────┴──────────────┘
平均时延差 4.8 倍adaptive 模式在 af_packet 上不可用
bash
vppctl set interface rx-mode host-eth1 adaptivetext
set interface rx-mode: unable to set rx-mode on interface host-eth1 queue-id 4294967295.adaptive(低负载中断、高负载轮询)在支持的驱动上是很好的折中, 但 AF_PACKET 不支持。
这也解释了第 3 章 HA 底座为什么刻意不开 polling —— 两台 VPP 各吃一个核,4 核的实验机扛不住,而 HA 实验不看时延。
为什么这些数字不能当生产参考
三层损耗叠在一起:
text
┌──────────────────┬────────────────────────┬──────────────────────────┐
│ 环节 │ 本实验 │ 生产部署 │
├──────────────────┼────────────────────────┼──────────────────────────┤
│ 收包路径 │ AF_PACKET(内核拷贝) │ DPDK / AF_XDP(零拷贝) │
│ 批处理效率 │ Vectors/Call ≈ 5~7 │ 可达几十到 256 │
│ 链路 │ veth + bridge │ 物理网卡 │
│ 内核参与 │ 每个包都过内核 │ 绕过内核 │
│ worker 线程 │ 1(vpp_main) │ 多个,绑核,NUMA 亲和 │
│ CPU │ 与其他容器共享 4 核 │ 独占核,隔离中断 │
└──────────────────┴────────────────────────┴──────────────────────────┘差距不是百分之几十,是数量级。本环境跑 10 万 pps, 同样的 VPP 配 DPDK 和多 worker 在物理机上跑到千万 pps 级别是常态。
千万别拿本教程的数字去做容量规划
本环境的数字只有一个用途:比较不同配置之间的相对差异。
text
✓ 有意义 慢路径比快路径贵 14 倍
✓ 有意义 polling 比 interrupt 时延低 4.8 倍
✓ 有意义 开 affinity 后负载均衡分布从 9:11 变成 20:0
✗ 无意义 "VPP NAT 能跑 10 万 pps"
✗ 无意义 "NAT 转发时延 0.088ms"真要测性能该怎么做
环境
text
· 物理机,不要虚拟化嵌套
· 独占 CPU 核,isolcpus + VPP 的 corelist-workers 绑定
· 关闭超线程,或者至少不要把 worker 和它的 HT 兄弟核一起用
· NUMA 亲和:网卡、内存、worker 在同一个 NUMA 节点
· DPDK 或 AF_XDP,不要 AF_PACKET打流工具
text
· TRex(Cisco 开源)—— 事实标准,能精确控制 CPS 和流数量
· DPDK-pktgen
· 商业测试仪(IXIA / Spirent)
不要用 iperf / netperf 测 NAT —— 它们建立少量长连接,
测出来的是快路径吞吐,完全掩盖了 CPS 瓶颈。必须分开测的两个指标
text
① 吞吐(已建立会话)
少量长流打满带宽,看 pps 和 bps
→ 衡量快路径效率
② 新建会话速率(CPS)
大量短流,每条只有几个包
→ 衡量慢路径效率,这通常才是真瓶颈
两者的结果可能差一个数量级,只报一个是不完整的。要一起记录的辅助数据
bash
vppctl show runtime # Vectors/Call 和 Packet-Clocks
vppctl show nat44 summary # 会话数水位
vppctl show errors # 有没有丢包压测时 Vectors/Call 应该上去
如果压到很高 pps 但 Vectors/Call 还是个位数,说明瓶颈不在 VPP, 而在收包路径或者打流端。这时候增加 worker 也没用。
本环境能可靠测量的东西
说了这么多不能测的,也说说能测的 —— 这些都是行为而非性能, 不受环境损耗影响:
text
✓ 功能正确性 地址改成了什么、会话怎么建的
✓ 相对差异 A 配置 vs B 配置,谁快谁慢
✓ 状态开销的量级 慢路径贵多少倍
✓ 错误行为 什么条件下丢包、丢在哪个节点
✓ 配额与限制 端口块大小、会话上限、每用户配额
✓ 插件交互 谁和谁冲突、怎么冲突
✓ 弱网下的行为 用 nsim 注入时延和丢包(见下一篇)整本教程做的都是这类观察。这也是为什么所有实验的自检脚本 断言的都是现象("源地址变成了 X"、"计数器出现了 Y"), 而不是数值("时延小于 1ms")—— 后者换台机器就不成立了。
小结
| 核心指标 | Vectors/Call,本环境 5~7,生产可达几十到 256 |
| 慢路径成本 | 8450 clocks vs 615,约 14 倍;吞吐掉到 27% |
| 选型要看 | CPS 而不是 bps,NAT 瓶颈通常在新建会话 |
| polling 代价 | 时延低 4.8 倍,代价是吃满一个核 |
| 本环境瓶颈 | AF_PACKET + veth + 共享 CPU,比生产差数量级 |
| 能可靠测的 | 功能、相对差异、状态开销量级、错误行为 |
| 不能测的 | 任何绝对性能数字 |
还有一件本环境能做的事
上面说的都是"不能测性能"。但有一类实验它其实能做得很好: 注入可控的网络损伤,观察时延和丢包对应用的影响。
下一篇用 nsim 插件把链路变差, 测出"2% 丢包让 TCP 吞吐掉 96%"这类结论 —— 并且据此重新审视本篇的性能数字。
全书到此结束
七章走下来,从"一个包被改了哪几个字节"到"运营商级 NAT 怎么做溯源":
text
第 0 章 上手 为什么 VPP · 搭环境 · 第一个 NAT
第 1 章 原理 改了什么 · 会话表 · EI vs ED · 端口与老化
第 2 章 NAT44-ED 伪装 · 地址池 · 静态映射 · identity · LB · twice-NAT · VRF · 超时
第 3 章 NAT44-EI 行为画像 · 会话高可用 · 选型
第 4 章 CGN DET44 算法映射 · 可追溯性
第 5 章 IPv6 过渡 NAT64 · NAT66 · 464XLAT
第 6 章 其他翻译器 PNAT · CNAT
第 7 章 排错与性能 读 trace · 故障速查 · 性能真相 · 弱网模拟四个实验底座、十四个可复现的实验步骤, 文档里贴的每一段命令输出都是从这套环境里真实抓下来的。
如果只带走三件事,我希望是这三件:
一、会话表是理解一切的钥匙。 会话键里有什么字段,决定了 EI/ED 的全部差异、 决定了端口能不能复用、决定了 P2P 能不能打洞、决定了删会话要不要带 external-host。
二、show trace 值得成为肌肉记忆。 它能回答"这个包经历了什么"这个问题, 而这个问题的答案往往就是故障的答案。内核转发给不了你这份逐跳清单。
三、计数器干净不等于没问题。 七章里遇到的最难查的五个故障, 共同点都是 NAT 计数器一片干净 —— 因为问题不在 NAT 逻辑, 而在路由、邻居解析或插件残留上。遇到这种情况, 第一反应应该是"把注意力从 VPP 移开"。
想继续深入
本教程覆盖的是 VPP NAT 的使用。再往下走的方向:
- VPP API —— CLI 只适合调试,生产用 govpp / vppapi 编程配置
- 多 worker 调优 —— handoff、RSS、会话在 worker 间的分布
- 写插件 —— VPP 的 graph node 模型对自定义转发逻辑非常友好
- Calico/VPP —— 看 cnat 在真实控制面驱动下怎么工作