一、现网故障背景
某运营商数据中心部署了一套基于DPDK的软件交换机。
承担业务:
- EVPN VXLAN Gateway
- IPv4/IPv6 Routing
- ACL Filtering
- Telemetry
- Service Chaining
硬件:
| 项目 | 配置 |
|---|---|
| CPU | Intel Xeon Platinum 8480+ |
| NIC | Intel E810 100G |
| DPDK | 23.11 |
| PMD Core | 48 |
上线验收:
95Mpps
稳定运行。
运行半年后:
业务规模增长。
Flow数量:
200万
↓
1800万
开始出现:
95Mpps
↓
87Mpps
↓
81Mpps
↓
74Mpps
同时:
RTT P99
0.8ms
↓
3.5ms
↓
6.4ms
二、第一轮排查
检查CPU:
top
结果:
PMD Core
100%
全部跑满。
检查网卡:
rte_eth_stats_get()
结果:
imissed = 0
ierrors = 0
rx_nombuf = 0
正常。
RSS:
48 Queue
均衡
正常。
ACL:
Lookup稳定
正常。
FIB:
DIR24_8
正常
正常。
NUMA:
本地内存命中率正常
正常。
所有传统分析方向全部失败。
三、一个奇怪现象
使用:
perf stat
分析。
发现:
Instructions
基本不变
但:
Cycles
持续增长
表现为:
| 时间 | Cycles/Packet |
|---|---|
| 初始 | 132 |
| 一个月 | 147 |
| 三个月 | 168 |
| 六个月 | 213 |
说明:
CPU执行的代码没变。
但等待时间增加了。
四、DPDK中的Prefetch机制
DPDK经典代码:
for (i = 0; i < nb_rx; i++) {
rte_prefetch0(
rte_pktmbuf_mtod(
pkts[i + 4],
void *
)
);
process_packet(pkts[i]);
}
核心思想:
提前加载未来数据
如下图:




五、很多人忽略的一件事
实际上:
DPDK有两套预取系统。
第一套:
Software Prefetch
即:
rte_prefetch0()
第二套:
Hardware Prefetcher
由CPU自动完成。
Intel CPU中:
包含:
L1 Stream Prefetcher
L2 Stream Prefetcher
Adjacent Line Prefetcher
Spatial Prefetcher
六、为什么开始失效
初始部署时:
流量模式:
大流
长连接
为主。
访问模式:
mbuf
↓
mbuf
↓
mbuf
↓
mbuf
连续。
CPU可以预测:
下一块数据在哪里
于是:
Hardware Prefetch成功率极高。
七、业务变化
半年后:
新增:
微服务
API Gateway
Telemetry
流量变成:
海量短流
访问模式变成:
mbuf1
↓
flowA
mbuf2
↓
flowX
mbuf3
↓
flowB
mbuf4
↓
flowY
访问地址:
完全随机。
八、Prefetch开始失效
CPU预取器本质上是:
预测系统
擅长:
连续访问
例如:
0x1000
0x1040
0x1080
0x10C0
但不擅长:
0x1000
0x8F34000
0x34000
0xFFF000
于是:
Hardware Prefetch命中率下降。
九、第二层放大效应
交换机中:
典型路径:
Packet
↓
ACL
↓
FIB
↓
Neighbor
↓
Statistics
每一步:
都会访问:
不同内存区域
当Flow数量达到:
1800万+
时。
这些对象:
远大于LLC
CPU开始频繁等待:
DRAM
返回。
十、Perf证据
分析:
perf top
发现:
热点函数:
fib_lookup()
没变。
但:
backend stalls
显著增加。
统计:
Frontend Bound
8%
Backend Bound
47%
六个月后:
Frontend Bound
9%
Backend Bound
71%
十一、为什么CPU仍然100%
因为:
PMD:
while (1)
{
rte_eth_rx_burst();
process();
rte_eth_tx_burst();
}
永不休眠。
CPU利用率:
100%
不变。
但:
大量时间:
等待内存
而非:
执行指令
十二、关键突破
进一步分析:
perf mem
发现:
大量访问:
flow entry
neighbor entry
stats entry
均呈:
随机访问
模式。
CPU预取器完全失效。
如下图:





十三、真正根因
完整链路:
Flow增长
↓
访问随机化
↓
Hardware Prefetch失效
↓
DRAM访问增加
↓
Backend Stall增加
↓
Cycles/Packet增加
↓
PPS下降
十四、为什么传统监控发现不了
因为:
不会出现:
丢包
不会出现:
RSS失衡
不会出现:
NUMA错误
不会出现:
Queue拥塞
系统看起来:
完全健康
实际上:
CPU流水线已经大量停顿。
十五、优化方案
方案一:Flow对象重排
原来:
Flow
Neighbor
Stats
分散存储。
改:
Flow + Neighbor
紧邻存储。
减少随机访问。
方案二:冷热分离
热点字段:
struct fast_path_flow
冷数据:
struct flow_metadata
拆分存储。
方案三:扩大Prefetch距离
原来:
prefetch(i+4)
改:
prefetch(i+8)
提高隐藏延迟能力。
方案四:批量查找
原来:
lookup(packet)
改:
lookup(32 packets)
提高访问局部性。
十六、优化效果
优化前:
| 指标 | 数值 |
|---|---|
| PPS | 74M |
| Backend Bound | 71% |
| Cycles/Packet | 213 |
| RTT P99 | 6.4ms |
优化后:
| 指标 | 数值 |
|---|---|
| PPS | 96M |
| Backend Bound | 31% |
| Cycles/Packet | 136 |
| RTT P99 | 0.9ms |
如下图展示CPU缓存层次与访问延迟差异:





核心知识点总结
1
DPDK性能问题不一定来自算法。
也可能来自:
访问模式
2
CPU 100%不代表CPU在干活。
可能在:
等待内存
3
DPDK存在两套预取系统:
Software Prefetch
Hardware Prefetch
4
Flow规模增长会改变内存访问模式。
5
随机访问会让Hardware Prefetch失效。
6
现代100G交换机很多瓶颈来自:
Memory Wall
而不是:
Compute Wall
7
真正应该关注的是:
Cycles Per Packet
Backend Stall
Memory Latency
而不仅仅是:
CPU利用率

664

被折叠的 条评论
为什么被折叠?



