PolarDB lazy 回放机制介绍
Lazy回放是PolarDB在存算分离架构下为提升只读节点(RO)日志回放效率而设计的核心机制,通过延迟回放和并行回放显著降低了主备延迟 。
核心原理
设计思想
Lazy回放的核心思想是将日志回放操作分为两个阶段:
快速解析阶段:Startup进程快速解析WAL Meta,生成LogIndex并推进回放位点 按需回放阶段:实际的数据页回放延迟到真正访问该页面时进行
与传统回放对比
技术实现
1. WAL Meta解析
RO节点接收主节点发送的WAL Meta而非完整WAL日志:
// Startup进程解析WAL Meta生成LogIndex
static void
polar_startup_parse_wal_meta(void)
{
// 从WAL Meta queue中读取meta数据
// 解析生成LogIndex记录
// 标记Buffer Pool中的页面为Outdate
}
2. LogIndex结构
LogIndex是一个可持久化的HashTable,维护Page到LSN的映射:
Key: PageTag(标识具体数据页) Value: 修改该Page的所有LSN列表
3. 延迟回放实现
当RO节点需要读取数据页时,触发实际的回放操作:
XLogRecPtr
polar_logindex_apply_page(polar_logindex_redo_ctl_t instance,
XLogRecPtr start_lsn, XLogRecPtr end_lsn,
BufferTag *tag, Buffer *buffer)
{
// 从LogIndex获取需要回放的LSN列表
// 逐个应用WAL日志到目标页面
// 返回回放后的最新LSN
}
看到这里, 我更愿意把lazy回放解释为两阶段回放, 第一阶段是解析wal日志, 转换为倒排索引(logindex), 第一阶段完成后就已经实现了RO节点的apply lsn位点推进. 第二阶段是按需回放(因主节点刷脏后, page可能已经不需要在RO进行回放了).
并行回放机制
背景回放进程
Lazy回放支持后台进程主动回放:
static bool
polar_logindex_apply_xlog_background(polar_logindex_bg_redo_ctl_t *ctl)
{
// 批量回放存在的Buffer页面
for (replayed_count = 0; replayed_count < ctl->replay_batch_size; replayed_count++)
{
polar_only_replay_exists_buffer(ctl->instance, ctl->state, ctl->replay_page);
}
}
Backend进程回放
当用户进程访问页面时,按需进行回放:
bool
polar_logindex_lock_apply_page_from(polar_logindex_redo_ctl_t instance,
XLogRecPtr start_lsn, BufferTag *tag, Buffer *buffer)
{
// 获取页面锁
// 按需回放日志到指定LSN
// 返回页面LSN是否发生变化
}
实际应用流程
页面读取流程

关键优化点
避免Cache Miss:不存在的页面仅记录LogIndex,不立即回放 并行回放:Backend进程和背景进程并行回放不同页面 I/O Offload:将回放I/O操作从单个进程分散到多个用户进程
性能优势
延迟降低
通过Lazy回放机制,PolarDB实现了:
**网络传输量减少98%**:仅传输WAL Meta而非完整WAL 回放速度提升30倍:相比AWS Aurora的回放性能
资源利用优化
内存效率:避免不必要的页面加载和淘汰 CPU效率:并行回放充分利用多核资源 I/O效率:按需回放减少无效I/O操作
Mini Transaction保证
一致性机制
为防止并行回放导致的数据不一致,PolarDB引入Mini Transaction锁机制:
// 获取页面的mini transaction锁
page_lock = polar_logindex_mini_trans_cond_lock(instance->mini_trans, tag, LW_EXCLUSIVE, NULL);
// 执行回放操作
start_lsn = polar_logindex_apply_page_from(instance, start_lsn, tag, buffer, page_lock);
// 释放锁
if (page_lock != POLAR_INVALID_PAGE_LOCK)
polar_logindex_mini_trans_unlock(instance->mini_trans, page_lock);
原子性保证
Mini Transaction确保:
同一WAL记录修改的多个页面要么全部回放,要么全部不回放 防止B+Tree索引结构因部分回放而损坏
故障恢复支持
Lazy Recovery
Lazy回放机制同样适用于主节点的故障恢复:
从checkpoint点开始解析WAL日志 生成LogIndex后即认为恢复完成 实际回放操作延迟到重启后的用户访问时进行
恢复时间优化
通过Lazy Recovery,500MB日志量的恢复时间显著缩短 。
Notes
Lazy回放是PolarDB 1.0版本的核心功能,专门为存算分离架构设计 在版本3.0中进一步引入了并行回放机制,与Lazy回放协同工作 Lazy回放机制需要配合Persistent BufferPool使用,以避免重启后的性能抖动
文章转载自PolarDB,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




