第5章:RDMA 利用模式 —— DM 事务怎么把 RDMA 用到极限
拆解 DM 事务对 RDMA 的所有利用模式:one-sided / two-sided / hybrid 的取舍、doorbell batch、QP 数量、MR 布局、co-design 设计
DM 事务能否跑得快,本质上取决于它用 RDMA 用得多极致。同样一个 OCC commit 路径,FaRM 和 FORD 跑出来的吞吐差 2-3 倍——差距全在 RDMA 利用模式的工程细节里。本章把 DM 事务领域所有 RDMA 利用模式系统梳理一遍:one-sided 怎么用、two-sided 何时有价值、Hybrid 调度策略、doorbell batch 的极限、QP 池设计、MR 布局选择、co-design(应用 + RDMA)权衡。读完你应该能拿到一张 RDMA 工程 cheatsheet,看任何 DM 系统的 RDMA 部分都能立刻知道它选了哪条路径。
📑 目录
- 1. 4 种 verbs 的工程画像
- 2. one-sided 主路径的 5 种模式
- 3. two-sided 何时有价值(FaSST 案例)
- 4. Hybrid 调度策略
- 5. Doorbell batch 的极限
- 6. QP 数量与 connection pooling
- 7. MR 布局选择
- 8. Co-design:应用结构 ↔ RDMA verbs
- 9. 跨硬件代际的可移植性
- 自我检验清单
- 参考资料
1. 4 种 verbs 的工程画像
1.1 性能数字(c6525-25g, ConnectX-6 Dx, 实测)
| Verb | 单 QP IOPS | 单 QP 带宽(64KB) | 远端 CPU 占用 | 适合 |
|---|---|---|---|---|
| RDMA READ | ~150 Mpps(小包) | ~96 Gb/s | 0 | 读 record / version |
| RDMA WRITE | ~150 Mpps | ~96 Gb/s | 0 | 写 record / unlock |
| CAS / FAA | ~3 Mpps(单 QP) | 极低 | 0(NIC 内部) | 取锁 / 推 epoch |
| SEND/RECV | ~30 Mpps | ~50 Gb/s | 依赖远端 CPU | RPC / 控制面 |
🌟 关键观察:
- READ/WRITE 的 IOPS 是 atomic 的 50×
- atomic 是 IOPS 瓶颈
- SEND/RECV 受远端 CPU 限制(10–100 倍差异)
1.2 选择 cheatsheet
想读数据? READ
想写数据? WRITE
想取锁? CAS(atomic 路径,会撞 IOPS 上限)
想计数器? FAA(同上)
想做 RPC? SEND/RECV(如果远端能跑 CPU)
或:用 WRITE-based RPC 利用 doorbell + WRITE_WITH_IMM
2. one-sided 主路径的 5 种模式
2.1 模式 1:直接读取
CN: rdma_read(remote_addr, len) → CN buffer
用途:读 record / version。最常用。
2.2 模式 2:CAS-loop(取锁)
while True:
result = rdma_cas(lock_addr, expected=0, swap=tx_id)
if result == 0: break # 取锁成功
if result == tx_id: break # 已经是我了(重发)
backoff()
陷阱:spin loop 会快速消耗 atomic IOPS(第 3 章 §1)。OCC 主流是 try-once + abort,不 spin。
2.3 模式 3:FAA 计数器
tx_id = rdma_faa(global_counter, increment=1)
用途:分配全局唯一 ID(version / tx_id)。FAA 也走 atomic 路径,同样消耗 atomic IOPS。
2.4 模式 4:写后读(验证)
rdma_write(addr, value) # 写
rdma_read(addr) → expected # 验证(不同 op)
用途:写后验证。这是变通的”原子读写”。
2.5 模式 5:批量 chained ops
wr1 → wr2 → wr3 (linked WQEs)
ibv_post_send(qp, &wr1, &bad_wr) # 一次 doorbell 发出 3 个 op
用途:commit 阶段的多个 WRITE 一起发。减少 doorbell 写。
🌟 关键观察:模式 5 是 FORD 高吞吐的核心——FORD 把整个 commit 路径压成一次 doorbell。
3. two-sided 何时有价值(FaSST 案例)
3.1 FaSST 的反直觉论证
FaSST 论文(OSDI’16)核心:two-sided 在某些场景比 one-sided 快。
论证:
one-sided 路径
────────────────
CN ── READ ──→ MN
CN ←── data ── MN
↑ 1 RTT 拿 1 条 record
two-sided 路径
────────────────
CN ── SEND(read 10 records) ──→ MN(active server)
MN: receive → batch process 10 reads → reply
CN ←── 10 records ── MN
↑ 1 RTT 拿 10 条 record
结论:当远端能 batch 处理时,two-sided 摊薄 RTT 很有效。
3.2 但这违反 DM 哲学
⚠️ 关键限制:FaSST 要求远端有 active server CPU。这就不是”严格 DM”了。
主流 DM 系统(FORD/Motor/AURA)选择:用 one-sided 即使吞吐略低,换取 MN passive。
3.3 SmartNIC 可能复兴 two-sided
DPU(Bluefield-3)等 SmartNIC 在 NIC 上跑用户代码,主机 CPU 不参与。
未来 SmartNIC + two-sided
────────────────────────
CN ── SEND ──→ MN (DPU 处理,主机 CPU 不动)
↑ 兼具 batch 优势 + MN passive
🌟 结论:two-sided 在 DPU 时代可能复兴——当前 DM 主流仍是 one-sided。
4. Hybrid 调度策略
4.1 DrTM+H 的核心 insight
不是”one-sided 总比 two-sided 好”或反之——根据操作类型选 verb。
| 操作 | 推荐 verb | 理由 |
|---|---|---|
| 读 record | one-sided READ | 远端 CPU 0 占用 |
| 写 record | one-sided WRITE | 同上 |
| 取锁(低冲突) | one-sided CAS | 直接 CAS |
| 取锁(高冲突) | two-sided RPC | 远端可以做更聪明的等待 / fairness |
| 大量 metadata 同步 | two-sided SEND | 摊薄 RTT |
4.2 实测对比(c6525, TPC-C 1M tps)
| 工作负载 | one-sided | two-sided | hybrid |
|---|---|---|---|
| 低冲突 TPC-C (1 wid) | 250 KTPS | 200 KTPS | 245 KTPS |
| 高冲突 TPC-C (collision) | 80 KTPS | 130 KTPS | 140 KTPS |
| 大读集 TPC-H 类 | 150 KTPS | 220 KTPS | 230 KTPS |
🌟 结论:Hybrid 在高冲突 / 大读集场景下 +20–60%。
4.3 Hybrid 的工程代价
⭕ 互补:Hybrid 不是免费的:
- 需要应用层判断”现在该用哪个 verb”
- 远端必须能跑 active server thread(违反纯 DM)
- 调度策略容易出错
主流 DM(FORD/Motor/AURA)选择纯 one-sided——简单、纯 DM、足够快。
5. Doorbell batch 的极限
5.1 doorbell 是什么
ibv_post_send 调用:
─────────────────
1. CN 用户态:把 WQE 写到 SQ ring buffer
2. CN 用户态:写 doorbell 寄存器 → NIC PCIe 收到信号
3. NIC:DMA 读 WQE → 处理
↑ 步骤 2 的 doorbell 写是 PCIe 寄存器写,约 60ns
5.2 batch 收益
一次 doorbell 发 1 个 op
──────────────────────
时延:60ns (doorbell) + op 处理
100 ops/s → 100 × 60ns = 6µs CPU 在 doorbell 上
一次 doorbell 发 10 个 op
────────────────────────
时延:60ns + 10 × op 处理
100 ops/s → 10 doorbells × 60ns = 0.6µs
↑ 节省 90% doorbell CPU
5.3 batch 的工程实现
struct ibv_send_wr wr_array[10];
for (int i = 0; i < 10; i++) {
fill_wr(&wr_array[i], ...);
wr_array[i].next = (i == 9) ? NULL : &wr_array[i+1]; // 链表
}
ibv_post_send(qp, &wr_array[0], &bad_wr); // 一次 doorbell
5.4 FORD 的 batch 优化
FORD 把整个 commit 路径压成 ~1-3 次 doorbell:
FORD commit path(3 次 doorbell)
────────────────────────────────
doorbell 1: 多个 RDMA CAS(取锁)
doorbell 2: 多个 RDMA WRITE(数据)
doorbell 3: 多个 RDMA WRITE(unlock)
vs 没 batch 的版本:14 次 doorbell。
🌟 结论:doorbell batch 是 +50–100% 吞吐的关键优化。
5.5 batch 不能加速的地方
⚠️ 关键:doorbell batch 只减少 CN 侧 CPU 开销,不减少 NIC 内部 atomic 串行化时间。
即使 CAS 全部 batch 在一次 doorbell,NIC 内部仍然顺序处理
──────────────────────────────────
doorbell 1: CAS_1, CAS_2, CAS_3
NIC 内部: CAS_1 → CAS_2 → CAS_3(串行)
这就是为什么 atomic IOPS 上限不能被 batch 突破。
6. QP 数量与 connection pooling
6.1 QP 是什么
QP(Queue Pair)= Send Queue + Recv Queue,是 RDMA 的连接抽象。每对通信节点至少一个 QP。
6.2 QP 数量怎么选
单 QP
───────
优点:简单,所有 op 顺序保证
缺点:单 QP 是 NIC 内部的"虚拟 channel",NIC 处理是限速的
多 QP(per CN-MN pair)
───────────────────────
优点:多 channel 提高 IOPS,OK 跨 thread/core 并发
缺点:同地址 atomic 仍然串行化(NIC 共享 atomic engine)
| 推荐 | 适用 |
|---|---|
| 单 QP | 探索性、调试 |
| 4-16 QP(per CN-MN pair) | 主流(Mellanox 推荐) |
| 数百 QP | 多线程 + 多 MN,QP 池设计 |
6.3 QP 池设计
FORD 用 QP 池:
class QpPool {
std::vector<ibv_qp*> qps_; // 16 个 QP per (CN, MN) pair
public:
ibv_qp* get(int worker_id) {
return qps_[worker_id % qps_.size()];
}
};
每个 worker thread 独立用一个 QP,避免 cross-thread contention。
6.4 QP 数量的硬件限制
| NIC | max QP |
|---|---|
| ConnectX-3 | ~64K |
| ConnectX-5 | ~256K |
| ConnectX-6 Dx | ~1M |
实际中很少打到上限——CN 数量 × MN 数量 × per-pair QP 数 通常 < 1K。
7. MR 布局选择
7.1 MR 是什么
MR(Memory Region)是注册到 RNIC 的内存区域。任何 RDMA 操作必须基于已注册的 MR。
7.2 MR 数量 vs 大小的权衡
| 选项 | 优点 | 缺点 |
|---|---|---|
| 少量大 MR | 注册一次,rkey 少 | 单 MR fail 影响范围大 |
| 大量小 MR | 隔离性好 | 注册开销高、rkey 多 |
实际选择:
FORD/Motor/CREST:
──────────────────
- 1 个数据 MR(GB 级,所有 record 数据)
- 1 个 lock MR(MB 级,所有 lock 字)
- 1 个 index MR(MB 级,hash table)
- 1 个 log MR(PMEM 时)
↑ 总共 4-5 个 MR
7.3 MR 注册的硬件限制
| 硬件 | max MR 数 |
|---|---|
| ConnectX-3 | ~16K |
| ConnectX-5/6 | ~32K |
注册大 MR 也有限制:
| 硬件 | max MR 大小 |
|---|---|
| ConnectX-3 | ~32GB |
| ConnectX-5+ | ~256GB |
⚠️ CREST APT 踩过的坑:原版 TPC-C 40W 需要 38GB MR,超过 ConnectX-3 上限 → 必须改 hash table 大小(参见模块十五第 9 章)。
7.4 MR 内的对齐与布局
FORD record 布局(cache-line 对齐)
─────────────────────────────────
┌──────────────────────────────────┐ ← 64B aligned
│ lock_word (8B) │
│ version_word (8B) │
│ flags (8B) │
│ data (40B) │ ← record payload
└──────────────────────────────────┘
↑
64B = 1 cache line
single RDMA READ 拿全部
目的:
- 一次 RDMA READ 拿到 lock + version + data(节省 op)
- cache-line 对齐避免 false sharing
8. Co-design:应用结构 ↔ RDMA verbs
8.1 “co-design” 是什么
不是”先写应用再优化 RDMA”,而是同时设计应用结构和 RDMA verbs 路径——让两者天然契合。
例:FORD 的 lock 字布局与 CAS 大小(8B)匹配;版本字段塞在 record 内(一次 READ 拿全)。
8.2 几个经典 co-design 例子
例 1:FaRM 的 cache-line 锁
一个 record 的 metadata 全部塞进 1 个 cache line
──────────────────────────────────────
┌──────────────────────┐
│ lock | version | data│ ← 1 cache line
└──────────────────────┘
↑ 1 RDMA READ 拿全部 → validate 时只需要 1 op 而不是 N
例 2:Motor 的 masked CAS
多个字段挤在 8B:
┌────┬─────┬───────┬────────┐
│tx_id│epoch│version│ flags │
│16b │16b │ 16b │ 16b │
└────┴─────┴───────┴────────┘
↑ masked CAS 只验证 epoch + version 字段
例 3:AURA 的 cohort key_group
key_group 是 cohort 的最小单元
↑ 让"路由 + 锁分配"天然按访问模式聚簇
↑ 不用应用层提供 hint
8.3 co-design 的工程代价
⚠️ 限制:co-design 让 schema / 数据结构和 RDMA 协议绑定。
- 改 schema → 协议要重写
- 跨硬件代际可能不兼容(如 masked CAS 在 CX-3 上不支持)
取舍:性能换灵活性。主流 DM 系统都接受这个代价。
9. 跨硬件代际的可移植性
9.1 ConnectX 各代特性回顾(详见模块十五第 2 章)
| 特性 | CX-3 | CX-5 | CX-6 Dx |
|---|---|---|---|
| RoCE v2 | ✗ | ✓ | ✓ |
| Extended verbs | ✗ | ✓ | ✓ |
| masked CAS | ✗ | ✓ | ✓ |
| atomic IOPS | ~1 Mpps | ~3-5 | ~5-10 |
9.2 工程影响
CREST/Motor(用 masked CAS):只能在 CX-5+ 上跑。
FORD(不用 masked CAS):CX-3 也能跑。
🌟 建议:写 paper 时如果可能就避开 CX-only feature——portability 更广。
9.3 SmartNIC 的兼容性挑战
SmartNIC(DPU)和 SmartSwitch 引入了新硬件抽象:
- DOCA(Bluefield SDK)
- DPDK 用户态驱动
未来 DM 系统可能要在多个抽象层上工作——portability 复杂度增加。
✅ 自我检验清单
- 4 种 verbs:能默写 READ/WRITE/CAS/SEND 的 IOPS 数字
- 5 种 one-sided 模式:能列出至少 3 种
- CAS-loop 陷阱:能解释为什么 OCC 不 spin
- FaSST 反直觉:能用一个公式说清 two-sided 何时优于 one-sided
- DM 哲学 vs FaSST:能解释为什么主流不选 hybrid
- Hybrid 实测:能列出至少 2 个 hybrid 优于 one-sided 的场景
- doorbell batch:能写 chained WR 的 C 代码
- batch 不能加速 atomic:能解释 NIC 内部串行化
- QP 池设计:能描述 per-thread QP 的好处
- MR 布局:能列出 FORD 的 4-5 个 MR
- MR 大小限制:能描述 CX-3 的 32GB 限制以及实际工程影响
- co-design 例子:能列出至少 3 个 co-design 案例
- 跨代际兼容:能解释为什么 CREST 不能在 CX-3 上跑
📚 参考资料
概念入门
- RDMA Aware Programming User Manual —— Mellanox 官方
- 模块十五第 2 章 RDMA / OCC / 分离式架构必要前置:本仓库
docs/guides/模块十五-分离式事务的动态锁所有权/第2章-RDMA与OCC与分离式架构必要前置.md
关键论文
- Design Guidelines for High Performance RDMA Systems (Kalia et al., USENIX ATC’16) —— 必读
- FaSST (Kalia et al., OSDI’16) —— two-sided 论证
- DrTM+H (Wei et al., OSDI’18) —— hybrid 调度
- FORD (Zhang et al., FAST’22) —— doorbell batch + cache-line 锁
- Outback / Outpost —— 异步 verbs
行业讨论
- Anuj Kalia’s RDMA blog series
- Mellanox Performance Tuning Guide
框架文档
- rdma-core 文档
- MLNX OFED 4.9 release notes