过去十年云数据库最显眼的架构演进,不是查询优化器变聪明,也不是事务协议换代,而是底层存储形态从”本地盘 + 复制”转向”共享池 + 共识化日志 + 页面服务”。Amazon Aurora(SIGMOD 2017/2018)打响第一枪,之后 Microsoft Socrates(SIGMOD 2019)、Alibaba PolarDB(VLDB 2018)、Huawei Taurus(SIGMOD 2020)相继发表,每家都把”存算分离”重新演绎了一遍。
这些系统表面上都叫”云原生数据库”,内部的取舍却各有不同:Aurora 把复制放在存储层,用 quorum 写解决持久化;Socrates 把服务进一步拆成 compute / page server / log service / XStore 四层,强调”XStore 是 database”;PolarDB 借助 RDMA 共享存储池,配 ParallelRaft 做日志复制;Taurus 则把”Log Store”和”Page Store”彻底分开,走 SMR(State Machine Replication)路线。
把这四家放在一起读,可以看到一个反复出现的模式:日志成为数据库的唯一真相,页面由独立的 page server 按需物化,上层计算节点趋于无状态。本文上半部分从这个公共骨架出发,逐家对照核心机制与取舍;下半部分讨论如果你自己要搭一套 disaggregated 存储,路线图该怎么走、哪些坑是必踩的。
版本说明 本文以 SIGMOD 2017 / 2018 / 2019 / 2020、VLDB 2018 的论文及各家公开技术博客为准。具体产品版本会持续演进,工程细节以最新官方文档为准。
一、为什么”日志即数据库”
1.1 传统主从复制的三个问题
经典的 MySQL / PostgreSQL 主从复制有三个长期痛点:
- 写放大在多副本间重复发生。 主库把变更落盘一次、发 WAL/binlog 到从库、从库再重放写盘。同一份数据实际刷盘 N 次,网络也跑 N 遍全量页。
- 主库故障恢复依赖 checkpoint。 崩溃恢复要从最近 checkpoint 起重放 WAL,恢复时间与 checkpoint 间隔强相关。大库 checkpoint 一放就是半小时以上。
- 扩容要停机或长时间追日志。 加一个从库,要 base backup + replay WAL,数据量上 TB 时通常几小时。
这些问题有一个共同根源:计算节点持有可变的本地状态(shared buffers + 数据文件)。只要这个状态存在,任何副本都要”先重做成相同状态才能服务”。
1.2 把”日志”提升为系统的真相
Verbitski 等人在 SIGMOD 2017 的 Aurora 论文里给出一条看似简单但影响深远的推论:
如果日志足够重建任何页面,那么”日志”就可以作为数据库的唯一持久真相,“页面”只是日志的缓存。
这个视角下:
- 主库不再需要把数据页写盘,它只发 WAL;
- 存储层的每个副本独立把 WAL 重放成页面;
- 恢复不需要 checkpoint,存储层已经保留了足够的 WAL,新计算节点接上即可。
“日志即数据库(Log is Database)” 后来成了几乎所有云原生数据库的架构哲学。
1.3 四家的共同骨架
抽象出 Aurora、Socrates、PolarDB、Taurus 的共同骨架:
+-----------------------+
| compute (SQL) | 解析、优化、执行、事务
+-----------+-----------+
| WAL
v
+-----------------------+
| log service | 日志持久化 + 共识
+-----------+-----------+
| WAL stream
v
+-----------------------+
| page server(s) | 物化页面 + 响应 getpage
+-----------+-----------+
| 冷页面 / 备份
v
+-----------------------+
| object storage | S3 / 自研对象存储
+-----------------------+
每家的差别,几乎都可以映射到这张图里某个组件的 “实现方式不同”:
- log service 是 quorum 写还是共识复制;
- page server 是共享池里按 chunk 划分,还是每个实例独立一套;
- compute 能缓存多少本地状态;
- 冷数据下沉用对象存储还是专门的 archive 层。
1.4 几个高频概念辨析
在进入各家系统前,先统一几个容易混淆的概念:
存算分离 vs 存储共享 “存算分离”(Disaggregation)强调计算层无状态、可独立伸缩;“存储共享”(Shared-Storage)强调多个计算节点能看到同一份存储。Aurora 是存算分离 + 存储共享;PolarDB 是存算分离 + 存储共享;TiDB 也是存算分离但 TiKV 之间不共享(每片数据多副本但副本不被其他分片共享)。两个概念经常混用,读文档时要看清具体语义。
主单写 vs 多主共写 本文讨论的四家系统都是”主单写”(Single-Writer):任一时刻只有一个 compute 节点写某段数据范围。多主共写(Multi-Master)架构在 disaggregated 层上更难做,需要跨 compute 的全局锁或冲突检测(如 CockroachDB 的 lease、Google F1 的协调层),不在本文范围。
逻辑复制 vs 物理复制 经典 MySQL 主从用 binlog 是”逻辑复制”(基于 SQL 语句或行级事件),PostgreSQL 的 streaming replication 是”物理复制”(基于 WAL 字节级)。disaggregated 数据库几乎全部走物理复制——因为计算节点无状态,只有 WAL 字节级的状态足以重建任何页面。
理解了这几点,后面看论文时就不会被术语晃晕。
二、Amazon Aurora:quorum 存储 + redo 流
2.1 存储层结构
Aurora 把底层存储组成一个”6 副本 × 多 segment”的池:
- 每个数据库卷被切成 10 GB 的”segment”(protection group),每个 segment 有 6 个副本,分布在 3 个 AZ,每 AZ 两个副本;
- 写入要求 6 个副本中 4 个确认(W=4);
- 读取一般是 single-read,遇到不一致回退为 quorum read(R=3);
- 这个 W+R > N 的 quorum 方案保证任一 AZ 整体故障(2 个副本丢失)后仍可写可读。
2.2 日志与页面
Aurora 把数据库的 “日志流” 定义为主库到存储层的唯一通信。主库发 redo record,每条标注它所属的 segment。存储层节点做三件事:
- 持久化 redo(自己本地的 log-structured 文件);
- 根据 redo 在本地物化页面(支持冷热分级);
- 响应计算节点的
get_page(pageno, lsn)请求。
“日志在每个副本独立物化成页面”这个设计,让网络上只传 redo(几十到几百字节级别的小记录),不传整页(8KB)。论文里给出的数字是 Aurora 的 IO amplification 大约是传统 MySQL 1:7.7 的那一侧的 1/7.7,即约 7.7× 的节省。
2.3 缓存层级
Aurora 没有单独的外部缓存层,计算节点自身 buffer pool 就是热数据缓存。主从副本之间通过存储层共享,从库不需要重新回放 WAL——它看到的页面和主库是同一个存储层,只需要保持 buffer pool 的 LSN 视图与主库一致即可(使用 “replica dictionary cache” 同步 schema)。
2.4 关键特性与限制
特性:
- 快速故障恢复(< 60 秒,不需要 checkpoint 重放);
- 只读副本几乎即时(共享存储);
- 克隆是元数据操作(copy-on-write,见《Serverless 数据库》)。
限制:
- 主库只有一个(single writer),写入瓶颈在主库单机资源;
- 存储层和计算层的网络必须在同一 region;
- quorum 写的尾延迟受”第四快副本”控制,偶发 AZ 抖动会放大到数据库延迟。
2.5 Aurora 的”不用共识”哲学
SIGMOD 2018 的那篇续作 “On Avoiding Distributed Consensus for I/Os, Commits, and Membership Changes” 强调一个观点:Aurora 存储层故意避开 Paxos/Raft。它用的是 quorum 多数派 + 异步 gossip 同步进度,而不是强一致的共识协议。
为什么不用 Raft?作者的理由:
- Raft 对写入要求 leader 单点协调,跨 AZ 的 RTT 把 commit 延迟拉到几十毫秒;
- quorum 写(W=4/6)在跨 AZ 下平均 commit 延迟更低,尾延迟由”第四快副本”控制;
- 存储层只需要保证”不会同时有两个主库写同一 segment”,这可以由更高层的 leader lease + fencing token 实现,不需要存储层自己选主。
这个取舍的代价是一致性模型稍弱:单独看存储层不是强一致的,它依赖计算层的唯一写者假设。但从业务视角看,Aurora 对外仍是”可串行化 + 强一致读”。这种”分层放松一致性”的设计在大规模系统里很常见,也提醒读者在做对比时不能只看存储层自身的一致性,要看端到端语义。
2.6 存储层容量与段分布
Aurora 每个数据库卷按 10 GB segment 切分,单个数据库卷最大支持 128 TB。段级的 quorum 意味着:
- 扩容时新段立刻按 6 副本分布在 AZ 中,不需要数据搬迁;
- 任何段的 IO 不会影响其他段;
- 故障恢复是段级粒度,不会整库停摆。
这个”把大卷切成 N 个独立小卷” 的思路,后来被几乎所有云原生数据库沿用。Socrates 的 page server partition、Taurus 的 Page Store partition、甚至对象存储内部的 chunk,都可以视为同一思想的不同粒度。段的大小是一个经典 trade-off:太小则元数据开销大,太大则故障影响面广、扩缩容不灵活。10 GB 是 Aurora 团队在实测中找到的甜点。
三、Microsoft Socrates:四层分离 + XStore 是 database
3.1 分层设计
Antonopoulos 等人在 SIGMOD 2019 的 “Socrates: The New SQL Server in the Cloud” 提出一个更激进的分层:
compute (SQL Server engine)
|
log service (LandingZone + XLog)
|
page servers (独立 page server 实例,按 SQL 数据库分配)
|
XStore (long-term archival storage)
关键差异点:
- Socrates 把 log service 单独拎出来,负责低延迟持久化 redo 与服务 “最近的 WAL”(供 page server 与 replica 消费);
- page servers 每个数据库有多个(典型 1–4 个),每个负责一段 page 范围;
- XStore 是长期归档层(基于 Azure Blob),存储所有 page 的”最终版本”与完整 WAL 历史。
Socrates 的说法是 “XStore is the database”——真正持久的事实在 XStore 上,log service 与 page server 都是上层缓存/加速。
3.2 日志路径
一次写事务的路径:
- compute 把 redo 写到 log service 的 LandingZone(低延迟磁盘,约 3 副本);
- LandingZone 确认后事务可以返回 commit;
- 后台把 redo 持久化到 XLog(长期保存);
- page servers 订阅 XLog 流,把 redo apply 到各自负责的 page range;
- 冷 page 最终写到 XStore。
这条路径把 “低延迟持久化” 和 “长期归档” 分开:LandingZone 只追求极低的写延迟,XLog + XStore 追求吞吐与成本。这个分离和 Neon 的 safekeeper / pageserver / S3 三层有直接对应关系,时间上 Socrates 在前。
3.3 缓存层级
Socrates 的缓存层级是多级的:
- compute 本地 buffer pool(RBPEX,即 Resilient Buffer Pool Extension,用本地 NVMe 做二级缓存);
- page server 本地缓存热 page;
- XStore 是冷存储,访问延迟相对高。
一次 buffer miss 的查找路径:compute buffer pool -> RBPEX -> page server -> XStore。层级多,意味着命中分布需要仔细调;Socrates 论文里花了相当篇幅讨论 RBPEX 的淘汰策略与并发结构。
3.4 与 Aurora 的对比
| 维度 | Aurora | Socrates |
|---|---|---|
| 日志持久化 | 存储层 6 副本 quorum | 独立 log service(LandingZone + XLog) |
| Page 物化 | 存储层每个副本自己重放 | 独立 page servers,按范围分工 |
| 归档 | 在存储层副本内部 | 独立的 XStore |
| Compute 本地缓存 | 主 buffer pool | buffer pool + RBPEX NVMe 二级缓存 |
Socrates 的层数更多,每一层的职责更窄,代价是路径上多次跳转。但它也带来好处:任何一层的扩容不影响其他层。
3.5 可用性故事
Socrates 在论文里着重强调了可用性。传统 SQL Server 的高可用方案 Always On 依赖同步复制多份数据盘,扩容慢、故障恢复依赖日志追赶。Socrates 把这些职责分散:
- Log service 用多副本保证 WAL 不丢;
- Page server 故障时,新 page server 可以从 XStore 拉最近的 page image + 从 XLog 拉增量重建,不需要阻塞 compute;
- Compute 故障时,新 compute 可以在几秒内接上,不需要”追 checkpoint”。
论文里给出的可用性数据:典型故障场景下恢复时间从 Always On 的分钟级降到 Socrates 的秒级。这类”分层设计天然降低 MTTR” 的效果,也是后来 Neon 等系统沿用四层架构的直接动机。
3.6 Socrates 的实践经验
Socrates 论文在附录里分享了几个有价值的经验数字,值得存档:
- RBPEX(本地 NVMe 做的二级缓存)让 buffer miss 的”远端查找”几乎消失:生产环境里 >95% 的 buffer miss 在 RBPEX 层就命中,不用去 page server;
- LandingZone 用 Azure Premium SSD + 3 副本,P99 写延迟稳定在 1–2 ms;
- XStore 负责冷存储,访问延迟 10–50 ms,由于 RBPEX 屏蔽,业务几乎感受不到。
这组数字说明:多级缓存设计得当,远端访问的延迟可以被”藏”起来。Socrates 用 RBPEX 实现了”compute 本地近似持有热数据”,既保留了存算分离的弹性,又维持了几乎等同本地盘的性能。这一点在工程上值得任何自建 disaggregated 数据库的团队借鉴:不要追求纯粹的 compute 无状态,必要的本地缓存是系统性能的决定因素。
四、Alibaba PolarDB:共享存储 + RDMA + ParallelRaft
4.1 设计背景
Cao 等人在 VLDB 2018 的 “PolarFS: An Ultra-low Latency and Failure Resilient Distributed File System for Shared Storage Cloud Database” 以及后续 PolarDB 论文给出的架构,走的是另一条路:
- 底层是 PolarFS:一个跨节点的分布式文件系统,基于 RDMA + NVMe SSD,暴露 POSIX-like 接口给上层;
- 数据库层是 PolarDB(MySQL / PostgreSQL fork),几乎不改上层引擎,只把底层文件 IO 接到 PolarFS;
- 复制由 PolarFS 内部通过 ParallelRaft 完成。
从外部看,PolarDB 的 compute 节点们共享一份”逻辑磁盘”——主写、从读,底层数据对所有节点同构可见。
4.2 ParallelRaft
普通 Raft(见《Raft 深度解析》)要求日志按顺序提交,这在存储层成为瓶颈:一个慢 IO 会阻塞后续所有 IO。PolarFS 的 ParallelRaft 允许”乱序 commit 已知不冲突的 IO”:
- 每个 IO 带上它写的块范围;
- 如果两次 IO 的块范围不重叠,可以并行确认;
- 冲突的 IO 仍按顺序走。
这让单个 Raft group 的写吞吐显著上升,适配 NVMe 的并行度。代价是协议推导更复杂,论文里花了不少篇幅证明 ParallelRaft 等价于 Raft + 额外的冲突检测。
4.3 RDMA 的角色
PolarFS 大量使用 RDMA(Remote Direct Memory Access)做节点间 IO:
- 客户端(compute)与 chunk server 之间用 RDMA write / read;
- 小数据量时用 RDMA send/recv;
- 通过 RDMA 拿到 µs 级延迟,接近本地 NVMe。
这是 PolarDB 区别于 Aurora 的关键:Aurora 跑在普通 VPC 网络上,存储层延迟典型在亚毫秒到毫秒;PolarDB 假设同机房 RDMA 网络,存储层延迟在 10–100 µs 量级。因此 PolarDB 可以在 compute / storage 分离的前提下,仍然让事务提交延迟接近本地 SSD。
4.4 日志与页面
PolarDB 的”日志即数据库”不像 Aurora 那样在存储层重放,而是:
- MySQL/Postgres 主库正常写 redo 到 PolarFS 上的 redo log 文件;
- PolarFS 把这个文件按 chunk 复制到 3 副本;
- 从库直接读取 PolarFS 上的 redo log(或 page),自己 apply 到 buffer pool。
也就是说,PolarDB 保留了”页面实体”,只是把它放在共享文件系统里。这跟 Aurora “只有日志,没有页面” 的设计是不同的思路:
- Aurora:存储层理解 redo 语义,可以在节点本地独立物化 page;
- PolarDB:存储层只是块设备,不理解 redo;page 仍然由数据库引擎维护。
优点:PolarDB 可以最小侵入地复用 MySQL/Postgres 的大量代码。缺点:存储层无法做”按 redo 物化 page”的优化,数据面仍然要传完整 page。
4.5 缓存层级
共享存储使得 PolarDB 的 “读副本” 几乎零成本扩展:每个从库自己维护 buffer pool,只要 WAL apply 跟上即可。主库的 redo log 写在共享卷上,从库直接读就拿到了。
4.6 PolarDB Serverless
2021 年 SIGMOD 的 “PolarDB Serverless” 在 PolarFS 基础上把 compute 与 memory 进一步分离,引入了 disaggregated memory 层——远端内存池(Remote Memory Pool)用 RDMA 共享 buffer。这条路线和后面要讲的《共享内存数据库复兴》里讨论的 RDMA 数据库有直接联系。
关键想法:buffer pool 也可以放在共享池里,多 compute 共享一份热 page;冷 page 按需从 PolarFS 拉回。这让弹性粒度从”整机”细化到”内存池槽位”,是 Aurora Serverless v2 / Neon 以外的第三条弹性路径。
4.7 PolarDB 的 CSN 与事务可见性
PolarDB 在 MySQL 分支上引入了 CSN(Commit Sequence Number)机制:每次事务提交分配一个全局递增的序列号,记录在共享存储的事务元数据区。这让只读副本可以用”我读到的 CSN 水位”来判断是否看到某写事务,取代传统 MySQL 的 “是否收到 binlog” 判断。
意义在于:
- 可见性有了明确锚点:业务可以查询”当前读副本的 CSN 水位”,判断与主库的差距;
- Read-Your-Writes 可在只读副本实现:事务 commit 后拿到 CSN,下次查询带上”最小 CSN 需求”;
- 跨副本一致性读:多个只读副本可以协同以最低 CSN 水位对齐。
这种思路和 TiDB 的 TSO、Spanner 的 commit_ts 一脉相承,只是 PolarDB 在 MySQL 兼容框架下做了适配。disaggregated 数据库几乎都需要类似的可见性锚点——当多个 compute 节点共享存储,“我读到多新的数据”必须有可度量的定义,否则应用无法推理一致性。
4.8 PolarDB 与 Aurora 的比较小结
一句话概括:Aurora 把”智能”放在存储层,PolarDB 把”智能”放在文件系统。Aurora 存储层理解 redo 语义,能做按需页物化和 quorum 写;PolarDB 底层只是块设备,靠 RDMA 把块读写做快,靠数据库引擎自己理解 redo。两种思路各有利弊:Aurora 的存储层更复杂但上层简化,PolarDB 的引擎改动小但底层依赖 RDMA 网络。对自建数据库的团队而言,前者更难实现但更”云原生”;后者更务实但要求硬件条件。
五、Huawei Taurus:Log Store 与 Page Store 彻底分离
5.1 整体架构
Depoutovitch 等人在 SIGMOD 2020 的 “Taurus Database: How to be Fast, Available, and Frugal in the Cloud” 给出了另一条走法,和 Socrates 的路径非常接近但独立:
compute (MySQL-based)
|
Log Store (分布式 WAL 存储,多副本强一致)
|
Page Store (分布式页面存储,多副本,按 partition)
|
Object Storage (冷数据归档)
Taurus 的突出点:Log Store 和 Page Store 分别独立扩展、独立故障域。Log Store 更像 Kafka 或 BookKeeper 式的日志服务,Page Store 更像对象存储 + 局部 KV 索引。
5.2 写入与读取路径
写入:compute 发 redo 到 Log Store;Log Store 多副本落盘后 ack;事务可以 commit。后台 Page Store 消费 Log Store 的 redo,按 partition 物化 page 并多副本存储。
读取:compute buffer miss 时向 Page Store 请求
get_page(pageno, lsn)。Page Store 如果没有该
lsn 的 page,它会拉对应 redo 重放后返回。
这和 Socrates 的 XLog + page servers 非常像,区别在于 Taurus 不引入 “专门的 archive 层”,冷数据直接下沉到对象存储(不是像 XStore 那样作为权威存储)。
5.3 一致性与恢复
Taurus 的故障恢复依赖 Log Store 的强一致性。compute 节点挂了,新 compute 接上:
- 从 Log Store 读最新 commit LSN;
- 向 Page Store 请求相应 LSN 的 page;
- 事务层根据 WAL 回滚未提交事务。
因为 Log Store 是强一致的,compute 的故障恢复不需要特别复杂的协议——它只要把 Log Store 看作权威 WAL 即可。
5.4 与其他三家的关系
Taurus 最接近 Socrates 的层次拆分,但更”原生分布式”:Log Store 和 Page Store 都是一等公民的分布式服务。这让 Taurus 可以更容易地独立扩缩某一层,也让某层故障时不会传导到其他层。
5.5 Taurus 的性能定位
论文给出的一组数据(sysbench OLTP):
- Taurus 的单节点吞吐与原生 MySQL 基本持平,不因为存算分离而显著退化;
- 在跨 AZ 部署下,写延迟比单机 MySQL 高一个 commit RTT(几毫秒),与 Aurora 类似;
- 只读扩展线性:加一个 compute 副本就多一份读吞吐,不需要数据搬迁。
这说明”存算分离”本身不必然带来性能损失,关键是 log 路径的 RTT 与批量刷盘策略。Taurus 在这点上的优化包括:log batching、pipelined commit、log store 内部的 group commit。
5.6 Taurus 的另一层贡献:把”Log 作为第一公民” 落到细节
Taurus 把 Log Store 做成独立分布式系统的设计,把一个常被模糊处理的问题显式化:“事务日志是否是一个独立的产品?” 传统数据库里日志是引擎内部的实现细节;Aurora 把日志与存储耦合;Taurus 则让 Log Store 变成一个可以独立运维、独立扩缩、独立选型的组件。这种”把内部组件 API 化” 的思路后来在 Neon 的 safekeeper、LinkedIn Databus、Kafka 作为”事件日志数据库”等方向被反复实践。对未来数据库架构师来说,这是一个值得长期思考的问题——下一个被独立化的内部组件会是什么?可能是锁管理器,也可能是 MVCC 版本链,或者查询优化器的统计信息服务。
六、四家横向对比
6.1 一张总览表
| 维度 | Aurora | Socrates | PolarDB | Taurus |
|---|---|---|---|---|
| 论文 | SIGMOD 2017/2018 | SIGMOD 2019 | VLDB 2018 (PolarFS) + 后续 | SIGMOD 2020 |
| 上层引擎 | MySQL / PostgreSQL fork | SQL Server | MySQL / PostgreSQL fork | MySQL fork |
| 复制粒度 | Redo record | Redo record | 块级(RDMA + ParallelRaft) | Redo record |
| 日志服务 | 存储层内置(quorum 6/4) | LandingZone + XLog | PolarFS redo 文件 | 独立 Log Store |
| 页面服务 | 存储层内置 | 独立 page servers | 无(共享文件系统 block) | 独立 Page Store |
| 归档 | 存储层副本 | XStore(Azure Blob) | 快照到 OSS | 对象存储 |
| 本地缓存 | buffer pool | buffer pool + RBPEX | buffer pool | buffer pool |
| 网络假设 | 普通云网 | 普通云网 | RDMA | 普通云网 |
| 主要特色 | quorum 存储 + 存储层 redo apply | 四层分离 + 多级缓存 | 共享文件系统 + 低延迟 | Log/Page 彻底独立 |
6.2 共同模式
抛开实现差别,四家系统抽象出的共同模式是:
- Compute 趋向无状态:本地缓存可以有,但不能是权威。
- 日志是唯一真相:所有系统都假设”只要日志没丢,就可以恢复任何页面”。
- Page 服务按需物化:Aurora / Socrates / Taurus 都在存储/页面层把 redo 应用成 page;PolarDB 是例外(块级共享)。
- 多级缓存:local buffer pool -> local NVMe cache(如有)-> page server cache -> 归档。
- 独立扩缩容:每一层可以按各自的瓶颈扩容,不需要整库重分布。
6.3 不同取舍的根源
- Aurora 把复制放在存储层,代价是存储层比较重(要理解 redo);收益是节省网络和解耦。
- Socrates 把服务切得最细,代价是 operator / ops 复杂度最高;收益是每层可以独立演化。
- PolarDB 把问题推到底层文件系统 + RDMA,代价是依赖特殊网络硬件;收益是几乎不改数据库引擎。
- Taurus 走 Log/Page 完全独立路线,代价是两套分布式协议;收益是故障隔离性最好。
四家没有”谁更好”的答案。它们代表的是:在不同的组织结构、既有代码基础、网络条件下,同一个”存算分离”主题的不同展开。
6.4 故障模式对比
存算分离架构下,各家的故障模式分布也不同。把常见故障放在一张表里对照:
| 故障类型 | Aurora | Socrates | PolarDB | Taurus |
|---|---|---|---|---|
| 单 compute 挂 | 秒级接管(快照即存储层状态) | 秒级接管 + RBPEX 可能需要重建 | 秒级接管(PolarFS 共享) | 秒级接管(Log Store 追 WAL) |
| 单存储副本挂 | 透明:6-4 quorum 允许 2 副本丢 | 隔离到某一层:看是 log / page / XStore | 透明:PolarFS 的 3 副本 Raft 容忍 1 挂 | 隔离到 Log Store 或 Page Store |
| 单 AZ 整体挂 | 依然可写可读(副本跨 AZ) | 依 XStore 可用性;Log service 多 AZ | 需要跨 AZ PolarFS 部署 | Log Store + Page Store 都需跨 AZ |
| 网络抖动 | quorum 的第 4 快副本被拖慢 | log service 的 LandingZone 可能尾延迟放大 | RDMA 网络抖动直接冲击事务延迟 | Log Store 的 commit 被阻塞 |
| 数据损坏(bit rot) | 存储层 checksum + 多副本比对 | XStore 层负责长期完整性 | PolarFS 的 checksum + scrub | Log Store 与 Page Store 各自 checksum |
这张表能帮助识别”同样的字眼背后不同的故障域”。例如”单副本挂” 在 Aurora 是存储层内部的 quorum 掩盖、用户无感;在 Socrates 可能意味着 page server 需要从 XStore 拉 image 重建,有几秒到几十秒的服务降级。
6.5 延迟预算分解
把一次 disaggregated 架构下的事务 commit 延迟做拆解,能看出各家瓶颈的位置。典型 commit 路径的耗时分解(同 region 跨 AZ 部署):
compute 本地 (事务结束,开始 commit) ~ 10 µs
|
| 发 redo 到 log service (RDMA / TCP)
|---- 网络 RTT 0.5 ~ 3 ms
|
log service 持久化 (多副本或 quorum) 1 ~ 5 ms
|
| 回 ack
|---- 网络 RTT 0.5 ~ 3 ms
|
compute 释放锁、返回客户端 ~ 10 µs
|
[异步] log service -> page server 消费
[异步] page server -> 对象存储下沉
commit 路径的延迟主要由”网络 RTT × 2 + 日志持久化”决定,单次 commit 普遍 3–10 ms。只要业务能忍受毫秒级 commit,存算分离就可以工作。如果是微秒级 commit 场景(高频交易、游戏状态同步),disaggregated 架构的网络跳数就无法接受,只能退回单机方案或用 RDMA(见下一篇《共享内存数据库复兴》)。
6.6 复制粒度对可用性的影响
一个容易被忽视的细节:复制粒度影响副本的使用方式。
- redo 记录级复制(Aurora / Socrates / Taurus):每个副本独立解 redo 成 page。副本可以并行、独立地恢复,且可以只恢复必要的 page 范围(按需 lazy recovery)。
- 块级复制(PolarDB via PolarFS):副本对底层存储块做 byte-level 复制,粒度大、恢复简单但灵活度低,副本不能”只恢复一部分 page”。
对实际业务的影响:
- 切主时间:redo 级复制允许副本”边恢复边服务”,切主可以秒级完成;块级复制通常需要整盘一致后才能切。
- 热点数据读扩展:redo 级副本可以优先物化热 page;块级副本按块粒度无法精细调度。
- 冷数据归档:redo 流天然可以驱动冷数据分层,块级复制下冷数据管理要额外层设计。
这些差异不在论文的显眼位置,却决定了每家系统在生产中的运维体验。
七、自建存算分离:路线图与踩坑
7.1 不要一开始就全分离
如果你的团队考虑自己搭一套 disaggregated 存储,先别急着上四层。实际可落地的渐进路线:
第 1 步:把 WAL 写到共享存储(EBS 多挂 / 分布式文件系统)
第 2 步:让只读副本直接读共享 WAL,不再 binlog 复制
第 3 步:引入独立 page server,按 redo 物化页
第 4 步:把 log 服务拆出来,走共识协议
第 5 步:把冷数据下沉到对象存储
每一步都能独立上线、独立验证。绝大部分企业不需要走到第 4、5 步——只走到第 2 步(共享 WAL + 只读扩展)就能解决 80% 的弹性需求。
7.2 日志压缩与 GC 的坑
disaggregated 架构下,日志会无限增长。必须设计日志压缩机制:
- checkpoint 等价物:page server 定期把 redo apply 到 page 后,能否安全截断对应 WAL?安全条件:该 WAL 对所有当前在线的 replica / reader 都已不再需要。
- 最早可见事务:长事务会阻止 WAL 截断,这一点在共享 WAL 下会跨所有实例放大影响。
- 对象存储归档:被截断的 WAL 不是丢弃,而是归档。恢复时要能从归档按需回取。
常见事故:某业务开了一个 30 分钟的分析事务,期间 WAL 在 log service 堆积,压不下去,log service 磁盘写满,全局写入阻塞。解决:分析负载使用只读 snapshot(快照隔离版本 + 不占 WAL 截断),而不是跨在线 WAL 的长事务。
7.3 Page Server 故障
Page server 是 disaggregated 架构里最容易成为单点的组件:
- 故障检测:基于心跳或 lease;lease 太短误检率高,太长恢复慢。
- 接管逻辑:新 page server 起来后需要”追 WAL”。追的过程中收到的 getpage 请求怎么处理?常见做法是”现追现 apply”,但延迟会抖。
- 分区再平衡:一个 page server 挂了,它负责的 partition 要转给其他 page server。转的时候会临时产生跨 page server 的 getpage 请求——注意路由表更新的原子性。
- 冷数据拉回:如果 page 不在 page server 的本地缓存,要从对象存储拉回。这一路径的延迟(几十毫秒)可能突然暴露给上层查询。
7.4 缓存一致性
在 disaggregated 架构里,一致性模型的每一层都要想清楚:
- compute buffer pool 与 page server 之间的一致性:compute 读到的 page LSN 必须 ≥ 它自己已经写过的 WAL LSN(read-your-writes)。
- 多个 compute 之间:如果允许多写(multi-writer),需要全局 LSN 排序 + page server 的版本化 get_page。Aurora 不允许多写,PolarDB 通过共享存储允许从库读主库刚写的 page(但从库不写)。
- page server 多副本:副本间的 WAL apply 进度可能不一致。getpage 请求到某个落后副本时,要么等、要么重路由。
这些都是老问题,但在 disaggregated 架构下表现形式更复杂。实际系统里通常用 “LSN 单调递增 + 显式等待”。参考本仓库《一致性模型》与《会话保证》。
7.5 运维侧的踩坑清单
- 监控维度爆炸:传统数据库一套监控够用;disaggregated 数据库每层都要独立监控,还要看跨层依赖。
- 部署拓扑复杂:cross-AZ / cross-zone 每一跳都要算延迟预算。常见错误是 compute 和 log service 部署在不同 AZ,每次 commit 多出 1ms。
- 版本升级:几层要协同升级,接口兼容性问题会跨版本暴露。推荐设计时就支持 “两个版本共存一段时间”。
- 成本归因:按层计费让成本分析更复杂。需要给每个租户打 tag,跨层汇总。
7.6 一个最小可落地的 disaggregation 实验
如果想在自己的环境里快速验证”共享 WAL + 多只读副本”这条路线,一个非常实用的做法是基于 PostgreSQL 的 streaming replication + 共享存储:
# 1. 一主两从部署,WAL 写在主库本地盘
# 2. 把 WAL archive 配置成共享存储(NFS / 对象存储 + sidecar 同步)
# 3. 从库的 restore_command 从共享存储拉 WAL
# 4. 在主库故障时,让备库从共享 WAL 继续追,而不是依赖主库返回
# postgresql.conf 关键项
archive_mode = on
archive_command = 'aws s3 cp %p s3://my-wal-bucket/%f'
# standby recovery.conf / postgresql.auto.conf
restore_command = 'aws s3 cp s3://my-wal-bucket/%f %p'
primary_conninfo = 'host=primary ...'这个结构和 Aurora / Socrates 的”共享日志”本质一致,只是副本数、故障检测、page 物化方式更朴素。做完这一步,可以真切感受到”WAL 在共享存储”带来的恢复简化与扩展便利。再往上走到 page server 独立、对象存储归档,工程难度会阶跃式增加。
7.6 引入 disaggregation 时,业务端要配合的改变
存算分离不只是基础设施动刀,业务侧也要配合调整。常被忽视的几点:
- 避免长事务:disaggregated 架构下的长事务会横跨 log service / page server 的回收窗口,放大故障面。典型 SOP:把 batch job 改成多段短事务 + 幂等。
- 连接池与 proxy:disaggregated 底层对连接数敏感(大量 compute 伸缩时连接风暴),需要业务统一接入连接池代理。
- schema 变更策略:共享存储下的 DDL 不像单机那么简单,尤其涉及到 page 层布局变化。业务要接受 DDL 被限流、分批执行。
- 读写延迟不一致:写路径加了 log service RTT,通常比单机慢几毫秒;读路径如果命中本地 buffer 几乎无损失。业务的 SLO 描述要分读写。
- 备份与恢复重训:传统 dump/restore 工具可能失效;要使用 disaggregated 存储自己的快照 / clone 能力。
把这些点提前和业务方对齐,上线后的摩擦会少很多。
7.7 disaggregation 的”非目标”
最后值得强调的:存算分离不是银弹。以下问题它不能解决:
- 跨分片事务性能:单主单写的架构,跨分片必须走上层分布式事务。
- SQL 语义复杂度:JOIN / 子查询 / 窗口函数 的优化照样要靠查询优化器。
- 业务侧的数据模型缺陷:反范式化、热点 key 等问题在任何架构下都一样坑。
- 监控与 SRE 熟练度:运维复杂度反而升高,团队需要更好的工具与经验。
一家团队如果带着”上了 Aurora/PolarDB 就能解决一切”的预期,基本必然失望。把存算分离当成更好的底座,而不是万能解药,是最健康的心态。
7.8 一个简化的故障演练清单
自建或选型 disaggregated 数据库时,上线前应至少演练以下故障:
| 故障类型 | 期望行为 | 验证方法 |
|---|---|---|
| 单 compute 进程 kill -9 | 秒级接管,连接在 proxy 层自动重连 | chaos 脚本定期 kill |
| 一个 log service 副本掉线 | 写入延迟 p99 轻微上升,无业务失败 | 把某副本 iptables drop |
| 一个 page server 掉线 | 其负责范围短暂不可读,自动迁移 | 停一台 page server 观察 |
| 对象存储不可达 | 热数据不受影响;冷数据访问失败可见 | 对 S3 断网 10 分钟 |
| 某 AZ 整体失联 | 跨 AZ 部署下仍能读写 | 网络隔离整个 AZ |
| 时钟严重跳变 | 事务不应出现回放错位 | ntp chaos,压 10 秒偏差 |
| 大事务触发 WAL 堆积 | 监控告警;其他事务不受影响 | 注入 1 小时大事务 |
| DDL 与在线事务并发 | DDL 不阻塞业务,或受限可预测 | 在压测中加 DDL |
这张清单不完备,但覆盖了生产中最常见的”突然某一层不可用”场景。真正上线前做一轮,能避免大量”架构纸上谈兵”的问题。
八、disaggregated 架构与分布式事务
disaggregated 架构解决了”单机资源和容灾”问题,但没有直接解决”跨分片事务”问题。具体来说:
- Aurora / PolarDB 默认是单写,跨 region 事务不在架构目标里;
- Socrates / Taurus 也是单主多从,写路径是单一 compute。
如果需要跨分片事务,仍然需要 Spanner / Calvin / Percolator 风格的分布式事务协议(参见本仓库《Spanner》、《Calvin》、《Percolator》)。disaggregated 存储和分布式事务是两个正交维度:
- disaggregated = 纵向切分存算;
- 分布式事务 = 横向切分事务 scope。
NewSQL 系统(TiDB、Spanner、CockroachDB)通常是”横向”的;Aurora 族是”纵向”的;两者可以组合:例如 TiDB 的 TiKV 本身就是存算分离的存储,TiDB compute 与 TiKV storage 分层,然后 TiKV 之间再做分布式事务(见《NewSQL》)。
九、小结
Aurora、Socrates、PolarDB、Taurus 用各自的方式回答同一个问题:当计算节点不再持有权威本地状态时,数据库还能不能跑得快、可靠、便宜?
它们的回答有共性也有差异:
- 共性:日志即数据库;页面按需物化;计算节点趋于无状态;多级缓存;各层独立扩缩。
- 差异:复制粒度(redo vs block)、分层数量(2 vs 3 vs 4)、网络假设(RDMA vs 普通云网)、归档策略(存储层内 vs 独立 XStore)。
读完这四篇论文再看任何一家新的云原生数据库,都可以用同一张”共同骨架”对照:它的 log service 在哪、page server 在哪、compute 本地缓存多厚、归档层是什么?能回答这四个问题,就能判断它到底是”又一个 Aurora 克隆”还是”真的有新设计”。
还有一个重要的观察:这四家的论文发表时间横跨 2017–2020,每家都声称自己是”独立设计”,但呈现出的结构惊人地一致。这不是巧合——当底层硬件(云环境、对象存储、虚拟网络)和业务需求(云原生、高可用、弹性)给定时,最优架构的形态就自然收敛到这几个组件。这是”基于第一性原理设计”的结果,而不是互相抄袭的结果。理解这一点,也能让读者在看未来新系统时,判断它是”在已有范式里做微创新”还是”真的突破了底层假设”。
下一篇《共享内存数据库复兴》换一个视角:当网络变成 RDMA,甚至 CXL 让”内存”跨机器共享时,disaggregated 的假设还成立吗?
Aurora、Socrates、PolarDB、Taurus 用各自的方式回答同一个问题:当计算节点不再持有权威本地状态时,数据库还能不能跑得快、可靠、便宜?
它们的回答有共性也有差异:
- 共性:日志即数据库;页面按需物化;计算节点趋于无状态;多级缓存;各层独立扩缩。
- 差异:复制粒度(redo vs block)、分层数量(2 vs 3 vs 4)、网络假设(RDMA vs 普通云网)、归档策略(存储层内 vs 独立 XStore)。
读完这四篇论文再看任何一家新的云原生数据库,都可以用同一张”共同骨架”对照:它的 log service 在哪、page server 在哪、compute 本地缓存多厚、归档层是什么?能回答这四个问题,就能判断它到底是”又一个 Aurora 克隆”还是”真的有新设计”。
下一篇《共享内存数据库复兴》换一个视角:当网络变成 RDMA,甚至 CXL 让”内存”跨机器共享时,disaggregated 的假设还成立吗?
参考文献
- Verbitski A., et al. Amazon Aurora: Design Considerations for High Throughput Cloud-native Relational Databases. SIGMOD 2017.
- Verbitski A., et al. Amazon Aurora: On Avoiding Distributed Consensus for I/Os, Commits, and Membership Changes. SIGMOD 2018.
- Antonopoulos P., et al. Socrates: The New SQL Server in the Cloud. SIGMOD 2019. https://www.microsoft.com/en-us/research/uploads/prod/2019/05/socrates.pdf
- Cao W., et al. PolarFS: An Ultra-low Latency and Failure Resilient Distributed File System for Shared Storage Cloud Database. VLDB 2018. https://www.vldb.org/pvldb/vol11/p1849-cao.pdf
- Cao W., et al. PolarDB Serverless: A Cloud Native Database for Disaggregated Data Centers. SIGMOD 2021.
- Depoutovitch A., et al. Taurus Database: How to be Fast, Available, and Frugal in the Cloud. SIGMOD 2020.
- Khlystov N., et al. Neon: Serverless PostgreSQL. Neon 技术博客 / arXiv.
上一篇:【数据库研究前沿】Serverless 数据库弹性理论:Neon 与 Aurora Serverless v2
下一篇:【数据库研究前沿】共享内存数据库复兴:RDMA/CXL 下的分布式事务
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【数据库研究前沿】自治数据库十年回顾:Peloton、NoisePage、OtterTune 到云原生 auto-tuning
从 Peloton、NoisePage、OtterTune 到 Aurora / Azure SQL 的自动索引推荐,系统回顾自治数据库十年,并讨论云上 auto-tuning 的踩坑与 SRE 工作流集成
【数据库研究前沿】Serverless 数据库弹性理论:Neon 与 Aurora Serverless v2
从 Aurora 的日志即数据库到 Neon 的 pageserver/safekeeper/compute 三层分离,拆解 Serverless 数据库的冷启动、细粒度伸缩与 copy-on-write 分支,并给出本地可跑的 Neon demo 指引
【数据库研究前沿】系列导论:从 System R 到 AI-Native 的 2026 研究地图
以 System R、Postgres、Bigtable、Spanner、Snowflake 等关键节点串起 50 年数据库史,勾勒 2026 年 AI-Native、向量检索、HTAP 云原生、新硬件、隐私计算、新范式、方法论七条主线,并给出 25 篇系列文章的完整阅读地图。
【数据库研究前沿】如何读数据库顶会论文:SIGMOD/VLDB/CIDR 阅读路线
从顶会定位、检索渠道、三遍读法到工业与学术论文的辨别方法,给出 2023–2025 年数据库领域可信必读二十篇,并配套 CMU 15-721、Stanford CS 245 等公开课清单。