PostgreSQL WAL解析与闪回的一些想法

本文涉及的产品
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介: 最近在walminer基础做了不少修改,以支持我们的使用场景。详细参考 如何在PostgreSQL故障切换后找回丢失的数据 修改也花了不少精力和时间,这个过程中有些东西想记录下来,方便以后查阅。

PostgreSQL WAL解析与闪回的一些想法

1. 背景

最近在walminer基础做了不少修改,以支持我们的使用场景。详细参考

修改也花了不少精力和时间,这个过程中有些东西想记录下来,方便以后查阅。

所以,这篇东西有点像流水账。

2. WAL文件格式

解析WAL的第一步是要了解WAL的文件格式,我觉得最详细易懂最值得看的资料是下面这个。

但是,以上还不够。细节的东西还是要看源码。我主要看的是写WAL记录的地方。

walminer作者李传成的博客里也有不少WAL解析相关的文章,是后来才发现的,我还没有看过。

3. walminer的解析流程

walminer解析WAL的入口是pg_minerXlog()函数。其主要过程如下

  1. 加载数据字典
  2. 起点搜索解析阶段

    遍历WAL,根据输入的起始时间和起始xid找到匹配的第一个事务。
    这个阶段只解析事务类型的WAL记录,其他WAL记录快速跳过。
  3. 完全解析阶段

    紧接着2的位置,继续往下进行完整的解析。
    这个阶段,会收集所有FPI(FULL PAGE IMAGE)并反映它们的变更,
    还会收集所有DML(insert/update/delete)类型的WAL记录,
    并且在遇到事务提交WAL时输出该事务对应的DML,事务回滚时清空该事务对应的DML。
    

walminer把WAL记录中tuple变成SQL的过程比较有意思,中间用了一个VALUES的临时格式。

以下面这个UPDATE语句为例

update tb1 set c1='3xy' where id=3;

其解析过程中涉及到的一些调用点如下:

pg_minerXlog()
 ->sqlParser()
  ->XLogMinerRecord()
   ->XLogMinerRecord_heap()
    ->minerHeapUpdate(XLogReaderState *record, XLogMinerSQL *sql_simple, uint8 info)
     1. 获取更新前后的tuple值(字符串格式)
     ->getTupleInfoByRecord()
      ->getTupleData_Update()
       ->mentalTup()
        ->mentalTup_nulldata()
        ->mentalTup_valuedata()
         tupleInfo:VALUES(-3, '3x')"
         tupleInfo_old:VALUES(3, NULL)
        
     2. 生成中间redo SQL
     ->getUpdateSQL(sql_simple, tupleInfo, tupleInfo_old,...)
       sql_simple:UPDATE \"public\".\"tb1\" SET VALUES(3, '3xy') WHERE VALUES(3, '3x')
       
     3. 生成中间undo SQL
     ->getUpdateSQL(&srctl.sql_undo, tupleInfo_old, tupleInfo,...)
       srctl.sql_undo:UPDATE \"public\".\"tb1\" SET VALUES(3, '3x') WHERE VALUES(-3, '3xy')"

     4. 生成最终undo SQL
     将中间中" VALUES"之后部分抹去,从rrctl.values,rrctl.nulls,rrctl.values_old,rrctl.nulls_old重新生成SQL后半部分。
     ->reAssembleUpdateSql(&srctl.sql_undo,true);
       srctl.sql_undo:UPDATE "public"."tb1" SET "c1" = '3x' WHERE "id"=3 AND "c1"='3xy' AND ctid = '(0,10)';
      
   
pg_minerXlog()
 ->sqlParser()
  ->parserUpdateSql()
   4. 生成最终redo SQL
   ->reAssembleUpdateSql(sql_ori, false)
   sql_ori:UPDATE "public"."tb1" SET "c1" = '3xy' WHERE "id"=3 AND "c1"='3x';

4. walminer存在的问题

walminer是个非常棒的工具,填补了PG的一个空白。
但是,在我们准备把它推向生产时发现了不少问题。

  1. 资源消耗和解析速度

    • 粗测了一下,解析一个16MB的WAL文件大概需要15秒。不得不说实在太慢了。
    • 解析大量WAL文件还容易把内存撑爆。
  2. 正确性和可靠性

    • 对并发事务产生的WAL记录,解析的结果不对。
    • 缺少回归测试集
    • 其他的小问题。
  3. 易用性

    • 不支持基于LSN位置的过滤
    • 解析一次WAL要调用好几个函数,我觉得没有必要,一个就够了。

对这些已知的问题,都进行了改进。主要有下面几点

  1. 使用单个wal2sql()函数执行WAL解析任务
  2. 支持指定起始和结束LSN位置过滤事务
  3. 支持从WAL记录的old tuple或old key tuple中解析old元组构造where条件
  4. 增加lsn和commit_end_lsn结果输出字段
  5. 添加FPI(FULL PAGE IMAGE)解析开关,默认关闭image解析
  6. 优化WAL解析速度,大约提升10倍
  7. 给定LSN起始位置后,支持根据WAL文件名筛选,避免大量冗余的文件读取。
  8. 修复多个解析BUG
  9. 增加回归测试集
    10.合并PG10/11/12支持到一个分支

修改后的walminer参考

https://gitee.com/skykiker/XLogMiner

后续希望这些修改能合到源库里。

5. 后续改进思路

walminer在功能和使用场景上和MySQL的binlog2sql是非常接近的。

binlog2sql对自己的场景描述如下:

https://github.com/danfengcao/binlog2sql

  • 数据快速回滚(闪回)
  • 主从切换后新master丢数据的修复
  • 从binlog生成标准SQL,带来的衍生功能

binlog2sql已经有很多生产部署的案例,但是walminer好像还没有。
其中原因,我想除了修改版已经解决的那些问题,walminer作为闪回工具,还有进一步改进的空间。

我考虑主要有以下几点可以改进的

  1. 以fdw的形式提供接口
    和函数相比fdw的好处是明显的

    • 不需要等所有WAL都解析完了再输出,因此可以结合limit进行多次快速探测
    • 不需要创建临时表,解析过程中不需要产生WAL(产生WAL可能会触发WAL清理)。
    • 可以在备库执行
      使用fdw后,过滤条件直接通过where条件传递,接口更清晰。无法通过where条件传递东西,比如WAL存储目录,可以通过设置参数解决。
  2. 把解析过程分成事务匹配探测和完全解析2个部分
    完全解析时,需要从匹配的事务往前回溯一部分,确保该事务的SQL甚至所需FPI都被解析到。
    单纯从匹配的事务后面开始完全解析,会丢失SQL的。
  3. 增加DDL解析
    其实并不需要解析出完整的DDL和逆向的闪回DDL,这个任务也很难实现。
    只需要能知道什么时间,在WAL的哪个位点,哪个表发生了定义变更即可。
  4. 代码重构
    从性能和可维护性考虑,有必要进行代码重构。
  5. 工具命名
    既然这个工具的功能是从WAL中解析出原始SQL和undo SQL,walminer这个名称就显得不合适了。
    因为从字面上理解,walminer应该是解析WAL本身包含的信息,包括很多与SQL无关的的信息,
    但是不应该包含undo SQL这种WAL里没有而完全是被构造出来的东西。
    所以,顾名思议,这个东西可以叫wal2sql。

6. 参考

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
7月前
|
存储 Oracle 关系型数据库
postgresql数据库|wal日志的开启以及如何管理
postgresql数据库|wal日志的开启以及如何管理
1242 0
|
7月前
|
存储 关系型数据库 数据库
postgresql|数据库|提升查询性能的物化视图解析
postgresql|数据库|提升查询性能的物化视图解析
700 0
|
6月前
|
SQL 关系型数据库 数据库连接
ClickHouse(20)ClickHouse集成PostgreSQL表引擎详细解析
ClickHouse的PostgreSQL引擎允许直接查询和插入远程PostgreSQL服务器的数据。`CREATE TABLE`语句示例展示了如何定义这样的表,包括服务器信息和权限。查询在只读事务中执行,简单筛选在PostgreSQL端处理,复杂操作在ClickHouse端完成。`INSERT`通过`COPY`命令在PostgreSQL事务中进行。注意,数组类型的处理和Nullable列的行为。示例展示了如何从PostgreSQL到ClickHouse同步数据。一系列的文章详细解释了ClickHouse的各种特性和表引擎。
188 0
|
7月前
|
SQL 关系型数据库 数据库
实时计算 Flink版产品使用合集之同步PostgreSQL数据时,WAL 日志无限增长,是什么导致的
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
7月前
|
SQL 关系型数据库 API
从API获取数据并将其插入到PostgreSQL数据库:步骤解析
使用Python处理从API获取的数据并插入到PostgreSQL数据库:安装`psycopg2`,建立数据库连接,确保DataFrame与表结构匹配,然后使用`to_sql`方法将数据插入到已存在的表中。注意数据准备、权限设置、性能优化和安全处理。
|
7月前
|
SQL 关系型数据库 数据库
postgresql|数据库|pg数据库的文件系统详解---最全面的解析
postgresql|数据库|pg数据库的文件系统详解---最全面的解析
721 0
|
前端开发 关系型数据库 Go
《PostgreSQL事务管理深入解析》
《PostgreSQL事务管理深入解析》
148 0
|
关系型数据库 数据库 PostgreSQL
PostgreSQL 的事务管理和并发控制机制解析
PostgreSQL 的事务管理和并发控制机制解析
298 0
|
关系型数据库 分布式数据库 PolarDB
《阿里云产品手册2022-2023 版》——PolarDB for PostgreSQL
《阿里云产品手册2022-2023 版》——PolarDB for PostgreSQL
368 0
|
存储 缓存 关系型数据库

推荐镜像

更多