阅读 SIGMOD 2024 一篇来自 Purdue University 的论文,关于存算分离数据库,做一些关键信息的摘要记录
简介
存算分离架构在云数据库中广泛使用,包括 Amazon Aurora/MicroSoft Socrates/Google AlloyDB/Alibaba PolarDB/Huawer Taurus。
传统非存算分离的架构,会把数据库的存储和计算聚合在同一物理机器上;而存算分离架构下,计算通过网络来访问存储,这样的设计能够独立去扩容计算或存储,在提升资源利用率、降低成本、故障快速恢复上有优势。
存算分离数据库通常会满足以下设计原则:
设计原则 P1:存储计算引擎隔离
- 存储引擎(包括 Logging 和 Storage)和计算引擎(包括 SQL Layer、Buffering、Transaction)部署在不同的物理节点
- 这种分离架构核心是把存储访问变成远程/共享存储,如果没有缓冲层,远程访问的性能会非常差
设计原则 P2:Log as the Database(LogDB)
- 为了降低计算引擎-存储引擎之间的网络开销,除了适用 Buffering,存算分离架构通常会引入 Log as the Database 设计
- 仅在事务提交时把 WAL 同步到存储层,而不去同步数据 Page,减少网络上需要传输的数据
- 存储引擎层通过异步回放 WAL 来获得真实的数据 Page
设计原则 P3:Shared-Storage 架构
- Shared-Storage 是相对于 Shared-Nothing 来讲的,指不同的计算引擎共享一份存储引擎数据,减少拷贝和异动数据
- 因为主从计算节点的同步延时,从节点可能需要读取老版本数据,Shared-Storage 需要支持 Multi-Version Pages
这里明确几个实现上的细节:
- 讨论 P2 LogDB 的时候,通常是做了 P1 存储计算引擎分离
- 讨论 P3 Shared-Storage 的时候,通常是做了 P1 存储计算引擎分离和 P2 LogDB
架构实现
XLog 是 PostgreSQL 中的 WAL
单体架构
下图是 PostgreSQL(v13.0) 的架构,数据库整体跑在单个节点上

远程盘
- 存储引擎和计算引擎拆分到不同的节点上,之间走网络通信
- 读写流程和单体架构没区别,核心是本地读写改成远程读写
- 远程盘的优势是独立扩容,其次是 LogDB 架构的基础

Log as the Database(LogDB)
- 远程盘因为网络开销表现会比较差,优化一方面是引入 Buffering,其次就是 LogDB
- 写路径在事务提交阶段,把 WAL 发送给存储节点,实际的数据 Page 通过在存储节点异步回放 WAL 生产(Step a/b)
- 读路径计算节点先检查 Local Buffer,Cache Miss 时从存储节点加载 Page 数据,如果此时 Page 数据尚未完成回放,会同步开始回放(Step1)
- 传统数据库也会有异步刷脏的设计,仅从架构角度不能说 LogDB 传输 Log 而非 Page 的方式,一定比单体架构性能高

多版本 LogDB(LogDB-MV)
- Shared-Storage 架构下不同计算节点共享同一个存储层,假设此时是单 Primary-多 Secondary 计算节点
- Primary 节点支持读写事务
- Secondary 节点仅支持只读事务
- Primary 把数据更新异步同步给 Secondary,因为延时 Secondary 可能读取老版本 Page,这个称为 GetPage@LSNmailto:GetPage@LSN
- 存储节点回放 WAL 时保存 Page 的多个版本
- 存储引擎维护 VersionMap,PageID-LSM 的映射(Step a)
- WAL 会拆分程 miniWAL,每个 miniWAL 仅包含一个 Page 的修改,回放阶段会把多个 Page 数据用 PageID+LSN 作为 Key 插入 RocksDB
- GetPage@LSNmailto:GetPage@LSN 请求首先同步等待回放进程完成读请求 LSN 的处理,然后从 VersionMap 中获取指定 PageID 的 Version LSN 列表, 从 RocksDB 中把小于等于请求 LSN 的 Page 数据加载出来,正常最终的 Page 数据
- 多版本的支持增加了 RocksDB 的写压力

为了加速读路径,LogDB-MV 提供 Filtered Replay 和 SmartReplay 两种优化思路。
- FilteredReplay:GetPage@LSN 阶段,通过 QuickScan 跳过和当前 Page 无关的 LSN,加速读

- SmartReplay:GetPage@LSN 阶段只去回放 Page 相关的 LSN,不同 Page 的回放可以多进程并行

测试数据
测试设置
- 计算节点 x 16(1 写 15 读)
- 写节点配置:Intel Xeon Gold 6330 CPU(2.0GHZ), 250GB DRAM, 1.5TB NVMe SSD
- 读节点配置:Intel Xeon Silver CPU (2.3 GHz), 64GB DRAM, and a 900GB NVMe SSD
- 存储节点 x 3(也测试了一版 6 存储节点,模拟 Aurora 架构)
- 节点配置:Intel Xeon Platinum 8368 CPU(2.4GHZ), 188GB DRAM, 1.5TB NVMe SSD
- 测试环境:Ubuntu 22.04, 10Gb TCP/IP 网络
- 测试数据:SysBench 和 TPC-C
- SysBench:2000 张表,每张表 20w 行数据,整体数据库大小 96GB
读写性能
单体架构 vs 远程盘
- 计算节点 Buffer 越大,读性能越高
- 计算节点 Buffer 超过 700MB 后,增加 Buffer 对写性能提升不大
- 主要是生成的脏页在 700MB 左右
- 在 Heavy workload 下,这个阈值会稍高
- 写性能在远程盘情况下,劣化严重

远程盘 vs LogDB
- 读性能相当
- LogDB 在写性能上优化明显,特别是 Heavy workload 下最大提升 2.5X(8GB buffer)
- Ligh workload 下,两种架构写性能相当,原因是低负载下有足够的时间去异步刷脏,同时也意味着 LogDB 本身并没有提升写性能
- Heavy workload 下,远程盘架构刷脏吞吐不够会阻塞写请求,而 LogDB 没有刷脏进而获得吞吐提升

写后读场景
- 持续 5min 写入
- LogDB 落后远程盘 20.3%
- LogDB-MV 落后远程盘 66.2%
- Gap 主要是回放日志的开销

LogDB vs. LogDB-MV
- Multi-Version 主要影响写,不影响读性能
- 一条 WAL 对应多个 Page,都要插入 RocksDB
- 移除写放大问题,Multi-Version 的写性能提升 37%

读性能水平扩展
- 水平扩容计算节点提升吞吐

FR vs. SR
- 只读请求不受 FR/SR 影响,优化混合读写场景
- FR 大幅度减少 LSN 回放,相比 LogDB-MV 写吞吐提升 50%
