暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PolarDB 共享存储架构下的"过去页面"问题解析

PolarDB 2025-12-31
131

PolarDB 共享存储架构下的"过去页面"问题解析

问题根源:为什么从库会读到过旧的 block

在 PolarDB 共享存储架构下,从库(只读节点)可能读到过旧页面的根本原因是:

  1. 内存淘汰机制:从库回放 WAL 后生成的新版本页面存储在 Buffer Pool 中,当 Buffer Pool 空间不足时,这些页面会被淘汰
  2. 主库刷脏延迟:主库不会立即将所有修改后的页面刷写到共享存储
  3. 版本不一致:当从库再次访问已被淘汰的页面时,从共享存储读取的是旧版本页面

具体流程:

// T1: 主库更新页面 P1 从版本 500 到 600,生成 WAL LSN=200  
// T3: 从库回放 WAL,内存中 P1 版本为 600    
// T4: 从库 Buffer Pool 淘汰 P1 页面  
// T5: 从库再次访问 P1,从共享存储读取到版本 500(过旧页面)  

解决方案:LogIndex 机制

PolarDB 通过 LogIndex 机制解决过去页面问题,核心思想是维护页面到 WAL 记录的映射关系  :

1. LogIndex 数据结构

LogIndex 是一个可持久化的 HashTable 结构:

  • Key: PageTag(标识具体数据页)
  • Value: 修改该页面的所有 LSN 列表

2. 内存中的 LogIndex Memtable

// LogIndex Memtable 包含三个关键数组  
- HashTable: 记录 Page 与 LSN List 的映射  
- Segment: 存储 LogIndex Item,包含 LSN 链表  
- Index Order: 记录 LogIndex 添加顺序  

3. 延迟回放机制

从库的 Startup 进程基于 WAL Meta 生成 LogIndex,但不立即回放:

// 接收 WAL Meta 后:  
1. 生成 LogIndex 记录  
2. 将 Buffer Pool 中对应页面标记为 Outdate    
3. 推进回放位点(不实际回放数据)  
4. 实际回放延迟到访问时进行  

代码实现细节

1. WAL Meta 处理

主库只传输 WAL Meta(不包含 payload)到从库:

// WAL Record 结构  
struct XLogRecord {  
    general header portion;  // 元数据部分  
    data portion;           // 数据部分(不传输)  
}  

2. 页面回放触发

当从库访问页面时检查是否需要回放:

bool polar_logindex_restore_fullpage_snapshot_if_needed(  
    polar_logindex_redo_ctl_t instance,   
    BufferTag *tag,   
    Buffer *buffer)
  
{  
    // 检查是否是未来页面  
    if (!polar_is_future_page(GetBufferDescriptor(*buffer - 1)))  
        return false;  
          
    // 通过 LogIndex 查找需要回放的 WAL  
    // 从共享存储读取 WAL 并回放  
}  

3. 并行回放优化

从库实现两种回放方式:

  • 背景回放进程:按 WAL 顺序依次回放 Buffer Pool 中的页面
  • Backend 进程:仅回放实际访问的页面

避免过旧页面的配置

1. 启用 LogIndex

# 必须启用共享存储模式  
polar_enable_shared_storage_mode=on  

# 配置 LogIndex 内存大小  
polar_logindex_mem_size=64MB  

2. 优化 Buffer Pool

# 适当增大 Buffer Pool 减少页面淘汰  
shared_buffers=4GB  

# 启用复制缓冲区处理热点页面  
polar_enable_copy_buffer=on  
polar_copy_buffer_size=128MB  

3. 监控关键指标

-- 监控 LogIndex 状态  
SELECT * FROM polar_logindex_stat();  
  
-- 检查页面回放情况    
SELECT * FROM polar_stat_buffercache();  
  
-- 监控刷脏延迟  
SELECT * FROM polar_stat_io_info;  

Notes

  • LogIndex 机制通过延迟回放和并行回放,将 WAL 回放延迟降低到毫秒级
  • 从库读取页面时,会先检查 Buffer Pool,若不存在或已过期,则通过 LogIndex 找到需要回放的 WAL 记录
  • LogIndex 记录会异步刷写到共享存储,确保持久化
  • 通过 Bloom Filter 优化 LogIndex 查找效率

文章转载自PolarDB,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论