跳到主要内容
分离式事务的动态锁所有权

第2章:RDMA / OCC / 分离式架构必要前置

看 AURA 论文之前要打牢的概念地基:RDMA verbs 与 atomic 语义、ConnectX 各代行为差异、OCC 三阶段、CN/MN 数据流、masked CAS

RDMA OCC Disaggregated Memory ConnectX masked CAS 前置

第 1 章把”为什么动态锁所有权是必须的”立住了。但要看懂 AURA 论文与所有相关工作,还需要一组更基础的概念:RDMA verbs 怎么调用、atomic 在不同 NIC 上有什么差异、masked CAS 是干嘛的、OCC 三阶段在 DM 架构里到底走哪几步。本章把这些”看 paper 之前必须会”的基础打牢——读完你应该能徒手画出 OCC commit 路径的 RDMA op 序列,并且看到 IBV_EXP_WR_EXT_MASKED_ATOMIC_CMP_AND_SWP 不会一头雾水。

📑 目录


1. RDMA verbs 速通:READ / WRITE / CAS / FAA

1.1 verbs 的角色:用户态直接对网卡下指令

RDMA 把”发数据”这件事从内核态完全移到用户态。verbs(即 libibverbs 暴露的接口)是一组让用户进程直接对网卡(RNIC)下指令的 API。一次 RDMA op 不需要陷入内核、不需要拷贝、远端 CPU 也不参与——这是它和 TCP 最本质的差异。

   用户态                                内核态
   ──────                                ──────
   ibv_post_send(qp, &wr, ...) 

        │ (mmap 过的 doorbell page)

   ┌──────────────┐
   │ RNIC TX ring │  写一个 WQE(Work Queue Element)
   └──────────────┘

        │ 直接 DMA 到 NIC 寄存器

   网卡硬件


   RoCE / InfiniBand 包发出

🌟 核心结论verbs 调用是 user-space → NIC 一步直达。这是为什么 RDMA 单 QP 能轻松跑 10M+ ops/sec——内核根本没参与。

1.2 四个最常用的原语

DM 事务系统几乎只用这四个 op:

原语字节大小远端 CPU 参与在 OCC 中的角色
IBV_WR_RDMA_READ任意(最大 1GB)读 read set / version / lock 状态
IBV_WR_RDMA_WRITE任意(最大 1GB)写 write set / unlock
IBV_WR_ATOMIC_CMP_AND_SWP(CAS)8B 固定是(NIC 内部)取锁 / 推进 epoch
IBV_WR_ATOMIC_FETCH_AND_ADD(FAA)8B 固定是(NIC 内部)计数器 / 序列号

重点观察

  • READ / WRITE 是 one-sided:发起方只要知道远端的 (addr, rkey),就能直接读写远端内存,远端 CPU 完全无感
  • CAS / FAA 也是 one-sided 但走特殊路径:远端 NIC 内部要做”读-比较-写”,必须仲裁。这就是第 1 章提到的 atomic IOPS 瓶颈来源。
  • 8B 限制不是任意决定:RoCE/IB 协议头里 atomic 字段就是 8B 宽,硬件层面没有更宽的 atomic 支持。

1.3 一次 ibv_post_send 调用的完整结构

// 一次 RDMA CAS(取锁)的最简版
struct ibv_sge sge = {
    .addr   = (uintptr_t) local_buf,   // 本地接收 original 8B 的 buffer
    .length = 8,
    .lkey   = local_mr->lkey,          // 本地 MR 的 lkey
};

struct ibv_send_wr wr = {
    .wr_id      = txn_id,
    .sg_list    = &sge,
    .num_sge    = 1,
    .opcode     = IBV_WR_ATOMIC_CMP_AND_SWP,
    .send_flags = IBV_SEND_SIGNALED,    // 完成后产生 CQE
    .wr.atomic = {
        .remote_addr = remote_lock_addr,
        .compare_add = 0,               // expected = 0(unlock)
        .swap        = my_tx_id,        // 想换上的值
        .rkey        = remote_rkey,
    },
};

struct ibv_send_wr *bad_wr = NULL;
int ret = ibv_post_send(qp, &wr, &bad_wr);

关键参数:

  • wr_id:用户自定义 64-bit ID,在 CQE(completion queue entry)里返回,用来识别”这次完成的是哪个 op”
  • IBV_SEND_SIGNALED:要求完成后产生 CQE。不加这个 flag 就是”silent send”,看不到完成信号
  • compare_add:CAS 的 expected 值
  • swap:CAS 成功时写入的新值
  • rkey:远端 MR 的访问 key(注册 MR 时返回,必须事先交换)

1.4 doorbell batch:一次写多个 WQE

把多个 op 串在一起 post,内核一次性 ring doorbell。这是 FORD / CREST 的高吞吐套路:

struct ibv_send_wr wr_array[8];
for (int i = 0; i < 8; i++) {
    fill_wr(&wr_array[i], ...);
    wr_array[i].next = (i == 7) ? NULL : &wr_array[i+1];
}
ibv_post_send(qp, &wr_array[0], &bad_wr);  // 一次 doorbell

🌟 关键事实:doorbell 写代价高(PCIe 寄存器写),把多个 op 摊到一次 doorbell 是 RNIC 高吞吐的关键。但对 atomic 没有帮助——atomic 在 NIC 内部仍然串行化。

1.5 one-sided vs two-sided 的分水岭

维度one-sided(READ/WRITE/CAS/FAA)two-sided(SEND/RECV)
远端 CPU 参与(必须 post 一个 RECV)
编程模型类似共享内存类似消息传递
DM 系统选择首选仅在协议必需时使用
典型用例读 record / 取锁 / 写数据控制面 RPC / OwnerRpc

互补:RDMA SEND/RECV 不是”慢”,FaSST 论文(OSDI’16)甚至论证过 two-sided 在某些场景比 one-sided 快——因为远端 CPU 可以做更聪明的 batching。但 DM 事务的核心承诺就是”远端 CPU 不参与”,所以 90% 路径都要走 one-sided。

🧠 关键洞察one-sided 让 MN 变成”被动内存”——这是 disaggregation 的本钱。每次你想引入一个需要 MN CPU 参与的协议,先问自己”能不能用 CAS + READ 替代”。


2. ConnectX 代际差异:从 mlx4 到 mlx5/6

2.1 三代 NIC 的关键参数对比

维度ConnectX-3ConnectX-4/5ConnectX-6 Dx
协议IB / RoCE v1IB / RoCE v2IB / RoCE v2
链路速率56 Gb FDR100 Gb EDR100/200 Gb HDR
内核驱动mlx4_coremlx5_coremlx5_core
用户态库libmlx4libmlx5libmlx5
atomic CAS Mpps(单 QP)~1.0~3.0~3.0
atomic CAS Mpps(多 QP 聚合)~1.0–2.6~4–5~5–10
max_atomic_arg0 / 83232
extended verbs(ibv_exp_*不支持(OFED 4.9 也只是模拟)支持支持
IBV_EXP_QP_INIT_ATTR_CREATE_FLAGS不支持(errno=95)支持支持
masked CAS不支持支持支持
RoCEv2 gid_idx不适用(IB only)通常 3通常 3
IB gid_idx000

数据来源:APT c6220 (ConnectX-3) + CloudLab c6525-25g (ConnectX-6 Dx) 实测,2026-04 / 2026-05。

2.2 mlx4 vs mlx5 驱动栈:分裂的代价

ConnectX-3 用 mlx4 驱动栈,从 ConnectX-4 起切到 mlx5——两个驱动几乎完全不兼容:

   ConnectX-3 软件栈                ConnectX-5+ 软件栈
   ──────────────────              ──────────────────
   user app                         user app
      │                                │
   libibverbs                       libibverbs
      │                                │
   libmlx4 (provider)               libmlx5 (provider)
      │                                │
   /dev/infiniband/uverbs0          /dev/infiniband/uverbs0
      │                                │
   mlx4_ib (kernel)                 mlx5_ib (kernel)
      │                                │
   mlx4_core                        mlx5_core

🌟 工程后果

  1. 同一个 RDMA 程序在 ConnectX-3 和 ConnectX-5 上跑,很多 verbs 调用结果不同(特别是 extended verbs)。
  2. APT 集群只有 ConnectX-3 → 上面只能跑 mlx4 驱动 → CREST/Motor 用 ibv_exp_* 的部分会报错或行为异常。
  3. 装 OFED 4.9(最后一版兼容 ConnectX-3 的 MLNX OFED)也只能解决一部分问题,剩下的需要改代码。

2.3 atomic 在不同代上的真实行为

实测命令:

# server (任一节点)
ib_atomic_bw -d $DEV -i 1 -F -D 30 -A CMP_AND_SWAP

# client (另一节点)
ib_atomic_bw -d $DEV -i 1 -F -D 30 -A CMP_AND_SWAP $SERVER_IP
平台设备单 QP Mpps多 QP Mpps备注
APT c6220mlx4_0 (CX-3 56Gb IB)2.59~2.6(饱和)多 QP 不能聚合
CloudLab c6525-25gmlx5_2 (CX-6 Dx 100Gb RoCE)~3.0~5.8多 QP 部分聚合

🧠 关键洞察:CX-3 上 多 QP 不能聚合 atomic——因为 NIC 内部只有一个 atomic engine。CX-6 Dx 有多个 engine,能部分聚合。这意味着同样的 OCC 协议,CX-3 上 retry storm 出现得早得多——这是 AURA 在 APT 上做”跨硬件 portability + 放大 retry storm”对照实验的物理基础。

2.4 gid_idx:IB vs RoCEv2 的隐藏陷阱

gid_idx 是 GID 表项索引,决定了 QP 用什么”地址”做寻址。这个值代际之间不一样

设备协议推荐 gid_idx命令验证
ConnectX-3 mlx4IB0show_gidscat /sys/class/infiniband/mlx4_0/ports/1/gids/*
ConnectX-6 Dx mlx5RoCEv2 (IPv4)3show_gids mlx5_2 1 看 RoCE v2 行
ConnectX-6 Dx mlx5RoCEv2 (IPv6)通常 1看 GID 类型

常见踩坑:把 c6525 上的 gid_idx=3 配置直接搬到 APT,QP 建立成功但 send 后包根本到不了对端。原因是 APT 是真 IB 不是 RoCE。

🌟 首次连通排错口令:先 show_gids 看实际表项,确认 GID type 是 IB 还是 RoCE v2,再调 ib_dev_idgid_idx

2.5 OFED 4.9 / rdma-core 的选择策略

场景选什么命令
跑 CREST / Motor(需要 ibv_exp_*MLNX OFED 4.9./mlnxofedinstall --user-space-only --skip-distro-check --without-depcheck
跑 FORD(只用 standard verbs)Ubuntu 22.04 inbox rdma-coreapt install librdmacm-dev libibverbs-dev
跑 perftest任意OFED 自带或 apt install perftest

APT 集群必踩的坑

  1. MLNX OFED 4.9 不再发布 Ubuntu 22.04 包(只到 ubuntu20.04)→ 需 --skip-distro-check 强装
  2. 它会想装 mstflint(依赖 libssl1.1,22.04 没有)→ 安装后 dpkg -P --force-all mstflint,让 22.04 自己的 mstflint 上
  3. inbox 包 libfabric1 libucx0 libopenmpi3 想拉回 inbox ibverbs-providers → 必须 apt-mark hold 住 OFED 包,再批量 purge

3. masked CAS 与 extended atomic:什么是 CREST 的依赖

3.1 为什么标准 CAS 不够用

标准 RDMA CAS 是”全 8B 比较 + 全 8B 替换”。但 OCC 的写锁字往往这样布局:

   8 字节 lock word
   ┌─────────┬─────────┬───────────────┐
   │ owner_id│ epoch   │  flags / bits │
   │  (16b)  │  (16b)  │     (32b)     │
   └─────────┴─────────┴───────────────┘

问题:你只想 CAS owner_id 字段,不关心 epochflags——但标准 CAS 会要求整个 8B 完全匹配,否则失败。这意味着如果有任何并发 op 改了 flags,你的 CAS 就误判失败了。

3.2 masked CAS:带掩码的原子比较交换

Mellanox extended verbs 提供:

IBV_EXP_WR_EXT_MASKED_ATOMIC_CMP_AND_SWP

它在标准 CAS 的基础上加了两个掩码:

  • compare_mask:哪些 bit 参与比较
  • swap_mask:哪些 bit 实际被替换

语义

原子地:
  if (memory & compare_mask) == (compare_value & compare_mask):
      memory = (memory & ~swap_mask) | (swap & swap_mask)
      return (true, original_memory)
  else:
      return (false, original_memory)

🍎 直觉比喻:标准 CAS 是”必须整个房子都跟我描述的一致才换”,masked CAS 是”只要客厅的家具一致就换客厅的家具”。

3.3 CREST / Motor 怎么依赖它

CREST 的 OCC commit 路径要在一次 atomic 里同时:

  1. 检查”锁字段”未被占
  2. 检查”版本字段”是某个值
  3. 替换”锁字段”为自己的 tx_id
  4. 不动”版本字段”

四步合一,没有 masked CAS 就要拆成”普通 CAS + 单独 READ 验证”——多一次 RDMA RTT,且引入 race window。

3.4 ConnectX-3 不支持的工程影响

我们在 APT 上实测:

[Logger] ASSERTION FAILED: opcode IBV_EXP_WR_EXT_MASKED_ATOMIC_CMP_AND_SWP
         not supported on this device
[Scheduler.cc:121] abort()
[bench_runner exit code 134 (SIGABRT)]

🌟 后果:CREST 和 Motor 完全无法在 ConnectX-3 上跑——这不是配置问题,是硬件能力缺失。FORD 只用 standard CAS,能跑通。

应对策略

  • 跨硬件 portability claim 用 FORD 而不是 CREST
  • AURA 主体实验留在 ConnectX-6 上(本来 atomic 就更紧)
  • APT 上 retry storm 实验用 FORD + 自制 micro benchmark 验证趋势

4. OCC 三阶段模型与 DM 架构对应

4.1 模型回顾

OCC(Optimistic Concurrency Control)把事务分三阶段执行:

   阶段 1:Read phase
   ─────────────────
   读所有需要的 record,记下版本号 → read set
   本地修改写集(不提交)→ write set
   
   阶段 2:Validation
   ──────────────────
   重新检查 read set 的版本号
   - 一致 → 进入 commit
   - 不一致 → abort + retry
   
   阶段 3:Commit
   ──────────────
   取所有写集的锁(CAS)
   写入新数据 + 新版本
   解锁

4.2 在 DM 架构上每阶段走什么 op

阶段主要 op工作位置atomic 压力
ReadRDMA READ ×NCN0
ValidateRDMA READ ×read_set(再读版本)
Commit (acquire)RDMA CAS ×write_set
Commit (data)RDMA WRITE ×write_set
Commit (release)RDMA WRITE ×write_set(写回 unlock)

🌟 关键观察只有 commit 的 acquire 阶段消耗 atomic IOPS。read / write / release 都是 normal RDMA op。这就是为什么”优化 atomic”是切中要害的。

4.3 为什么 DM 系统不用 2PL

维度2PL(两阶段锁)OCC
取锁时机事务开始commit 阶段
冲突时等待(阻塞)abort + retry
远端 CPU 参与必须(锁状态机 + 唤醒)不必须(CAS)
死锁可能不可能(无等待)

🧠 关键洞察2PL 的”等待”语义需要远端有线程持有锁、被唤醒——这违反 disaggregation 原则。OCC 用 CAS 把”取锁”做成 1 次原子写,远端无感知。所以所有 DM 事务系统都用 OCC

4.4 SI / SR 隔离级别在 DM 上怎么实现

级别DM 实现代表系统
Read Committed读最新已提交版本(工业数据库默认,DM 论文不常用)
Snapshot Isolation (SI)MVCC + 拉版本表Motor
Serializable (SR)单版本 + 严格 OCCFORD

互补:FORD 单版本系统跑 SR;Motor 多版本系统支持 SI 也支持 SR(设 iso_level=2)。AURA 设计上不限定,但实验默认用 SR(最难,最能反映 atomic 压力)。


5. CN / MN 数据流图谱

5.1 CN 侧持有什么

   CN (Compute Node)
   ──────────────────
   ┌─────────────────────────────────────┐
   │ Transaction logic                   │
   │  ↓                                  │
   │ Local working set (read/write set)  │
   │ Local hot record cache              │ ← 减少远端 READ
   │ TxnRequest queue                    │
   │ Coroutine scheduler                 │
   ├─────────────────────────────────────┤
   │ RDMA QP / CQ pool                   │
   │ MR for local buffers                │
   │ rkey 表(远端各 region 的 rkey)    │
   ├─────────────────────────────────────┤
   │ ★ AURA 增量:                       │
   │  OwnerLockTable (本地锁表)          │
   │  AffinityRouter (路由表)            │
   │  AccessGraph snapshot               │
   └─────────────────────────────────────┘

5.2 MN 侧持有什么

   MN (Memory Node)
   ──────────────────
   ┌─────────────────────────────────────┐
   │ ❶ Data region (record bytes)        │
   │    - 按 partition 布局              │
   │    - cache-line 对齐(FORD)        │
   │    - version table(Motor MVCC)    │
   ├─────────────────────────────────────┤
   │ ❷ Lock region (8B lock words)       │
   │    - 与 record 1:1 或 cache-line:1  │
   │    - CREST 用 masked field          │
   ├─────────────────────────────────────┤
   │ ❸ Index region (hash / B+tree)      │
   │    - FORD 用 PoolHashIndex          │
   │    - 索引也是 RDMA 远端拉取         │
   ├─────────────────────────────────────┤
   │ ❹ Persistent log (PMEM 时持久)      │
   ├─────────────────────────────────────┤
   │ MR + rkey 注册(CN 启动时拉取)     │
   ├─────────────────────────────────────┤
   │ ★ AURA 增量:                       │
   │   FallbackLock 区域(继续兜底)     │
   │   OwnerMap snapshot 快照副本        │
   └─────────────────────────────────────┘

5.3 关键观察:MN 是被动存储

MN 不主动做任何事

  • 不解析事务
  • 不处理冲突
  • 不维护锁状态机(只是被 CAS 覆写的 8B 字)
  • 不参与版本回收

它的 RNIC 处理 RDMA 入站包,DMA 到/从主机内存,仅此而已。这是 disaggregation 的本钱也是天花板——天花板就是第 1 章讲的 atomic IOPS。

🍎 直觉比喻:MN 是一块”放在远端的 DRAM”,CN 通过 RDMA 网卡像访问本地内存一样访问它。CN 是 CPU,MN 是 RAM——这是模块十三第 1 章的核心比喻。

5.4 AURA 改了什么、没改什么

维度原 CREST/MotorAURA
MN 数据布局不变不变
MN 锁字布局8B masked field不变(fallback 路径仍用)
MN CPU 参与不参与不参与
CN 路由随机 / 哈希AffinityRouter
CN 锁表OwnerLockTable
CN 间 RPCOwnerRpc
控制面进程Profiler / Planner / Publisher

🌟 关键事实AURA 不改 MN 的物理布局,只在 CN 侧加新结构。这意味着可以渐进部署——同一个 MN 同时服务 AURA-aware 和 legacy 客户端。


6. 一次 commit 的完整 RDMA op 序列

6.1 TPC-C NewOrder 简化路径

NewOrder 事务在 TPC-C 里读 Warehouse / District / Customer,写 District(d_next_o_id) / NewOrder / Order / OrderLine ×N / Stock ×N。简化到 1 个 OrderLine + 1 个 Stock,op 序列如下:

   Phase 1: Read
   ─────────────
   ① RDMA READ  → W[wid] (warehouse, 读 w_tax, 不写)
   ② RDMA READ  → D[wid,did] (district)
   ③ RDMA READ  → C[wid,did,cid] (customer)
   ④ RDMA READ  → S[wid,iid] (stock)
   
   Phase 2: Validate(CREST 用版本字段 inline 在 record 里)
   ──────────────────────────────────────────────────────
   ⑤ RDMA READ  → 重新读 ④ 的 version → 比对
   
   Phase 3: Commit
   ───────────────
   ⑥ RDMA CAS   → D.lock (acquire)
   ⑦ RDMA CAS   → S.lock (acquire)
   ⑧ RDMA CAS   → NO.lock (acquire, 新插入)
   ⑨ RDMA WRITE → D.data (新 d_next_o_id)
   ⑩ RDMA WRITE → S.data (新 stock 数量)
   ⑪ RDMA WRITE → NO.data (新行)
   ⑫ RDMA WRITE → D.lock = 0 (release)
   ⑬ RDMA WRITE → S.lock = 0 (release)
   ⑭ RDMA WRITE → NO.lock = 0 (release)

统计

  • READ:5 次
  • CAS:3 次(消耗 atomic IOPS
  • WRITE:6 次

关键观察:CAS 占总 op 的 21%,但消耗 100% 的 atomic 预算。这就是 atomic 优化的重要性来源——少量 op 决定整体上限。

6.2 doorbell batch 的优化空间

step ⑨⑩⑪ 的 3 次 WRITE 可以合成一次 doorbell:

struct ibv_send_wr writes[3];
writes[0].next = &writes[1];
writes[1].next = &writes[2];
writes[2].next = NULL;
ibv_post_send(qp, &writes[0], &bad_wr);  // 一次 doorbell,发出 3 个 WRITE

CAS 也可以 batch(步骤 ⑥⑦⑧),但 NIC 内部仍然是串行执行。Batch 减少 CN 的 doorbell 写代价,不减少 MN 的 atomic 处理代价

6.3 AURA 改了哪些步骤

步骤原 CRESTAURA(owner CN 命中)
① ② ③ ④ READRDMA READ → MN不变
⑤ ValidateRDMA READ → MN不变
⑥ ⑦ ⑧ CAS lockRDMA CAS → MN(消耗 atomic)OwnerLockTable 本地 lock(无 RDMA)
⑨ ⑩ ⑪ WRITE dataRDMA WRITE → MN不变
⑫ ⑬ ⑭ releaseRDMA WRITE → MNOwnerLockTable 本地 release

🌟 核心收益AURA 把 ⑥⑦⑧⑫⑬⑭ 这 6 次 RDMA op 中的 atomic CAS(3 次)变成 0 次远端 atomic——整个 commit 只剩 normal READ/WRITE。这是 AURA 解决 atomic IOPS 上限的物理路径


7. 必须知道的 5 个失败模式

OCC commit 路径上每一步都可能失败。学完它们才能看懂论文的 abort 分析章节。

7.1 失败模式 1:CAS abort

现象:步骤 ⑥ 的 CAS 返回 failure(original ≠ expected)。

原因:另一个事务先到、已经持有该锁。

处理:当前事务释放已经取得的锁,全部 abort,retry 整个事务。

if (atomic_cas_result.original != 0) {
    release_already_acquired_locks();
    return ABORT_LOCK_BUSY;
}

7.2 失败模式 2:version mismatch

现象:步骤 ⑤ 的 validate read 返回的 version 不等于 phase 1 时的 version。

原因:read set 在事务执行期间被改了。

处理:abort + retry。

🍎 直觉比喻:你在做菜时打开冰箱拿了 3 样食材,做到一半发现有人换了其中一样——你只能扔掉重做。

7.3 失败模式 3:RDMA timeout

现象:RDMA op 长时间没有 CQE。

原因:网络抖动 / 远端 RNIC 过载 / QP 状态错误。

处理:根据严重程度 retry op、retry 整个事务、或 reset QP。

7.4 失败模式 4:硬件不支持的 atomic 模式

现象:post 时返回 errno=95(EOPNOTSUPP)。

原因:NIC 不支持你用的 atomic 操作。最常见是 ConnectX-3 上跑 masked CAS

处理:不可救——只能换 NIC 或换协议。

7.5 失败模式 5:MR 边界 / rkey 失效

现象:CQE 状态是 IBV_WC_REM_ACCESS_ERRIBV_WC_LOC_PROT_ERR

原因

  • 写远端地址超出 MR 注册区域
  • 远端 MR 已经 dereg(rkey 失效)
  • 本地 buffer 不在已注册的 MR 内

处理:检查地址计算、重连 QP、重新注册 MR。

重要提示:MR 注册有数量上限(通常几千)。CREST/FORD 在 TPC-C 大规模 populate 时可能撞这个上限——APT 上踩过的坑。


✅ 自我检验清单

  • verbs 速通:能不查文档写出 ibv_post_send 一次 atomic CAS 的完整调用代码
  • one-sided vs two-sided:能解释为什么 DM 系统几乎只用 one-sided
  • doorbell batch:能解释为什么 batch 加速 WRITE 但不加速 atomic
  • 代际差异:能说出 ConnectX-3 与 ConnectX-6 Dx 至少 4 个关键差异
  • gid_idx 陷阱:能描述把 c6525 配置搬到 APT 时会发生什么
  • masked CAS:能解释 CREST 为什么不能跑在 ConnectX-3 上
  • OCC 三阶段:能徒手画 Read / Validate / Commit 三阶段在 DM 上的 RDMA op 序列
  • 2PL vs OCC:能用一句话说清为什么 DM 系统不用 2PL
  • CN / MN 数据流:能列出 CN side 与 MN side 各自持有的数据结构
  • AURA 改动范围:能描述 AURA 改了 CN 侧什么、没改 MN 侧什么
  • commit op 序列:能列出 TPC-C NewOrder 的 14 步 RDMA op
  • 失败模式:能描述至少 4 种 OCC commit 路径上的失败模式

📚 参考资料

概念入门

  • RDMA Aware Programming User Manual —— Mellanox 官方编程手册:Mellanox Docs
  • libibverbs man pages —— man ibv_post_send / man ibv_create_qp
  • 模块十三第 2 章 RDMA 通信原理与 verbs:本仓库 docs/guides/模块十三-新型互联与远程内存系统/第2章-RDMA通信原理与verbs.md

关键论文

  • Design Guidelines for High Performance RDMA Systems (Kalia et al., USENIX ATC’16)USENIX 链接 —— 单边 vs 双边 RDMA 的系统级权衡
  • FaSST (Kalia et al., OSDI’16)USENIX 链接 —— 反直觉论证:two-sided 在某些场景比 one-sided 更快
  • FaRM (Dragojević et al., NSDI’14)USENIX 链接 —— 首篇 RDMA OCC,奠定 commit 路径范式
  • FORD (Zhang et al., FAST’22)USENIX 链接 —— cache-line 对齐锁的实现,是理解 standard CAS 用法的最佳样本
  • Motor (Wu et al., OSDI’24)USENIX 链接 —— MVCC + masked CAS 的 commit 路径

行业讨论

  • NVIDIA ConnectX-6 Dx Programmer’s Reference Manual —— atomic 操作的硬件实现说明(NDA 许可)
  • Mellanox Community: Show GIDs —— show_gids 工具用法

框架文档

  • rdma-core 仓库github.com/linux-rdma/rdma-core
  • MLNX OFED 4.9 release notes:包含 ConnectX-3 兼容性最后状态
  • CREST 仓库:本路线第 8/9 章实战载体