Lesson 12: DPDK Ring HTS模式
课程目标
学习DPDK Ring的HTS(Head-Tail Sync)同步模式,理解其适用场景,掌握Peek API的使用方法。
知识点
1. HTS模式简介
HTS(Head-Tail Sync):头尾同步模式,一种序列化的多生产者/多消费者同步方式。
核心特点:
- 同一时刻只允许一个线程操作Ring(像排队)
- 避免MP/MC模式中的tail等待问题
- 特别适合虚拟机/容器环境
2. 适用场景
✅ 虚拟机/容器环境 - 资源被调度器动态分配 ✅ 过度提交场景 - 线程数 > CPU核心数 ✅ 需要Peek API - 先看内容再决定是否取出 ✅ 需要稳定延迟 - 更可预测的延迟表现
3. 性能特点
| 场景 | HTS vs MP/MC |
|---|---|
| 物理机 | 慢10-20% |
| 虚拟机/容器 | 快30-50% |
4. Peek API
Peek API:HTS模式独有的特性,允许"先看再取"。
使用场景:
- 条件过滤消息
- 优先级队列实现
- 根据消息内容决定是否处理
代码结构
目录结构
12-hts-ring/
├── CMakeLists.txt # CMake构建配置
└── hts_ring.c # HTS Ring示例代码测试内容
示例代码包含4个测试:
- Test 1: HTS性能测试
- Test 2: HTS vs MP/MC性能对比
- Test 3: Peek API演示(HTS独有)
- Test 4: 多线程HTS测试
核心API
创建HTS Ring
c
#include <rte_ring.h>
/* 创建HTS模式Ring */
struct rte_ring *ring = rte_ring_create(
"hts_ring",
1024, // Ring大小(必须是2的幂)
rte_socket_id(), // NUMA socket
RING_F_MP_HTS_ENQ | // HTS生产者
RING_F_MC_HTS_DEQ // HTS消费者
);使用通用API
HTS Ring使用标准的Ring API:
c
/* 入队 */
unsigned sent = rte_ring_enqueue_burst(ring, objs, n, NULL);
/* 出队 */
unsigned received = rte_ring_dequeue_burst(ring, objs, n, NULL);Peek API(两阶段操作)
c
void *obj;
/* 阶段1:Peek - 查看队头元素(不移除) */
uint32_t n = rte_ring_dequeue_bulk_start(ring, &obj, 1, NULL);
if (n != 0) {
/* 阶段2:决定是否取出 */
if (should_accept(obj)) {
/* 确认出队 */
rte_ring_dequeue_finish(ring, 1);
// 处理obj...
} else {
/* 取消出队(元素保留在Ring中) */
rte_ring_dequeue_finish(ring, 0);
}
}编译和运行
编译
bash
# 在项目根目录
mkdir -p build
cd build
cmake ..
make hts_ring运行
bash
# 基础运行(单核)
sudo ./bin/hts_ring -l 0 --no-pci
# 多核运行(推荐,用于测试4)
sudo ./bin/hts_ring -l 0-3 --no-pci预期输出
╔════════════════════════════════════════════════╗
║ DPDK Ring HTS Mode Demo ║
║ (Head-Tail Sync Mode) ║
╚════════════════════════════════════════════════╝
╔═══════════════════════════════════════════════╗
║ Test 1: HTS Mode Performance ║
╚═══════════════════════════════════════════════╝
✓ Created HTS ring (size=1024)
Performance:
Operations: 1000000
Time: 0.082 seconds
Throughput: 12.20 Mpps
╔═══════════════════════════════════════════════╗
║ Test 2: HTS vs MP/MC Comparison ║
╚═══════════════════════════════════════════════╝
✓ Created HTS and MP/MC rings
Testing HTS mode...
Testing MP/MC mode...
┌────────────┬──────────┬──────────────┐
│ Mode │ Mpps │ Relative │
├────────────┼──────────┼──────────────┤
│ HTS │ 12.20 │ 100.0% │
│ MP/MC │ 14.35 │ 117.6% │
└────────────┴──────────┴──────────────┘
💡 HTS is 15.0% slower (normal on physical machines)
╔═══════════════════════════════════════════════╗
║ Test 3: Peek API (HTS Only) ║
╚═══════════════════════════════════════════════╝
✓ Created HTS ring for Peek API test
✓ Enqueued 20 messages with different priorities
Using Peek API to filter messages (only accept priority 0 and 1):
──────────────────────────────────────────────────────────
[Peek #1] Seq=0, Priority=0 → ✓ Accept
[Peek #2] Seq=1, Priority=1 → ✓ Accept
[Peek #3] Seq=2, Priority=2 → ✗ Reject (stop)
──────────────────────────────────────────────────────────
Peek API Results:
Peeked: 3 messages
Accepted: 2 messages (priority 0-1)
Rejected: 1 messages (priority 2)
Remaining in ring: 17 messages
💡 Peek API allows conditional dequeue:
- Look at the message first
- Decide whether to take it or leave it
- Only supported by HTS and SP/SC modes
╔═══════════════════════════════════════════════╗
║ Test 4: Multi-thread HTS Test ║
╚═══════════════════════════════════════════════╝
✓ Created HTS ring for multi-thread test
Available lcores: 4
[Lcore 1] Worker started
[Lcore 2] Worker started
[Lcore 3] Worker started
[Lcore 1] Worker finished (enqueued 100)
[Lcore 2] Worker finished (enqueued 100)
[Lcore 3] Worker finished (enqueued 100)
✓ All 3 workers completed
Final ring count: 0
╔════════════════════════════════════════════════╗
║ All Tests Completed ║
╚════════════════════════════════════════════════╝
Key Takeaways:
1. HTS is 10-20% slower than MP/MC on physical machines
2. HTS is faster in VM/container environments (overcommit)
3. Peek API is unique to HTS and SP/SC modes
4. HTS provides more predictable latency测试解析
Test 1: HTS性能测试
测试HTS模式的基本性能,通过100万次入队/出队操作测量吞吐量。
关键代码:
c
for (i = 0; i < TEST_COUNT / 32; i++) {
rte_ring_enqueue_burst(hts_ring, objs, 32, NULL);
rte_ring_dequeue_burst(hts_ring, objs, 32, NULL);
}Test 2: HTS vs MP/MC对比
对比HTS和MP/MC模式的性能差异。
预期结果:
- 物理机:MP/MC快10-20%
- 虚拟机/容器:HTS快30-50%
Test 3: Peek API演示
演示Peek API的条件式出队功能。
场景:根据消息优先级决定是否处理
- Priority 0-1:接受并处理
- Priority 2:拒绝并停止
核心逻辑:
c
ret = rte_ring_dequeue_bulk_start(ring, &obj, 1, NULL);
if (msg->priority <= 1) {
rte_ring_dequeue_finish(ring, 1); // 确认取出
} else {
rte_ring_dequeue_finish(ring, 0); // 取消,保留在Ring中
}Test 4: 多线程HTS测试
多个worker线程同时对HTS Ring进行入队/出队操作,验证HTS的同步正确性。
常见问题
Q1: HTS比MP/MC慢,为什么还要用?
答:在特定场景下HTS更优:
- 虚拟机/容器:HTS更快(避免tail等待)
- 需要Peek API:只有HTS和SP/SC支持
- 延迟敏感:HTS延迟更可预测
Q2: Peek API的典型应用?
答:
- 消息过滤:跳过不感兴趣的消息
- 优先级队列:实现复杂的调度策略
- 条件处理:根据系统状态决定是否处理
- 流量控制:根据负载动态调整接收
Q3: 如何选择Ring模式?
决策树:
是否单生产者单消费者?
└─> 是:SP/SC(最快)
是否需要Peek API?
└─> 是:HTS
是否运行在虚拟机/容器?
└─> 是:HTS
└─> 否:MP/MC(物理机最快)Q4: Peek API的性能开销?
答:
- Peek本身开销很小
- 如果频繁"看了又不取"会影响性能
- 建议:如果大部分消息都会处理,直接用
dequeue
Q5: 可以混合使用不同模式吗?
答:不能。Ring创建时确定模式,之后不能更改。
实践练习
练习1:实现优先级队列
使用Peek API实现一个简单的优先级队列:
- 只处理高优先级消息(priority < 5)
- 低优先级消息留在队列中
练习2:性能测试
在虚拟机/容器环境中运行测试,观察HTS vs MP/MC性能差异。
练习3:条件过滤
实现一个消息过滤器:
- 使用Peek API查看消息
- 根据消息类型决定是否处理
- 统计accept/reject比例
总结
核心要点
- HTS特点:同一时刻只允许一个线程操作
- 适用场景:虚拟机/容器、需要Peek API
- 性能权衡:物理机慢10-20%,虚拟机快30-50%
- Peek API:HTS独有,实现条件式出队
选择建议
| 场景 | 推荐模式 |
|---|---|
| 单生产者单消费者 | SP/SC |
| 物理机高吞吐 | MP/MC |
| 虚拟机/容器 | HTS |
| 需要Peek API | HTS |
参考资源
下一课预告:RTS模式(Relaxed Tail Sync)- HTS的优化版本
