第7章:持久化、故障与恢复 —— DM 上的 durability 模型
拆解 DM 系统持久化的核心矛盾(MN 不主动 flush)、PMEM / RDMA log 的工程设计、故障模型分类、恢复协议。从 FaRM 到 Plor 系统梳理
事务系统四大基本属性 ACID 中的 D(Durability)和故障下的恢复 是被讨论得最少的——大多数 DM 论文focus在性能,对 durability 一笔带过。但生产 OLTP 必须能”宕机不丢数据”,DM 系统的 durability 模型远比单机复杂:MN 不主动 flush、PMEM 协议复杂、跨副本一致性、CN 故障 vs MN 故障的语义差异。本章把 DM 的持久化、故障、恢复系统梳理一遍——从 FaRM 的 epoch + lease 经典模型,到 Clover / Plor 的 PMEM 加速,再到 LOTUS / AURA 的 CN-side 状态恢复。读完你应该能回答”DM 系统挂了一个节点,会丢什么、能恢复到什么程度”。
📑 目录
- 1. 单机 vs DM:durability 模型的根本差异
- 2. 三种持久化媒介
- 3. PMEM 持久化协议
- 4. RDMA log 设计
- 5. 故障模型分类
- 6. CN 故障 vs MN 故障
- 7. FaRM-style epoch + lease 经典模型
- 8. Plor:PMEM log 加速
- 9. AURA 的 CN-side 状态恢复
- 10. 跨副本一致性
- 自我检验清单
- 参考资料
1. 单机 vs DM:durability 模型的根本差异
1.1 单机数据库的 durability
单机持久化路径
────────────────
1. 事务在内存修改
2. 写 WAL(Write-Ahead Log)→ append to log file
3. fsync() ← 强制刷到磁盘
4. 返回 commit OK 给客户端
5. 后台异步把 WAL 应用到主数据
──────────────────────
crash 后:从 WAL recover
关键:单一进程 + OS 提供的 fsync 语义——简单可靠。
1.2 DM 的持久化路径
DM 持久化路径
────────────────
1. CN 在本地修改
2. CN RDMA WRITE 数据到 MN
3. ??? MN 主机内存不是 PMEM 怎么 flush
4. ??? CN 怎么知道数据真的落到持久存储
5. 返回 OK 给客户端
──────────────────────
crash 后:??? 谁来 recover MN 状态
🌟 核心矛盾:DM 的 MN 不主动做任何事——MN 既不能主动 flush,也不能主动 recover。所有持久化协议必须由 CN 主导。
1.3 三种 durability 假设
DM 系统的 durability 模型按”假设强度”分三档:
| 模型 | 假设 | 适合 |
|---|---|---|
| In-memory only | 节点不 crash,依赖副本 | 实验室 baseline |
| PMEM-backed | MN 主机有 PMEM | 真正持久化 |
| NVMe + RDMA | 数据写到 NVMe via RDMA | 折中方案 |
🍎 直觉:DM 的”持久化”不像单机的 fsync 那么简单——它是一组协议级约定,要 CN 和 MN 配合才能保证。
2. 三种持久化媒介
2.1 DRAM-only(无持久化)
配置
──────
- MN 只有普通 DRAM
- 数据在 DRAM
- 节点 crash → 数据丢
适合
──────
- 实验室测性能
- 副本足够多(多 MN)→ 容忍单 MN 丢失
🌟 现状:大多数 DM 论文实验是 DRAM-only——FORD / Motor / CREST 的 main result 都是 DRAM。
2.2 PMEM(Intel Optane)
配置
──────
- MN 主机有 Intel Optane DC PMM
- byte-addressable + persistent
- 容量大(768GB/CPU),但比 DRAM 慢 3-5×
| 特性 | DRAM | PMEM |
|---|---|---|
| 字节寻址 | ✓ | ✓ |
| 持久 | ✗ | ✓ |
| 延迟 (read) | ~50ns | ~150-300ns |
| 延迟 (write) | ~50ns | ~150-300ns |
| 容量 | 单机 ~1TB | 单机 6-12TB |
⚠️ 现状:Intel 2022 年宣布停产 Optane——PMEM 路线的未来不确定。后续可能被 CXL 持久化设备替代。
2.3 NVMe via RDMA
配置
──────
- MN 后端是 NVMe SSD
- CN RDMA WRITE → MN buffer → 异步刷 NVMe
- 持久化但更慢(~10µs vs PMEM 0.3µs)
优势:容量极大、便宜 劣势:延迟高、协议复杂
🌟 结论:目前主流 DM 论文实验仍以 DRAM 为主,PMEM 是少数(Clover / Plor)。CXL 上的持久化是开放方向。
3. PMEM 持久化协议
3.1 PMEM 持久化的硬件协议
单机 PMEM 持久化(Intel ISA)
────────────────────────────
1. store (write) 到 cache line
2. clflush / clwb 显式刷 cache → memory controller
3. memory controller 进入 PMEM controller
4. PMEM controller 确认写入 ADR domain(电力丢失保护域)
──────────────────────────────
只有第 4 步完成才算"真正持久化"
3.2 RDMA + PMEM 的协议复杂性
DM 上的 PMEM 持久化
────────────────────
1. CN RDMA WRITE → MN
2. 数据到 MN 主机内存 cache
3. ??? cache 何时 flush 到 PMEM
4. ??? CN 何时知道 PMEM 落下
几个工程做法:
| 做法 | 描述 |
|---|---|
| MN 主动 flush | 需要 MN CPU(违反 DM 哲学) |
| 特殊 RDMA op | DDIO / FLUSH(NIC 直接 flush) |
| CN 触发 | CN 写一个 “flush flag” → MN 触发 |
3.3 RDMA Persist 扩展(实验性)
Mellanox 在新 NIC 中加入了 RDMA Persist:
// 实验性 verb
ibv_post_send(qp, IBV_WR_RDMA_WRITE_WITH_PERSIST, ...);
语义:NIC 保证数据已落 PMEM 才返回 CQE。省去 CN 协议层逻辑。
⚠️ 现状:仅在 ConnectX-7+ 实验性支持,主流 DM 论文还没普遍用。
3.4 client-side flush 协议(Clover / Plor)
主流做法(Clover, Plor)
──────────────────────
1. CN RDMA WRITE 数据 → MN
2. CN RDMA WRITE 到一个 "flush trigger" 地址 → MN
3. MN 主机有一个轻量 worker 监听 trigger → 触发 clwb
4. CN RDMA READ "flush_done" 标志 → 确认完成
──────────────────────
↑ 仍然需要 MN 一点 CPU,但只是周期性查询
🌟 结论:完全 zero-CPU MN 的 PMEM 协议还没有成熟方案——这是开放方向。
4. RDMA log 设计
4.1 为什么需要 RDMA log
事务的 redo / undo log 必须持久化才能 recover。在 DM 上:
传统 WAL: 写本地磁盘
DM WAL: 写 MN PMEM via RDMA
4.2 RDMA log 的工程挑战
| 挑战 | 解释 |
|---|---|
| 顺序保证 | log 必须按事务 commit 顺序 append |
| 持久化保证 | 必须确认落 PMEM 才能 commit |
| 并发 append | 多 CN 同时写 log 怎么不冲突 |
| GC | 老 log 何时可以删 |
4.3 Plor 的核心设计(ATC’23)
核心 insight:把”顺序 append”做成 atomic FAA + WRITE 组合。
Plor log append 协议
────────────────────
1. log_offset = rdma_faa(global_log_tail, increment=record_size)
↑ atomic 拿到唯一 offset
2. rdma_write(log_addr + log_offset, log_record)
↑ 写到对应位置
3. wait for flush trigger / read flush flag
──────────────────────
↑ 多 CN 并发 append 不冲突(FAA 保证)
4.4 Plor 性能数字
| Workload | FaRM-style log | Plor |
|---|---|---|
| Log append latency | ~15µs | ~5µs |
| Log throughput | ~200K | ~600K |
🌟 结论:Plor 是 DM PMEM log 的当前 SOTA。
4.5 Log GC
老 log 何时删?
GC 决策
──────────
1. 找到所有 CN 的最早 active tx_id
2. log_record.tx_id < min_active_tx_id → 可删
3. 后台 worker 周期性 truncate
⚠️ 限制:长事务会 hold log 很久——log 累积压力。
5. 故障模型分类
5.1 故障类型
DM 系统的故障分类
──────────────────
┌─────────────────────────────────────┐
│ 节点故障 │
├─────────────────────────────────────┤
│ - CN crash │ ← 简单
│ - MN crash │ ← 复杂
│ - 部分故障(CPU OK,NIC 挂) │ ← 难处理
├─────────────────────────────────────┤
│ 网络故障 │
├─────────────────────────────────────┤
│ - 丢包(RDMA 自动重传) │ ← OK
│ - 网络分区(partition) │ ← 复杂
│ - 高延迟(RDMA timeout) │ ← 中等 |
├─────────────────────────────────────┤
│ 持久化故障 │
├─────────────────────────────────────┤
│ - PMEM 损坏 │ ← 副本兜底 |
│ - SSD 损坏 │ ← 同上 |
└─────────────────────────────────────┘
5.2 故障模型四档
| 模型 | 假设 | 复杂度 |
|---|---|---|
| Crash-stop | 节点 crash 后永不返回 | 低 |
| Crash-recover | 节点 crash 后能恢复 | 中 |
| Network partition | 网络分区,节点活但不通 | 高 |
| Byzantine | 节点可能恶意(不在 DM 范围) | - |
主流 DM 系统假设 Crash-stop + 持久化时考虑 Crash-recover。
5.3 故障检测
主流做法
──────────
- 心跳协议(heartbeat)
- RDMA timeout 触发
- epoch + lease(FaRM)
- Paxos/Raft 维护 membership
6. CN 故障 vs MN 故障
6.1 CN 故障(相对简单)
CN 故障的影响
──────────────
1. 该 CN 上正在跑的事务全部失败
2. 客户端重试到其他 CN
3. CN 上的本地缓存丢失(无所谓,可以从 MN 重读)
──────────────
↑ 通常不影响数据一致性
但有例外:
| 系统 | CN 故障的特殊问题 |
|---|---|
| LOTUS | CN-side 锁丢 → 该 CN 拥有的 cohort 不可用 |
| AURA | 同上,但 fallback 到 MN 兜底 |
| Motor | CN 上 active tx 的 ts 丢失,可能阻塞 GC |
6.2 MN 故障(复杂)
MN 故障的影响
──────────────
1. MN 上的数据全部不可访问
2. 单 MN 配置:整个系统宕
3. 多 MN 副本:另一个副本顶上
主流做法:
- 每份数据存在多个 MN(FaRM 默认 3 副本)
- 用 Paxos 协议维护副本一致
🌟 关键事实:单 MN 故障是 DM 系统的高严重事件——必须有多副本兜底。
6.3 部分故障
最难处理:节点活着但部分组件挂(如 NIC 挂)。
症状
──────────
- CN 心跳还在(CPU OK)
- 但 RDMA op timeout(NIC 挂)
- membership 协议判它"半死"
处理
──────────
- 把它从 OwnerMap 中移除(AURA)
- 等 CN 自己 reset NIC 后重新加入
⚠️ 挑战:判断”NIC 慢” vs “NIC 挂”的边界——容易误判。
7. FaRM-style epoch + lease 经典模型
7.1 FaRM 故障恢复的核心思想
Epoch + Lease:
Epoch 协议
────────────
- 全局递增 epoch number(由 config service 管理)
- 每个 CN/MN 持有一个 lease(时间窗口)
- lease 过期 → 必须刷新 epoch
- epoch 推进 → 旧 lease 失效
────────────
↑ 让"故障检测"和"故障恢复"基于时间窗口,不需要复杂分布式协议
7.2 FaRM 协议详细
正常时
──────
t=0 epoch=42, lease=10ms
t=5ms heartbeat OK → lease 续期
t=10ms heartbeat OK → lease 续期
...
节点 X crash
──────────────
t=20ms X 不再发 heartbeat
t=30ms 其他节点检测到 X 失败
t=30ms config service 推 epoch → 43
t=30ms 所有节点开始 recovery(X 上的事务全 abort)
t=40ms 系统恢复正常
7.3 FaRM 协议的性质
| 性质 | 价值 |
|---|---|
| 不需要 Byzantine 检测 | 简单 |
| time-bound 恢复 | 知道最差恢复时间 |
| epoch 全局有序 | 不会有”两个 leader”问题 |
| 基于 Paxos 的 config service | 可靠 |
🌟 结论:FaRM-style 是 DM 故障恢复的”标准做法”——后续 FORD / Motor / Plor 都用类似的协议。
7.4 FaRM 的局限
⚠️ 限制:
- lease 期间无法快速检测故障(恢复延迟 = lease 时间)
- 全局 epoch 推进受 Paxos 限制
- 跨 DC 时 lease 时间过短不可行
8. Plor:PMEM log 加速
8.1 Plor 的双重贡献
第 4 节已经讲了 Plor 的 log append——这里讲它的 recovery:
Plor recovery 协议
──────────────────
1. 系统启动 → 找到所有 PMEM log 的最新 tail
2. 从 last checkpoint 开始 redo all log records
3. apply 到主数据
4. 标记完成 → 系统进入 normal 模式
8.2 加速点
Plor 的 recovery 用 RDMA 并行读 log——多 CN 同时拉取 log records:
Recovery throughput
──────────────────
单 reader: ~50 MB/s
多 reader(4 个并行): ~200 MB/s
↑ 重启时间从分钟级压到秒级
🌟 意义:DM 系统重启不需要”长时间不可用”——这对生产场景重要。
9. AURA 的 CN-side 状态恢复
9.1 AURA 多了一类故障:owner CN 的状态丢失
传统 DM(FaRM/FORD):CN 故障无大碍
AURA:owner CN 故障 = cohort 上的"权威"丢失
9.2 AURA 的应对:fallback to MN
owner CN 故障检测
──────────────────
1. 心跳超时(500ms)→ 判定 owner 故障
2. OwnershipPlanner 把 cohort 改为 FALLBACK 状态
3. publish 新 OwnerMap epoch
4. 该 cohort 上的事务自动走 MN atomic 路径(与 FORD 相同)
──────────────────
↑ 不会卡住整个 cohort
9.3 fallback 的语义保证
AURA 不变式 I4:commit 路径不依赖 owner 位置
──────────────────────────────────────────────
↑ 即使 owner 在 commit 中途挂,事务可以:
- abort(自动 retry)
- 或者继续走 MN atomic(fallback)
↑ 数据一致性不损失
🌟 结论:AURA 的 fallback 是它”故障安全”的核心——详见模块十五第 6 章。
10. 跨副本一致性
10.1 多 MN 副本的需求
单 MN 系统是 SPOF(single point of failure)。生产 DM 系统必须有多 MN 副本。
10.2 副本协议
主流副本协议
──────────────
1. Primary-backup(FaRM)
- 1 个主 + N-1 个备
- 写到主,主 RDMA WRITE 给所有备 → 等 quorum ack
2. Chain replication
- 写到 head,head → next → ... → tail
- tail ack → commit
3. Paxos/Raft
- quorum-based
- 通常用于 metadata(不用于数据)
10.3 副本一致性的代价
| 副本数 | 写延迟 | 容忍故障 |
|---|---|---|
| 1(无副本) | ~10µs | 0 |
| 2 | ~12µs | 1 |
| 3 | ~15µs | 1 |
| 5 | ~20µs | 2 |
🌟 主流选择:3 副本——容忍 1 节点故障,延迟可接受。
10.4 跨 DC 副本(开放问题)
跨 DC 挑战
──────────────
- RTT 从 1µs(同 DC)→ 1ms(跨 DC)
- 等 quorum ack 延迟爆炸
- 主流 DM 系统不支持 cross-DC 副本
⚠️ 限制:DM 系统目前都是单 DC——cross-DC 是开放方向(详见第 9 章)。
✅ 自我检验清单
- DM vs 单机 durability:能解释为什么 MN 不能主动 flush
- 三种持久化媒介:能列出 DRAM/PMEM/NVMe + 各自延迟
- PMEM 协议:能解释 cache flush + ADR domain
- client-side flush:能描述 Clover 的协议
- RDMA Persist:能说明它的实验性现状
- Plor log append:能写 FAA + WRITE 协议伪代码
- 故障模型四档:能列出 crash-stop / crash-recover / partition / Byzantine
- CN 故障 vs MN 故障:能列出复杂度差异
- 部分故障难点:能描述 NIC 慢 vs NIC 挂的边界问题
- FaRM epoch + lease:能描述 lease 续期与 epoch 推进
- Plor recovery 加速:能说明并行 log 读如何减少重启时间
- AURA fallback:能解释 owner crash 后 cohort 如何兜底
- 副本协议三种:能列出 primary-backup / chain / Paxos
- 3 副本是主流:能说明数字理由
📚 参考资料
关键论文
- FaRM (Dragojević et al., NSDI’14) —— epoch + lease 经典
- Clover (Tsai et al., ATC’20) —— PMEM + RDMA 持久化
- Plor (Lee et al., ATC’23) —— PMEM log 加速
- Hyder (Bernstein et al., CIDR’11) —— single-leader log 早期参考
PMEM 资料
- Intel ISA Persistence Programming Model —— 官方 PMEM 编程指南
- Persistent Memory Programming (Scargall, 2020) —— 教科书
故障与恢复
- Concurrency Control and Recovery (Bernstein et al., 1987) —— 经典教材
- Distributed Snapshots (Chandy & Lamport, 1985) —— 分布式快照鼻祖
- Raft Consensus —— 简化 Paxos
行业讨论
- Intel Optane DC PMM 停产公告(2022) —— PMEM 路线讨论
- CXL 2.0 持久化扩展讨论 —— 未来方向