第1章:DM 事务定义与领域边界 —— 它和单机/共享存储/经典分布式有什么本质区别
用 4 个区分维度(资源解耦、远端被动、单边原语、OCC 默认)把 DM 事务从单机 / 共享存储 / 经典分布式事务里切出来,建立看任何 DM 论文的领域坐标系
DM 事务是分布式事务领域过去 12 年里”最像但又最不像”的一类系统——它表面看是”分布式数据库的网络更快版本”,但底层硬件假设的差异几乎让 Spanner / Cockroach 那一整套范式在 DM 上不再适用。本章不直接进入任何论文细节,而是先把”DM 事务到底是什么、不是什么”用 4 个区分维度钉死。读完你应该能拿到一个 5 秒判别工具:看到任何新系统,问 4 个问题就能判断它是不是 DM 事务、是 DM 事务的话属于哪一支。这是后续 8 章所有深挖的基础坐标系。
📑 目录
- 1. 用一个反例开场:Spanner 不是 DM 事务
- 2. 四个区分维度
- 3. DM 事务 vs 单机数据库
- 4. DM 事务 vs 共享存储数据库(Aurora / Polar)
- 5. DM 事务 vs 经典分布式事务(Spanner / Cockroach)
- 6. 为什么”OCC + 单边原语”几乎是 DM 事务的默认范式
- 7. 5 秒判别工具:4 个问题
- 8. 领域边界外:哪些系统看起来像 DM 但其实不是
- 自我检验清单
- 参考资料
1. 用一个反例开场:Spanner 不是 DM 事务
1.1 Spanner 的硬件模型
Google Spanner 是经典分布式事务的代表。每个 Spanner 节点:
- 持有一份完整数据 partition(Paxos 副本)
- 跑应用 CPU(执行 query)
- 跑事务管理器(TrueTime + 2PC coordinator)
- 持有 SSD 存储
Spanner Node A Spanner Node B
──────────────── ────────────────
┌──────────────┐ ┌──────────────┐
│ Application │ │ Application │
│ Query Engine │ │ Query Engine │
├──────────────┤ ├──────────────┤
│ Txn Manager │ ←───→ │ Txn Manager │ 2PC + Paxos
│ (Paxos lead) │ │ (replica) │
├──────────────┤ ├──────────────┤
│ SSD storage │ │ SSD storage │
└──────────────┘ └──────────────┘
TCP / RPC
关键观察:Spanner 的两端都是 active 节点——能跑代码、能维护锁状态机、能主动 abort/commit 协议。
1.2 DM 事务的硬件模型
CN A CN B
(Compute Node) (Compute Node)
─────────────── ───────────────
┌──────────────┐ ┌──────────────┐
│ Application │ │ Application │
│ Txn logic │ │ Txn logic │
│ Local cache │ │ Local cache │
└────┬─────────┘ └────┬─────────┘
│ RDMA single-sided │
│ READ / WRITE / CAS / FAA │
▼ ▼
┌──────────────────────────────────────────────────┐
│ MN (Memory Node, passive memory + RNIC) │
│ ┌────────────────────────────────────────────┐ │
│ │ data records | lock words | version table │ │
│ │ index region | log buffer (PMEM if any) │ │
│ └────────────────────────────────────────────┘ │
│ NO application CPU. RNIC processes RDMA only. │
└──────────────────────────────────────────────────┘
关键观察:MN 完全 passive——没有应用 CPU 运行事务逻辑、没有锁状态机、没有协议参与。
1.3 这个差异不是”性能优化”
很多人第一次看 DM 事务以为是”Spanner 网络更快版本”——错。这是硬件假设的差异:
| 操作 | Spanner | DM |
|---|---|---|
| 远端取锁 | 远端线程 receive RPC → 检查状态机 → reply | NIC 直接 CAS 内存 8B 字 |
| 远端写数据 | 远端线程 receive → 验证 → 写盘 → reply | NIC DMA 到主机内存 |
| 远端 abort 协议 | 远端线程主动发 abort 消息 | MN 不知道 abort 是什么 |
| 远端持久化 | 远端 fsync | CN 必须主动确保 PMEM flush |
🌟 关键事实:DM 的协议必须只用”被动内存能支持的语义”——也就是 RDMA 单边原语 + 字节级原子操作。这是为什么很多 Spanner 思想(TrueTime、2PC、Paxos lead)在 DM 上要么不可用、要么必须重写。
🍎 直觉比喻:Spanner 像”两个能商量的银行职员”,DM 像”两个客户都对着同一个 ATM 操作,ATM 不会替任何一方做决定”。
2. 四个区分维度
要把 DM 事务从其他相邻领域里切出来,最简洁的工具是 4 个二选一的维度:
D1: 远端是否资源解耦?
────────────────────
是 → 计算节点和存储节点物理分开
否 → 计算和存储在同一节点
D2: 远端是否被动?
──────────────────
是 → 远端 NIC 处理请求,无应用 CPU 参与
否 → 远端有线程跑代码、状态机
D3: 主路径是否单边原语?
──────────────────────
是 → READ / WRITE / CAS / FAA 直接 DMA
否 → SEND/RECV 双边消息 + 远端 handler
D4: 默认并发控制是 OCC 还是 2PL?
─────────────────────────────────
OCC → 不取锁、提交时验证 + CAS
2PL → 事务开始就取锁,远端持有
只要 D1=是 + D2=是 + D3=是 + D4=OCC,就是典型 DM 事务系统。任何一个维度反过来,就脱离 DM 范式:
| D1 | D2 | D3 | D4 | 这是什么 |
|---|---|---|---|---|
| ✓ | ✓ | ✓ | OCC | DM 事务(FaRM/FORD/Motor/AURA) |
| ✓ | ✓ | ✓ | 2PL | 罕见(不可行:2PL 需要远端线程持锁) |
| ✓ | ✓ | 部分双边 | OCC | DrTM+H / FaSST 类 hybrid |
| ✓ | 否 | × | OCC | NAM-DB(NIC-attached) |
| 否 | × | × | OCC | 单机数据库 |
| ✓ | 否(active) | 否(RPC) | OCC/2PL | 共享存储(Aurora / Polar) |
| 否 | 否 | × | 2PL | 经典分布式(Spanner) |
🧠 关键洞察:四个维度构成 DM 事务的特征签名——任意一个反过来都意味着进入相邻领域。这给了你看任何新论文 5 秒定位的工具。
3. DM 事务 vs 单机数据库
3.1 单机数据库的设计前提
单机数据库(PostgreSQL / MySQL / RocksDB / DuckDB):
- 所有数据在本地内存或本地磁盘
- 锁、版本、索引都在同一进程地址空间
- 并发控制可以用任何机制(2PL / MVCC / OCC / 锁层级 / 死锁检测)
- 性能瓶颈在磁盘 IO + 锁争用
3.2 DM 改变了什么
单机数据库 DM 事务系统
────────────── ────────────────
┌──────────────┐ ┌──────────────┐
│ Application │ │ CN logic │
│ Buffer Pool │ │ Local cache │
│ Lock Manager │ ← 本地内存 └────┬─────────┘
│ Version Mgr │ │ RDMA
│ Index │ ▼
│ WAL │ ┌──────────────┐
│ ↓ │ │ MN: data + lock│
│ Disk │ │ + version │
└──────────────┘ │ + index │
└──────────────┘
性能瓶颈: 磁盘 IO 性能瓶颈: RDMA atomic IOPS
3.3 三个反直觉的 DM 设计选择
选择 1:放弃所有需要”远端代码”的设计
| 单机方案 | 在 DM 不可用 | 因为 |
|---|---|---|
| 锁等待队列(remote lock manager) | 是 | MN 不能维护队列 |
| 死锁检测器 | 是 | 需要全局视图 + 主动算法 |
| 可重入锁 | 是 | 状态机 |
| 锁升级(read → write) | 是 | 需要协议 |
选择 2:8B atomic 是唯一同步原语
单机:std::mutex / spinlock / atomic<T> for any T
DM: RDMA CAS 8B / FAA 8B(其他都不是 atomic)
🌟 后果:所有锁字必须能压进 8B。版本号 + lock holder + flags 全部塞进同一个 8B 字段——这是为什么 masked CAS 有用(可以只更新 8B 中的部分 bit)。
选择 3:放弃 buffer pool 的所有变种
单机数据库花了 30 年优化 buffer pool(LRU、CLOCK、ARC、各种淘汰算法)。DM 上这些不再适用:
- 数据”在哪个层级”由 RDMA 网络决定,不是由 OS page cache 决定
- buffer pool 的 hit miss 不再是核心 metric——RDMA RTT 才是
- prefetch 和 batch 必须在 RDMA verbs 层做
🍎 直觉:DM 把”内存 vs 磁盘”的二元层级换成”local vs remote DRAM”——两端都是 ns 级,但中间有 µs 级网络。
4. DM 事务 vs 共享存储数据库(Aurora / Polar)
4.1 共享存储数据库的架构
Amazon Aurora / Alibaba PolarDB / Microsoft Hyperscale 这一系:
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Compute │ │ Compute │ │ Compute │
│ Node 1 │ │ Node 2 │ │ Node 3 │
│ (主) │ │ (只读副本) │ │ (只读副本) │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ redo log only │ read pages
▼ ▼
┌──────────────────────────────────────────────────┐
│ Shared Storage (distributed log + page server) │
│ ★ 这里有应用 CPU │
│ ★ Storage server 主动 apply log → page │
│ ★ Storage 主动做 GC、compaction、replication │
└──────────────────────────────────────────────────┘
4.2 共享存储 vs DM 的关键差异
| 维度 | 共享存储(Aurora) | DM |
|---|---|---|
| 远端是否被动 | 否(storage server 主动 apply log) | 是 |
| 主路径协议 | RPC(compute → storage 发 redo log) | RDMA 单边 |
| 锁管理 | compute 节点(leader) | CN 或 MN 上的 8B 字 |
| 一致性维持 | redo log 串行化 + page server replay | OCC validate + CAS |
| 默认并发控制 | 2PL(PostgreSQL 风格)/ MVCC | OCC + MVCC |
🌟 核心区分:共享存储的 storage 是 active 服务(有 CPU),DM 的 MN 是 passive memory(无 CPU)。这是两条完全不同的工程路径。
4.3 共享存储的工程优势
⭕ 互补:DM 不一定比共享存储好——共享存储有自己的优势:
- storage server 能做主动 GC、compaction、replication,不需要客户端管
- 能跑复杂逻辑(page server 可以解析 SQL hint)
- 兼容性好(用现成的 PostgreSQL/MySQL kernel 改)
DM 的优势在另一头:
- 真正的 zero-copy(不经过 storage server CPU)
- 更细粒度的扩展性(CN 数量与 MN 容量独立)
- 更接近”硬件级”性能上限
🧠 关键洞察:共享存储是”分布式数据库的工程化”,DM 是”分布式数据库的硬件原生重构”——两者面向不同 trade-off,长期共存。
4.4 一个常见误解:把 Aurora 当成 DM
⚠️ 重要:Aurora 论文里有”compute 和 storage 解耦”的说法,让一些读者误以为 Aurora 是 DM。它不是——Aurora 的 storage 是 active server(page server 跑代码),不是 passive memory。
判别方法:问”远端节点上跑不跑应用 CPU”。Aurora 跑(page server 解析 redo log)。FORD/Motor 不跑。
5. DM 事务 vs 经典分布式事务(Spanner / Cockroach)
5.1 经典分布式事务的核心机制
| 机制 | Spanner | Cockroach | FaRM/FORD/Motor |
|---|---|---|---|
| Leader 选举 | Paxos | Raft | 无(无 leader) |
| 全局时间 | TrueTime | HLC | epoch(基于 NIC RTT) |
| 跨节点协议 | 2PC + Paxos | 2PC + Raft | OCC + RDMA CAS |
| 远端 abort | 主动消息 | 主动消息 | 不存在概念 |
| 节点角色 | 都是 active replica | 都是 active replica | CN active, MN passive |
5.2 为什么 Spanner 思想在 DM 上不适用
Spanner 协议假设
────────────────
1. 远端节点有线程持有锁、能 timeout、能主动 release
2. 跨节点协议 = 多个 active 节点交换消息达成共识
3. 时间用 TrueTime 等"权威时钟服务"
DM 的限制
────────────────
1. MN 没线程 → 不能"持有锁等待"
2. 多 active 节点 = 多 CN,但 MN 不参与协议
3. NIC 的 RTT 是天然 epoch 边界,不需要时钟服务
🌟 后果:Spanner 的整套协议要么完全不可用,要么必须重写。FaRM 论文(2014)里专门说过这一点:“we deliberately rejected 2PC because it requires remote thread participation”。
5.3 跨节点事务在 DM 上怎么做
经典分布式事务用 2PC:
Coordinator → ALL participants:
1. PREPARE: "你能提交吗?"
2. ALL reply: "能/不能"
3. COMMIT/ABORT: "提交吧/回滚吧"
DM 上没有 active 远端,跨 cohort 事务怎么办?两种方案:
| 方案 | 怎么做 |
|---|---|
| OCC validate + CAS(FaRM/FORD) | 取所有锁(CAS)→ 验证版本(READ)→ 写入(WRITE)。失败原子回滚 |
| Owner 代理(LOTUS/AURA) | 客户端发到主 cohort owner,由它 forward 给协作 owner |
两种都不需要 MN 参与——这是 DM 设计哲学的根本。
5.4 一个高度 important 的工程后果
DM 事务系统几乎都不做”严格 serializable + 跨数据中心”:
- Spanner 主打全球分布 + 严格 serializable
- DM 主打单 DC 单机柜规模 + 强一致
🌟 不同的目标空间:DM 不是”廉价 Spanner”,是”针对单机柜内 OLTP 极限性能的另一种范式”。理解了这个目标空间区别,才不会拿 Spanner 去 review DM 论文。
6. 为什么”OCC + 单边原语”几乎是 DM 事务的默认范式
6.1 为什么不是 2PL
2PL(两阶段锁)需要:
- 事务开始时取锁
- 锁被占时等待
- 事务结束时释放锁
- 死锁检测
在 DM 上:
| 2PL 步骤 | DM 是否能做 |
|---|---|
| 取锁 | ✓(用 RDMA CAS) |
| 等待(被锁住时) | ✗(MN 不能挂起 CN,CN 必须 spin 或回退) |
| 释放锁 | ✓(RDMA WRITE) |
| 死锁检测 | ✗(需要全局视图) |
🌟 致命问题:2PL 的”等待”语义需要”持锁方释放时通知等待方”。在 DM 上 MN 不能做通知——CN 只能 spin 重试,等同于退化成 OCC 的 abort+retry。所以 2PL 在 DM 上没有任何优势,全部论文都用 OCC。
6.2 为什么不是 Pessimistic + Spin
理论上 CN 可以 spin 等锁释放:
while (rdma_cas(lock_addr, expected=0, swap=tx_id) != 0) {
cpu_relax();
}
问题:spin 占满 NIC atomic IOPS。一个 spin 循环每 µs 发一次 CAS,10 个 spin 客户端 = 10 Mpps,直接打爆 atomic 上限。
⭕ 互补:少量 spin 可以接受(lock 即将释放时)。但作为默认协议路径不可行。OCC 是更好的选择:失败就 abort,不浪费 NIC 资源。
6.3 OCC 在 DM 上的天然优势
| OCC 性质 | 为什么适合 DM |
|---|---|
| 无锁等待 | 不需要 MN 维护等待队列 |
| 失败 abort | 不浪费 atomic IOPS(spin 才浪费) |
| commit 用 CAS 取锁 | RDMA CAS 是 native 支持 |
| 验证用 read 重读版本 | RDMA READ 是 native 支持 |
| 不需要远端 active 参与 | 完美匹配 passive MN |
🌟 结论:OCC + 单边 RDMA 原语是 DM 事务的”自然语言”——这不是某篇论文的发明,是硬件约束下的必然。
6.4 例外:FaSST 用 two-sided
FaSST(OSDI’16)是个反例——它论证 two-sided(SEND/RECV)有时比 one-sided 快。但:
- 它不否认”远端必须能跑应用 CPU”——所以本质上 FaSST 是”轻 active server” 不是纯 DM
- 它的高吞吐来自”远端 batch 处理”——这跟 DM 哲学相反
🍎 结论:FaSST 是历史上探索过的另一条路,但主流 DM 事务(FORD/Motor/LOTUS/AURA)都选 OCC + one-sided。
7. 5 秒判别工具:4 个问题
拿到任何新论文/系统,问 4 个问题,30 秒内定位它在地图哪个角落:
7.1 Q1:远端节点跑应用 CPU 吗?
| 答案 | 含义 |
|---|---|
| 跑(有 application thread) | 不是 DM。是共享存储 / 经典分布式 / 单机 |
| 不跑(只 NIC 处理 RDMA) | 是 DM 候选 |
7.2 Q2:主路径用 RDMA 单边原语吗?
| 答案 | 含义 |
|---|---|
| 是(READ/WRITE/CAS/FAA 为主) | DM |
| 否(RPC / SEND / TCP) | 不是典型 DM |
7.3 Q3:默认并发控制是 OCC 吗?
| 答案 | 含义 |
|---|---|
| 是 | 主流 DM 路径 |
| 否(2PL) | 罕见或非纯 DM |
7.4 Q4:锁权威在哪里?
| 答案 | 含义 |
|---|---|
| MN | 第一代 DM(FORD/Motor/CREST) |
| CN-static | LOTUS 派 |
| CN-dynamic | AURA 派 |
| 多副本 | 未来开放方向 |
7.5 一个练习:判断 NAM-DB
NAM-DB(VLDB’20)声称是 DM 数据库。用 4 问:
- Q1:远端跑 CPU 吗?部分跑(NAM-DB 有 active server thread 处理批量请求)
- Q2:主路径单边原语?部分(用 RDMA WRITE 但也用 RPC)
- Q3:OCC?是
- Q4:锁权威?远端
🌟 判别:NAM-DB 是半 DM——介于纯 DM(FORD)和共享存储(Aurora)之间。这种系统在 paper 里通常叫”NIC-attached database”,不是严格 DM。
8. 领域边界外:哪些系统看起来像 DM 但其实不是
8.1 InfiniSwap(NSDI’17)
InfiniSwap 把远端 RDMA 内存当 swap 用。不是 DM 事务——它解决的是 OS 层的内存扩展,不涉及事务语义。但它是 DM 概念的早期工程实现,被频繁引用。
8.2 LegoOS(OSDI’18)
LegoOS 把 OS 拆分成多个 monitor(process / memory / storage 解耦)。不是 DM 事务——它是 OS 概念,不直接处理事务。但它确立了 disaggregation 的设计哲学。
8.3 RAMCloud / FaRM-KV
这些是 KV 系统,不是事务系统。如果只支持 GET/PUT/DELETE 没有跨 key 一致性,就不属于 DM 事务范畴。
8.4 Mooncake / DistServe(KV-cache 池)
Mooncake / DistServe 是 LLM 推理的 KV-cache 共享系统。不是 DM 事务——它的 KV-cache 是 LLM 的 attention 状态,不是数据库事务。但它用了 DM 的硬件(RDMA + remote memory),所以经常被一起讨论。
8.5 CXL Memory Pool(Pond / TPP)
CXL pool 是新一代 disaggregation 硬件。目前没有 CXL-native DM 事务系统——CXL 上跑 DM 事务是开放方向(§9 详述)。
8.6 经验法则:领域边界
是 DM 事务必须满足:
────────────────────
1. 远端 passive memory(不跑 application CPU)
2. 主路径单边原语(RDMA / CXL.mem)
3. 处理事务级一致性(不只是 KV)
4. 跨节点协议不依赖远端 active 参与
缺任何一条 → 不是严格 DM
🌟 建议:写 paper / 报告时不要说”我们做了 DM 事务”如果你的系统不满足以上 4 条——审稿人会挑刺。老实说”我们做了 NIC-attached database”或”shared-storage txn”更安全。
✅ 自我检验清单
- Spanner 反例:能用一句话解释为什么 Spanner 不是 DM
- MN passive:能描述”远端 NIC 处理 RDMA,不跑 application CPU”的工程含义
- 4 个区分维度:能默写 D1–D4 + 各自二选一
- DM vs 单机:能列出至少 3 个单机数据库的设计选择在 DM 上不可用
- 8B atomic 限制:能解释为什么所有 DM 锁字都要压进 8B
- DM vs 共享存储:能用”远端跑不跑 CPU”区分 DM 和 Aurora
- DM vs Spanner:能列出至少 2 个 Spanner 思想在 DM 上不适用的原因
- OCC 默认范式:能解释为什么 2PL 在 DM 上不可行
- FaSST 例外:能说明 FaSST 为什么是历史例外
- 5 秒判别工具:能用 4 问判别一个新系统是不是 DM 事务
- NAM-DB 是半 DM:能解释为什么 NAM-DB 介于 DM 和共享存储之间
- 领域边界:能列出至少 3 类”看起来像 DM 但其实不是”的系统
📚 参考资料
概念入门
- The Datacenter as a Computer (Barroso et al., 3rd ed., 2018) —— Warehouse-scale computing 奠基
- A Survey on Disaggregated Memory (Wang et al., 2023) —— 早期综述
- 模块十三第 1 章 什么是分离式内存:本仓库
docs/guides/模块十三-新型互联与远程内存系统/第1章-什么是分离式内存.md
关键论文
- FaRM (Dragojević et al., NSDI’14):USENIX 链接 —— 首篇系统性 DM 事务,确立 OCC + 单边原语范式
- LegoOS (Shan et al., OSDI’18):arXiv 1810.01632 —— Disaggregated OS 概念奠基,DM 哲学源头
- FaSST (Kalia et al., OSDI’16):USENIX 链接 —— 反直觉论证 two-sided 的存在意义
- Spanner (Corbett et al., OSDI’12) —— 经典分布式事务对照
- Aurora (Verbitski et al., SIGMOD’17) —— 共享存储数据库对照
- NAM-DB (Zamanian et al., VLDB’20) —— 半 DM 数据库的代表
行业讨论
- Disaggregated Memory in Production(HPCA / OSDI tutorial)
- Why DM is the next stack of cloud infra(行业博客)
框架文档
- CREST 仓库 —— 后续章节实战载体
- Spanner / Cockroach 文档 —— 作为对照参考