PolarDB PostgreSQL版(以下简称 PolarDB-PG)是一款阿里云自主研发的企业级数据库产品,采用计算存储分离架构,兼容 PostgreSQL 与 Oracle。PolarDB-PG 的存储与计算能力均可横向扩展,具有高可靠、高可用、弹性扩展等企业级数据库特性。同时,PolarDB-PG 具有大规模并行计算能力,可以应对 OLTP 与 OLAP 混合负载;还具有时空、向量、搜索、图谱等多模创新特性,可以满足企业对数据处理日新月异的新需求。
低延迟复制
传统流复制的问题
- 同步链路:日志同步路径 IO 多,网络传输量大。
- 页面回放:读取和 Buffer 修改慢(IO 密集型 + CPU 密集型)。
- DDL 回放:修改文件时需要对修改的文件加锁,而加锁的过程容易被阻塞,导致 DDL 慢。
- 快照更新:RO 高并发引起事务快照更新慢。
如下图所示:
- 主节点写入 WAL 日志到本地文件系统中。
- WAL Sender 进程读取,并发送。
- 只读节点的 WAL Receiver 进程接收写入到本地文件系统中。
- 回放进程读取 WAL 日志,读取对应的 Page 到 BufferPool 中,并在内存中回放。
- 主节点刷脏页到 Shared Storage。
可以看到,整个链路是很长的,只读节点延迟高,影响用户业务读写分离负载均衡。
优化 1:只复制 Meta
因为底层是 Shared-Storage,只读节点可直接从 Shared-Storage 上读取所需要的 WAL 数据。因此主节点只把 WAL 日志的元数据(去掉 Payload)复制到只读节点,这样网络传输量小,减少关键路径上的 IO。如下图所示:
- WAL Record 是由:Header,PageID,Payload 组成。
- 由于只读节点可以直接读取 Shared-Storage 上的 WAL 文件,因此主节点只把 WAL 日志的元数据发送(复制)到只读节点,包括:Header,PageID。
- 在只读节点上,通过 WAL 的元数据直接读取 Shared-Storage 上完整的 WAL 文件。
通过上述优化,能显著减少主节点和只读节点间的网络传输量。从下图可以看到网络传输量减少了 98%。
优化 2:页面回放优化
在传统 DB 中日志回放的过程中会读取大量的 Page 并逐个日志 Apply,然后落盘。该流程在用户读 IO 的关键路径上,借助存储计算分离可以做到:如果只读节点上 Page 不在 BufferPool 中,不产生任何 IO,仅仅记录 LogIndex 即可。
可以将回放进程中的如下 IO 操作 offload 到 session 进程中:
- 数据页 IO 开销。
- 日志 apply 开销。
- 基于 LogIndex 页面的多版本回放。
如下图所示,在只读节点上的回放进程中,在 Apply 一条 WAL 的 meta 时:
- 如果对应 Page 不在内存中,仅仅记录 LogIndex。
- 如果对应的 Page 在内存中,则标记为 Outdate,并记录 LogIndex,回放过程完成。
- 用户 session 进程在读取 Page 时,读取正确的 Page 到 BufferPool 中,并通过 LogIndex 来回放相应的日志。
- 可以看到,主要的 IO 操作有原来的单个回放进程 offload 到了多个用户进程。
通过上述优化,能显著减少回放的延迟,比 AWS Aurora快速三十倍。
优化 3:DDL 锁回放优化
在主节点执行 DDL 时,比如:drop table,需要在所有节点上都对表上排他锁,这样能保证表文件不会在只读节点上读取时被主节点删除掉了(因为文件在 Shared-Storage 上只有一份)。在所有只读节点上对表上排他锁是通过 WAL 复制到所有的只读节点,只读节点回放 DDL 锁来完成。而回放进程在回放 DDL 锁时,对表上锁可能会阻塞很久,因此可以通过把 DDL 锁也 offload 到其他进程上来优化回放进程的关键路径。
通过上述优化,能够回放进程一直处于平滑的状态,不会因为去等 DDL 而阻塞了回放的关键路径。
上述 3 个优化之后,极大的降低了复制延迟,能够带来如下优势:
- 读写分离:负载均衡,更接近 Oracle RAC 使用体验。
- 高可用:加速 HA 流程。
- 稳定性:最小化未来页的数量,可以写更少或者无需写页面快照。