一、WAL 概述

*Write-Ahead Logging(预写式日志)是 He3DB实现事务持久性和崩溃恢复的核心机制。其基本思想是:在任何数据页被写入磁盘之前,必须先将对该页的修改记录到持久化的日志中。这一设计确保了即使在系统崩溃的情况下,已提交的事务也不会丢失,未提交的事务可以被正确回滚。

二、WAL 核心架构

2.1 整体架构图

以下是 WAL 系统的整体架构示意图:

IMG_256

2.2 关键数据结构

2.2.1 XLogRecPtr(日志位置指针)

WAL 使用 64 位的 XLogRecPtr 来唯一标识每一条日志记录的位置。其结构包含:

  • 时间线 ID(TimelineID):标识数据库的历史分支,用于时间点恢复
  • 日志段号(LogSegNo):标识具体的 WAL 段文件
  • 段内偏移(Offset):记录在段文件中的具体位置

2.2.2 WAL 段文件

WAL 日志以固定大小的段文件(Segment)组织,默认大小为 16MB(可通过 --wal-segsize 编译时调整)。文件名格式为:

IMG_256

三、WAL 生成流程

3.1 标准插入流程

当事务执行数据修改操作时,WAL 记录的生成遵循以下流程:

IMG_256

关键步骤说明:

  1. 记录结构:根据操作类型(INSERT/UPDATE/DELETE 等)构造对应的 WAL 记录,包含记录头部和记录内容,记录头部(XLogRecord)包含记录类型、长度、CRC 校验等元信息,记录内容包含具体的变更数据(如 Tuple 数据、页偏移等)。
  2. XLogInsert:将记录插入到 WAL Buffer,包括获取插入锁(WALInsertLock)、分配空间并复制记录数据、更新插入位置指针。
  3. XLogFlush:确保记录持久化到磁盘,包括等待 WAL Writer 或主动刷盘、更新 flushedLSN 标记。

3.2 全页写(Full Page Write)机制

为防止"部分写"(Torn Page)问题,PG 在检查点后首次修改数据页时,会将整个数据页的内容写入 WAL。

检查点发生后第一次修改页生成的WAL记录格式如下:

WAL Record Header

Block Header (页标识信息)

完整数据页镜像 (8KB)

实际变更记录 (如Tuple变更)

在崩溃恢复时,即使数据文件中的页处于不一致状态,也可以从 WAL 中恢复完整页面。

四、WAL 写入与刷盘机制

4.1 三层缓冲架构

IMG_256

4.2 WAL Writer 进程

WAL Writer 是一个后台进程,负责定期将 WAL Buffer 中的内容写入磁盘。

触发条件:

  • 周期性触发(默认 200ms,由 wal_writer_delay 控制)
  • WAL Buffer 满或接近满
  • 事务提交要求(synchronous_commit 设置)

写入策略:

  • 批量写入:一次尽可能多地写入连续空间
  • 顺序写优化:WAL 文件采用追加写模式,充分利用磁盘顺序写性能

4.3 同步提交策略

He3DB 提供多种同步提交级别,在性能和数据安全之间提供灵活选择:

级别

行为

适用场景

on

每次事务提交都等待 WAL 刷盘

默认,最高安全性

remote_apply

等待备库应用 WAL

读写分离场景

remote_write

等待备库接收 WAL

容灾场景

local

只等待本地 WAL 刷盘

单机高性能

off

不等待,由后台进程异步刷盘

最高性能,可能丢数据

五、WAL 归档与清理

5.1 归档机制

WAL 归档用于将已写满的 WAL 段文件复制到外部存储,支持 PITR(Point-In-Time Recovery):

IMG_256

关键配置参数:

  • archive_mode:启用归档
  • archive_command:自定义归档命令
  • archive_timeout:强制切换 WAL 段的时间间隔

5.2 WAL 清理策略

He3DB通过以下机制自动管理 WAL 文件:

  • 检查点回收:检查点完成后,之前的 WAL 不再需要用于崩溃恢复,可以删除或归档
  • 复制槽保护:逻辑复制或物理复制使用的复制槽会保护 WAL 不被过早删除
  • 归档状态跟踪:archive_status 目录跟踪每个段的归档状态

目录结构示例:

wal_dir/
├── 000000010000000000000001
├── 000000010000000000000002
├── 000000010000000000000003.ready (等待归档)
├── 000000010000000000000004.done (已归档)
└── archive_status/
├── 000000010000000000000003.ready
└── 000000010000000000000004.done

六、WAL 回放(Recovery)

6.1 崩溃恢复流程

当数据库异常关闭后重启时,会自动执行崩溃恢复:

IMG_256

6.2 回放关键机制

资源管理器(Resource Manager):

He3DB将回放操作按资源类型划分,每种资源有对应的处理函数:

资源管理器

职责

RM_XLOG

WAL 自身管理(检查点、时间线切换等)

RM_XACT

事务管理(提交、中止、准备事务)

RM_HEAP

堆表操作(插入、删除、更新)

RM_BTREE

B-Tree 索引操作

RM_GIN/GIST/SPGIST/BRIN

其他索引类型

回放优化:

  • 预取(Prefetch):He3DB并行回放优化
  • 延迟回放:备库可配置延迟应用,防止误操作传播

七、He3DB中 WAL 相关的新特性与优化

7.1 性能优化

  • 压缩 WAL 归档:支持 wal_compression = zstd/lz4,减少归档存储和网络传输开销
  • 增强的统计视图:pg_stat_wal 视图提供更详细的 WAL 活动统计
  • 批量提交优化:改进组提交(Group Commit)机制,提高高并发场景下的吞吐量

7.2 可靠性增强

  • 校验和增强:WAL 记录头部的 CRC 校验更加严格
  • 时间线管理改进:简化时间线切换流程,提高 PITR 可靠性

八、关键配置参数总结

参数名

默认值

说明

wal_level

replica

WAL 详细程度(minimal/replica/logical)

wal_buffers

-1

WAL Buffer 大小(-1 表示自动)

wal_writer_delay

200ms

WAL Writer 刷盘间隔

checkpoint_timeout

5min

检查点触发间隔

max_wal_size

1GB

WAL 最大累积大小

min_wal_size

80MB

WAL 最小保留大小

archive_mode

off

归档模式

synchronous_commit

on

同步提交级别

九、总结

WAL 模块是一个经过精心设计的日志系统,其核心设计原则包括:

  • 先日志后数据:确保数据持久性的黄金法则
  • 顺序写优化:WAL 的追加写模式最大化磁盘 I/O 效率
  • 灵活的配置:多种同步级别和压缩选项适应不同场景
  • 可靠的恢复:完善的崩溃恢复和 PITR 机制

理解 WAL 的工作原理对于He3DB 的运维优化、故障排查和架构设计都至关重要。在实际生产环境中,建议根据业务对数据安全的要求,合理配置 synchronous_commit、wal_level 等关键参数,在性能和可靠性之间取得平衡。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐