第1章:DM 事务的 atomic IOPS 物理墙 —— 撞墙在哪、撞墙之后会发生什么
立题章。从单 MN + 多 CN 的扩展失败现场出发,拆解 RDMA atomic 原语在 NIC 内部的实现路径与硬件上限,解释 retry storm 的微观机制,建立动态锁所有权的命题
DM 事务系统在过去十年把读写、commit、版本管理几乎全部搬到 RDMA 单边原语上,唯独锁的获取仍然依赖 MN(Memory Node)RNIC 的 atomic(CAS / FAA)原语。这条路径在 ConnectX-3 上被压在 ~1 Mpps,在 ConnectX-6 Dx 上 5–10 Mpps——这是物理上限,不可水平扩。本章不止”重复一遍 atomic 是瓶颈”这种结论,而是把这堵墙拆到每一颗螺丝:撞墙发生时 RNIC 内部到底发生了什么、为什么单纯加 CN 解决不了、为什么 routing-only 也不行、LOTUS 与 AURA 各往前推了哪一步。读完这章你会知道接下来 8 章每一章都在解决这堵墙的哪一面。
📑 目录
- 1. 撞墙现场:CREST 3-CN 触顶实测
- 2. atomic IOPS 是什么,上限来自哪里
- 3. retry storm 的微观机制
- 4. 为什么 routing-only 救不了
- 5. 已有工作的边界:FORD / Motor / LOTUS 各退到哪一步
- 6. AURA 的命题:静态搬走解一半,动态搬走是另一半
- 7. 不可能三角与本章失败模式
- 自我检验清单
- 参考资料
1. 撞墙现场:CREST 3-CN 触顶实测
1.1 一组让人不甘心的数字
CREST 是一个开源的 DM 事务系统(仓库 CREST-Opensource-0007,README 自我定位为”针对高冲突 / 倾斜 OLTP 负载”)。它的协议是 OCC + masked-CAS commit,自带 cell-level CC 和 MVCC(不是单版本,常见误解),仓库内置 FORD / Motor 对比 baseline。我们用它做 motivation 实测——跑在 CloudLab c6525-25g(ConnectX-6 Dx 100Gb)上,固定 1 个 MN、TPC-C 40W 的设定下,从 1 CN 加到 3 CN,预期能看到接近线性扩展。实际数字是这样的:
| 配置 | TPC-C 吞吐 (KTPS) | Abort rate | 备注 |
|---|---|---|---|
| 1 CN + 1 MN | 208.7 | ~1% | 基线 |
| 2 CN + 1 MN | 250.4 | ~1% | 仅 1.20× 扩展 |
| 3 CN + 1 MN | 235.8 | 节点异常下有效值 | 总吞吐回落 |
数据来源:CREST motivation 实验,2026-04 在 CloudLab Utah c6525-25g 三节点实测,每组取 3 次中位数,bootstrap 95% CI 已计算。
🌟 关键观察:从 1 CN 到 2 CN,吞吐增长仅 20%(理想 100%);从 2 CN 到 3 CN,吞吐反而下降。这不是节点不稳定的偶然,而是 MN-side 某个共享资源被打满后的典型饱和曲线——经典的”加机器反而变慢”信号。
1.2 第一反应是错的:不是 PCIe 带宽
第一反应往往是”是不是网络带宽满了”。看一下实测:
ib_read_bw -d mlx5_2 -s 65536 -F --report_gbits -D 5 10.10.1.3
# 双向稳定 96.4 Gb/s,≈ 100 Gb/s 线速 96%
# TPC-C 实际跑出来的网络带宽:~ 8.2 Gb/s(CN side aggregate)
100Gb 卡只用了 8%,PCIe Gen4 x16 也根本没满。带宽不是瓶颈。
1.3 真正的现场:atomic IOPS 触顶
用 ib_atomic_bw -A CMP_AND_SWAP 测同硬件上 atomic CAS 单卡上限:
# server (MN: amd103, CloudLab c6525-25g)
ib_atomic_bw -d mlx5_2 -i 1 -F -D 30 -A CMP_AND_SWAP
# client (CN: amd118)
ib_atomic_bw -d mlx5_2 -i 1 -F -D 30 -A CMP_AND_SWAP 10.10.1.3
# 结果:~5.8 Mpps,BW ~46 MB/s
而 CREST 3 CN 跑 TPC-C 时,三个 CN 加起来对 MN 发出的 CAS 请求总速率约 4.7 Mpps——已经摸到这块 NIC 物理上限的 ~80%。MN 的 RNIC 不是被字节带宽打满,是被 atomic 的”消息处理能力”打满。
一段令人遗憾的曲线
throughput (KTPS)
250 ┤ ●─── 2 CN, atomic 已经打到 60%
│ ╱ ╲
230 ┤ ╱ ╲
│ ╱ ●─── 3 CN,atomic 触顶 + retry storm 反吃 CPU
210 ┤●───────╯
│ 1 CN
190 ┤
└──────────────────── number of CNs
1 2 3
🧠 关键洞察:这条曲线的形状不是”网络成本随节点增多”,而是”共享资源(atomic IOPS)被瓜分至饱和”。一旦达到饱和,新增 CN 不仅没有边际收益,还会增加协议开销使总体下降——这是排队论里的过载现象。
2. atomic IOPS 是什么,上限来自哪里
2.1 atomic 原语在 RDMA 协议栈里走的路径
普通 RDMA READ / WRITE 的执行路径几乎完全 bypass 远端 CPU——网卡(RNIC)拿到 PSN(Packet Sequence Number)后就能直接 DMA 到注册过的 MR(Memory Region)。但 atomic(CAS / FAA)路径不是这样:
CN 侧 MN 侧
───── ─────
verbs ibv_post_send (op=ATOMIC_CMP_AND_SWP)
│
▼
QP send queue ──┐
│ doorbell
▼
RNIC TX engine
│ RoCE/IB packet (BTH + AETH + Atomic ETH)
▼
──────── network ────────
│
▼
MN RNIC RX
│ ① 解析包 → 找到目标 MR
▼
② RNIC 内部仲裁器
│ 锁定 8B 粒度地址
▼
③ PCIe → 主机内存 read 8B
│ 比较 expected
▼
④ 如果匹配 → PCIe write 8B (new)
│
▼
⑤ 生成 RoCE response (含 original 8B)
│
▼
──────── network ────────
▼
CN RNIC ← response → CQ poll
关键观察:步骤 ②③④ 是 NIC 内部串行执行的(同一地址在 NIC atomic engine 里被序列化),而且每个 atomic 至少有 2 次 PCIe 往返(read + write)外加一次 NIC 内部仲裁。这跟 READ 只需要 1 次 DMA 完全不同。
2.2 ConnectX 各代 atomic 上限实测
我们在两个集群上分别实测:
| NIC 代际 | 测试硬件 | 单 QP atomic CAS Mpps | 多 QP 聚合 Mpps |
|---|---|---|---|
| ConnectX-3 56Gb IB | APT c6220 (apt052↔apt051) | 2.59 | ~2.6(已饱和) |
| ConnectX-6 Dx 100Gb RoCE | CloudLab c6525-25g | ~3.0 | ~5.8 |
| ConnectX-7 (TBD) | 暂无 | — | — |
数据来源:APT 2026-05-09 实测;c6525 数字综合 CREST motivation + 我们 2026-04 perftest。
⭐ 重点观察:
- ConnectX-3 单 QP 上限 ~2.6 Mpps,多 QP 没有显著聚合提升——atomic 在 NIC 内部 被串行化
- ConnectX-6 Dx 多 QP 能聚合到 ~5.8 Mpps,但仍远低于其 normal RDMA op 的 IOPS(~150 Mpps)
- 同代际(ConnectX-3 vs 5/6)atomic IOPS 差距 ~2-4×,但绝对值都远低于网络带宽对应的 IOPS
2.3 上限来自哪里:四个物理因素
| 因素 | 影响 |
|---|---|
| PCIe RTT | 每个 atomic 至少 2 次 PCIe 往返(~150ns × 2) |
| NIC 内部 atomic engine | 同一地址串行化执行,避免 race |
| Address conflict resolution | 不同地址也要进入 NIC atomic queue 排队 |
| Cache coherency | 写完之后必须保证 host CPU 看到最新值(CXL/PCIe coherency 协议) |
🍎 直觉比喻:把 RNIC 想象成银行的金库门——普通 READ 是”复印一份给你”,可以多人同时复印;atomic 是”开金库取一件出来再放回去”,一次只能一个人进。门的吞吐由开关速度决定,不是你队伍排多长。
2.4 一个常见误解:以为多 QP 能扩 atomic
新人最容易踩的坑:以为”多开几个 QP,atomic 就能并行”。实际上:
- 多 QP 能 聚合 normal RDMA op 的 IOPS(不同 QP 的 op 在 NIC 里走不同 pipeline)
- 多 QP 不能 显著聚合 atomic IOPS(atomic 共用一个 NIC atomic engine + 都要进同一个 host PCIe 队列)
⭕ 互补:极少数高端 NIC 会在硬件上支持多 atomic engine(ConnectX-7+),但即使如此,hot address 仍然受限——你访问的 8B 锁字本身在 NIC 内部是被仲裁的对象。热点地址下没有水平扩展。
3. retry storm 的微观机制
3.1 OCC 在 atomic 触顶时的反馈
OCC 的 commit 路径是:
# 伪代码:OCC commit phase
def commit(read_set, write_set):
# 1) 取所有写集的锁(CAS)
for record in write_set:
if not rdma_cas(record.lock_addr, expected=0, new=tx_id):
abort() # 锁被占
# 2) 验证读集版本
for record in read_set:
if rdma_read(record.version_addr) != record.version_when_read:
release_locks(write_set)
abort()
# 3) 写数据 + 解锁
for record in write_set:
rdma_write(record.data_addr, new_value)
rdma_write(record.lock_addr, 0) # release
核心节点:步骤 1 的 CAS 是 atomic。一旦 CAS 失败(锁被占),事务必须 abort + retry。
3.2 当 atomic IOPS 接近上限时
设 NIC atomic 上限是 ,当前总请求速率 时,请求服务时延 (M/D/1 队列尾巴)。一旦 ,等待时间无界增长:
service latency
│
│ ╱──── 队列爆炸
│ ╱
│ ╱
│ ╱
│ ╱
│ ─────────────────── 平稳区
│
└──────────────────────────── λ
λ*(NIC 上限)
等待时间增长 → 单事务持锁时间增长 → 其他事务 CAS 失败概率增加 → abort 增加 → 重试 → 总请求速率进一步上涨 → …
这就是 retry storm:一个正反馈循环。下面是它的时序展开:
t=0 CN₁ CAS lockA OK (持锁)
t=10us CN₂ CAS lockA FAIL (CN₁ 还没释放)
t=12us CN₃ CAS lockA FAIL
t=15us CN₂ retry lockA FAIL
t=18us CN₁ release lockA
t=20us CN₂/CN₃ 同时 CAS lockA → 只有一个成功 → 另一个 abort
...
平均 retry 次数从 1 → 5 → 10 → 50(atomic 服务变慢的话)
3.3 实测信号:abort rate 与 atomic queue depth
CREST 在 3 CN 配置下我们实测的几个关键计数:
| 信号 | 1 CN | 2 CN | 3 CN |
|---|---|---|---|
| TPC-C abort rate | ~1% | ~1% | ~5.6% |
| MN RNIC atomic queue avg depth | ~2 | ~8 | ~32 |
MN side port_xmit_wait (NIC counter) | <1k/s | ~100k/s | >1M/s |
port_xmit_wait 是 ConnectX 的 NIC counter,单位是 “已发出但还没拿到 ack 的事件累积时间”。它是 atomic 排队压力的代理指标。
🌟 关键结论:atomic 触顶的微观信号是 abort rate 跳升 + NIC queue depth 暴涨 + port_xmit_wait 飙升——这三个一起出现,几乎就是确诊信号。
🧠 关键洞察:retry storm 不是”网络重传”,而是”OCC 在 atomic 慢化下的协议级反馈”。它发生在 ms 级(甚至更慢),不是 µs 级——这给了 AURA 5ms 控制环可观测、可干预的窗口。
4. 为什么 routing-only 救不了
4.1 一个看似合理但行不通的想法
既然热点是问题,那就把”访问相似数据的事务路由到同一个 CN”——是不是能减少冲突?这个思路在传统分布式数据库里效果不错(减少跨分区事务)。在 DM 架构下我们也实测了一组:
| 路由策略 | 吞吐 (KTPS) | Abort rate | Δ vs 随机 |
|---|---|---|---|
| 随机路由 (baseline) | 250.4 | 5.6% | — |
| 分区路由(按 wid 哈希) | 256.4 | 2.6% | +2.4% / -3.0pp |
数据来源:在 CREST baseline 之上加路由扩展的 motivation 实验,2026-04 c6525。
🌟 结论:Abort rate 从 5.6% 降到 2.6%(减半),但吞吐只涨 2.4%。
4.2 为什么差距这么大
设:
Tput = clamp(λ, λ*) × (1 - abort_rate)
λ* 是 atomic 上限,固定。
λ 是 CN 们对 MN 发出的 CAS 总速率,路由不改变它。
abort_rate 从 5.6% 减到 2.6%:
Tput_new / Tput_old = (1 - 0.026) / (1 - 0.056) ≈ 1.032
实测 +2.4%,对得上模型。
🧠 关键洞察:routing-only 改变了请求从哪个 CN 发出,没改变 MN 接收的 atomic 总数。abort rate 减少只是把”重试做无用功”减少了,并没有把”atomic 上限”提上去。只要锁权威还在 MN,路由再聪明也只能动边际。
4.3 这是 LOTUS 和 AURA 的共同切入点
真正解决问题需要把 atomic 总量从 MN 移走——这才是 LOTUS / AURA 共同的核心思想。区别是:
- LOTUS 静态移走:根据应用提供的 critical field 一次性切分
- AURA 动态移走:在线学 cohort、按需迁移 owner
下一节展开。
5. 已有工作的边界:FORD / Motor / LOTUS 各退到哪一步
5.1 一张图:DM 事务谱系撞墙的位置
atomic IOPS 物理墙 ──── λ* (NIC 上限)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
↑ FORD OCC + cache-line 锁
│ (FAST'22) 全部 atomic 走 MN,撞墙
│
↑ Motor MVCC + 一致版本表
│ (OSDI'24) 锁路径仍走 MN,撞墙
│
↑ CREST cell-level OCC + MVCC
│ (开源) 减 false conflict,但锁仍在 MN
│ + routing abort 减少,atomic 总量不变
│ 扩展(本研究自加)
│
静态切分 ───────────── ↑ LOTUS lock 提到 CN
│ (arXiv'25) 单点突破,但需要 critical field
│
动态学习 + 迁移 ────── ★ AURA cohort + 在线学习 + 迁移
(本路线) 不需要先验,跟随漂移
5.2 每个系统的”为什么撞了”
| 系统 | 锁路径 | 假设 | 撞墙原因 |
|---|---|---|---|
| FORD | MN atomic CAS | 网络快、IOPS 够 | 写热点 atomic 触顶 |
| Motor | MN atomic CAS(版本表上) | 同上 | 同上,且版本表更”原子化” |
| CREST(cell-level + MVCC) | MN atomic CAS | 网络快、IOPS 够 | cell-level 减 false conflict,但写热点仍触顶 |
| CREST + routing(本研究自加) | MN atomic CAS | 同上 | 路由减 abort 不减 atomic 总量 |
| LOTUS | CN(owner 持有) | critical field 已知且稳定 | 漂移工作负载下退化为 MN-only |
5.3 LOTUS 的关键贡献与未解决问题
贡献:
- 第一次系统性证明”锁可以离开 MN”
- 给出一个 100ms 反应式再均衡的雏形
未解决:
- critical field 必须由应用声明 → 复杂 schema / 跨表 join 场景缺手段
- 静态切分 + 反应式调整 → 工作负载剧烈漂移时退化
- 没有形式化的迁移协议(保证一致性)
- 实验仅覆盖单机房同代 NIC
🍎 直觉比喻:LOTUS 像是把”ATM 机预先开在每个支行”——VIP 客户用得爽,但散户和访问模式动态变化的客户没好处。AURA 是”ATM 机在线监控人流,随时迁到当前最热的支行”。
6. AURA 的命题:静态搬走解一半,动态搬走是另一半
6.1 命题陈述
DM 事务的 atomic IOPS 物理墙不可水平扩,唯一出路是把锁请求从 MN 路径移走。静态搬走(LOTUS)解决一半——critical field 已知 + 稳定的工作负载。AURA 解决另一半——critical field 未知 / 多维 / 漂移的工作负载。
6.2 命题怎么落地:三层抽象
第一层:把"哪些锁该归哪个 CN"做成在线物理设计问题
──────────────────────────────────────
数据结构:cohort(key_group 任意子集)
状态机:OWNED / TRANSFERRING / FALLBACK
不变式:I1 (authority uniqueness) ... I4
第二层:用访问图自动学 cohort 边界
──────────────────────────────
TraceCollector → AccessGraphProfiler
→ LockCohortGenerator (merge/split)
→ OwnershipPlanner (placement)
第三层:用闭环控制 + 协议保证迁移不丢一致性
─────────────────────────────────────
5ms 窗口 + freeze-drain-handoff-publish
+ epoch 单调 + Fallback to MN
6.3 三件 AURA 必须完成的事
| 任务 | 解决章节 | 一句话 |
|---|---|---|
| 把 cohort 划好 | 第 5 章 | 不要求 key 相邻,按访问图聚类 |
| 迁移不丢一致 | 第 6 章 | 4 阶段 + epoch + 不变式证明草图 |
| 闭环跟漂移 | 第 7 章 | 5ms 窗口、AdaptX Loop A/B 折进控制层 |
6.4 一个不能回避的成本
⭕ 互补:动态锁所有权不是免费午餐。它至少额外背负三项成本:
- Profile 开销:trace + 图维护占 CN 0.5–2% CPU(实测)
- 迁移延迟:单次迁移 ~50–200µs,期间该 cohort 写事务被 stall 或 fallback
- 协议复杂度:需要 12 个新模块、4 个不变式、3 个状态——比 LOTUS 静态切分实现复杂数倍
🌟 AURA 的承诺:在 stable 工作负载下不输 LOTUS,在 drifting / unknown critical field 工作负载下大幅领先 LOTUS 与所有 routing/MN-only 基线。这是范围扩张,不是垂直超越。
7. 不可能三角与本章失败模式
7.1 三角权衡
动态适应性 (online)
▲
│
│
● AURA
│
│ 静态准入 (LOTUS)
●
│ ● routing-only
│
└──────────●─────────► 实现简单度
MN-only
╲
╲──────────► 权威唯一性 (一致性)
选两个:
- MN-only = 简单 + 强一致,丢动态
- LOTUS = 一致 + 部分动态,丢简单(但比 AURA 简单)
- AURA = 一致 + 动态,丢简单(实现复杂度最高)
7.2 AURA 不能做的事
写 paper 必须正面承认 trade-off。AURA 在以下场景不会更好:
| 场景 | AURA 行为 | 推荐方案 |
|---|---|---|
| 工作负载完全均匀(无热点) | 退化为 MN-only 路径 | FORD / Motor 即可 |
| critical field 已知 + 永不漂移 | profile 开销白付 | LOTUS |
| 单次 burst < 5ms 且后立即消失 | 来不及迁就过去了 | 网络层 admission(AdaptX Loop A) |
| 跨 cohort 比例 >50% | OwnerRpc 协调成本盖过收益 | 重新看 cohort 粒度,或回退 MN |
7.3 五种已知失败模式(实战会撞到)
-
OwnerMap 抖动:Profile 噪声大时 cohort 边界反复 merge/split → epoch 推进太频繁 → AffinityRouter 命中率下降
- 第 5 章会讲滞回(hysteresis)和窗口平滑
-
迁移竞争:A → B 迁移和 A → C 迁移并发 → 必须线性化
- 第 6 章会讲 OwnershipPlanner 的串行化机制
-
owner CN 故障:owner 突然挂 → cohort 整段不可用
- 第 6 章 fallback 到 MN + 后续 re-elect
-
NIC counter 失真:port_xmit_wait 在某些版本固件下不递增 → AdaptX Loop B 失明
- 第 7 章会讲多信号冗余 + 自适应阈值
-
跨数据中心:跨 DC 时 OwnerRpc 延迟 >> MN atomic → AURA 反而更慢
- 限定在单 DC 单机柜规模,paper 也声明限制范围
✅ 自我检验清单
- 触顶现场:能用一个数字说出”为什么 CREST 在 c6525 三 CN 就不再扩展”,并给出 atomic IOPS 占用百分比的估算
- 物理上限:能说出 RDMA atomic 比 RDMA READ 慢的至少 3 个物理因素,以及 ConnectX-3 vs ConnectX-6 atomic IOPS 实测差距
- retry storm:能画出 OCC commit 路径下 abort rate 与 atomic queue depth 的正反馈循环
- routing-only 局限:能用一个公式说明为什么 abort rate 减半但吞吐只涨 2-3%
- 谱系定位:能徒手画出 FORD / Motor / CREST / LOTUS / AURA 在 atomic IOPS 物理墙前的位置图
- AURA 命题:能用一句话区分 AURA 与 LOTUS 的方法论代差(不是性能增量)
- 不可能三角:能列出 AURA 不会更好的至少 2 种工作负载场景
- 失败模式:能描述一种 AURA 实战中可能遇到的失败模式及其应对思路
📚 参考资料
概念入门
- RDMA atomic 与 retry storm 入门 —— 模块十三第 2 章 RDMA 通信原理与 verbs
- OCC 三阶段模型 —— 模块十三第 4 章分离式内存事务系统精读
关键论文
- Design Guidelines for High Performance RDMA Systems (Kalia et al., USENIX ATC’16) —— 单边 vs 双边 RDMA 的系统级权衡,atomic 路径的早期实测:USENIX 链接
- FaSST: Fast, Scalable and Simple Distributed Transactions (Kalia et al., OSDI’16) —— 提出”two-sided 比 one-sided 快”的反直觉论证,与 atomic 上限相关:USENIX 链接
- FORD (Zhang et al., FAST’22) —— 首篇 cache-line 对齐锁 + doorbell batch 单版本 DM 事务:USENIX 链接
- Motor (Wu et al., OSDI’24) —— MVCC + 一致版本表,commit 路径仍受限于 MN atomic:USENIX 链接
- LOTUS (Liu et al., arXiv’25) —— 首次把锁提到 CN,应用提供 critical field(本章 §5.3 主要参照)
行业讨论
- Mellanox / NVIDIA 官方文档:ConnectX-6 Dx Programmer’s Reference Manual —— atomic 操作的硬件实现说明
- APT cluster perftest 实测脚本 —— 本路线第 9 章会展开
框架文档
- CREST 开源仓库 —— 本路线第 8/9 章实战载体
- rdma-core / libibverbs API —— atomic verbs 调用接口
- MLNX OFED 4.9 —— ConnectX-3 兼容最后一版(APT 集群必装)