PG wal日志解析工具功能增强并更名为WalMiner

Download

2019/12/05

李传成Contributor

瀚高软件内核研发工程师,主要的研究wal日志,并基于对wal日志的理解开发了wal相关的开源项目walminer和pg_lightool

在大象的世界里,砥砺前行,move ahead。

博客:https://my.oschina.net/lcc1990

使用软件遇到问题可先更新代码(欢迎提交bug)~~

开发群组:811105058欢迎任何使用者


XlogMiner是从PostgreSQL的WAL(write ahead logs)日志中解析出执行的SQL语句的工具,并能生成出对应的undo SQL语句。此版本使用限制较大,需要将wal级别设置为logical,而且需要将表设置为IDENTITY FULL模式。这会加剧wal日志的膨胀,降低数据库性能。为迎合PG日志名称的改变,现将XlogMiner改名为WalMiner。新的开源地址为:https://gitee.com/movead/XLogMiner


WalMiner功能增强

1.WalMiner支持解析minimal级别以上的任何wal日志级别。

2.无需将表设置为IDENTITY FULL模式。

3.增加对系统表修改的wal记录的解析。

4.修复发生relfilenode变化后,异库解析失败的bug。

WalMiner带来的新的限制

walminer可以完整的解析出给定的wal日志中第一个checkpoint点之后的所有wal记录。第一个checkpoint点之前的delete和update记录可能会解析失败,如下。

UPDATE "public"."t1" SET VALUES(NULL) (NOTICE:wal is not enought.);

如果一定需要将此记录解析出来,那么只需要增加更早的wal日志即可。

使用方法一

1.编译安装

代码下载地址:https://gitee.com/movead/XLogMiner/releases

编译安装:将下载的代码中的walminer目录放置到数据库代码的contrib目录下,执行make;make install

[lichuancheng@IP43 walminer]$ pwd /work/src/lichuancheng/postgresql-11.1/contrib/walminer[lichuancheng@IP43 walminer]$ make;make install

2.创建extension

postgres=# create extension walminer; CREATE EXTENSIONpostgres=#

3.插入测试数据

postgres=# create table t2(i int,j int, k varchar); CREATE TABLE postgres=# insert into t2 values(1,1,'qqqqqq'); INSERT 0 1 postgres=# insert into t2 values(2,2,'wwwwww'); INSERT 0 1 postgres=# insert into t2 values(3,3,'eeeee'); INSERT 0 1 postgres=# update t2 set k = '1111qqqqq' where i = 1; UPDATE 1 postgres=# delete from t2 where j = 2; DELETE 1 postgres=# insert into t2 values(4,4,'44444rrrrrr'); INSERT 0 1 postgres=# select pg_walfile_name(pg_current_wal_lsn());     pg_walfile_name -------------------------- 00000001000000000000000A(1 row)postgres=# select pg_switch_wal(); pg_switch_wal --------------- 0/A003508(1 row)postgres=#

手动备份这个需要解析的wal日志(此处我没有开归档,做这个手动备份防止wal日志被数据库移除)

[lichuancheng@IP43 pg_wal]$ cp 00000001000000000000000A 111/[lichuancheng@IP43 pg_wal]$

4.指定需要解析的wal日志

(wal日志可以放置在任意位置,也可同时指定多个wal日志)

postgres=# select walminer_wal_add('pg_wal/111/00000001000000000000000A');NOTICE:  Get data dictionary from current database.  walminer_wal_add -------------------- 1 file add success(1 row)

5.执行解析

解析方法1:postgres=# select walminer_start('NULL','NULL',0,0);   walminer_start --------------------- walminer sucessful!(1 row)解析方法2:(此种解析在$PGDATA/walminer/temp目录下会记录系统表的变更情况)postgres=# select walminer_start('NULL','NULL',0,0,true);   walminer_start --------------------- walminer sucessful!

6.解析结果查看

postgres=# \xExpanded display is on.postgres=# select record_database,record_user,op_text,op_undo from walminer_contents;-[ RECORD 1 ]---+------------------------------------------------------------------------------------------------------ record_database | postgresrecord_user     | lichuanchengop_text         | INSERT INTO "public"."t2"("i", "j", "k") VALUES(1, 1, 'qqqqqq');op_undo         | DELETE FROM "public"."t2" WHERE "i"=1 AND "j"=1 AND "k"='qqqqqq' AND ctid = '(0,1)';-[ RECORD 2 ]---+------------------------------------------------------------------------------------------------------ record_database | postgresrecord_user     | lichuanchengop_text         | INSERT INTO "public"."t2"("i", "j", "k") VALUES(2, 2, 'wwwwww');op_undo         | DELETE FROM "public"."t2" WHERE "i"=2 AND "j"=2 AND "k"='wwwwww' AND ctid = '(0,2)';-[ RECORD 3 ]---+------------------------------------------------------------------------------------------------------ record_database | postgresrecord_user     | lichuanchengop_text         | INSERT INTO "public"."t2"("i", "j", "k") VALUES(3, 3, 'eeeee');op_undo         | DELETE FROM "public"."t2" WHERE "i"=3 AND "j"=3 AND "k"='eeeee' AND ctid = '(0,3)';-[ RECORD 4 ]---+------------------------------------------------------------------------------------------------------ record_database | postgresrecord_user     | lichuanchengop_text         | UPDATE "public"."t2" SET "k" = '1111qqqqq' WHERE "i"=1 AND "j"=1 AND "k"='qqqqqq';op_undo         | UPDATE "public"."t2" SET "k" = 'qqqqqq' WHERE "i"=1 AND "j"=1 AND "k"='1111qqqqq' AND ctid = '(0,4)';-[ RECORD 5 ]---+------------------------------------------------------------------------------------------------------ record_database | postgresrecord_user     | lichuanchengop_text         | DELETE FROM "public"."t2" WHERE "i"=2 AND "j"=2 AND "k"='wwwwww';op_undo         | INSERT INTO "public"."t2"("i", "j", "k") VALUES(2, 2, 'wwwwww');-[ RECORD 6 ]---+------------------------------------------------------------------------------------------------------ record_database | postgresrecord_user     | lichuanchengop_text         | INSERT INTO "public"."t2"("i", "j", "k") VALUES(4, 4, '44444rrrrrr');op_undo         | DELETE FROM "public"."t2" WHERE "i"=4 AND "j"=4 AND "k"='44444rrrrrr' AND ctid = '(0,5)';postgres=#

使用方法二

可以使用测试数据库解析生产库的wal日志。

(1)需要使用select walminer_build_dictionary(PATH);在生产库生成数据字典,然后将生成的数据字典和需要解析的wal日志放到测试库可以获取的路径。

(2)在测试库使用select walminer_load_dictionary(PATH);加载数据字典

(3)指定wal日志->执行解析->查看解析结果

具体使用方法在开源代码中的readme中查看。

使用限制

1.本版本只解析DML语句,不处理DDL语句
未来改动:DDL语句的解析已放入todolist,可能会逐步支持各种DDL语句

2.执行了删除表、truncate表、更改表的表空间、更改表字段的类型、vacuum full,这样的DDL语句后,发生DDL语句之前的此表相关的DML语句不会再被解析。
应对措施:建议在执行表结构变更之前,先保存一份数据字典,用来保证可以解析历史wal日志。
未来改动:现在已经考虑在walminer内增加保存数据字典的功能

3.解析结果依赖于数据字典。(举例:创建表t1,所有者为user1,但是中间将所有者改为user2。那解析结果中,所有t1相关操作所有者都将标示为user2)
应对措施:建议在执行表结构变更之前,先保存一份数据字典,用来保证可以解析历史wal日志。
未来改动:现在已经考虑在walminer内增加保存数据字典的功能

4.解析结果中undo字段的ctid属性是发生变更“当时”的值,如果因为vacuum等操作导致ctid发生变更,这个值将不准确。对于有可能存在重复行的数据,
我们需要通过这个值确定undo对应的tuple条数,不代表可以直接执行该undo语句。

5.执行了表字段drop的DDL语句后,发生DDL语句之前的这个字段相关的值都会被解析为encode('AD976BC56F',hex)的形式,另外自定义类型也会解析为这种形式

6.只能解析与数据字典时间线一致的wal文件

7.WalMiner是个人出品,暂时未进行全面测试。

8.[20190309新增]不建议使用walminer解析大宗copy语句(在同一个事务中插入大量数据行)产生的wal日志,

  这会导致解析过程中的效率低下和内存占用过高。

 

WalMiner的改进原理

    旧版本的工具xlogminer的解析来源是当前wal record所记录的"变更点"。它不会从FPW里的page里获取数据进行wal记录的解析。而新版本的walminer不仅可以解析当前wal记录的FPW,而且还对解析过程中出现的所有FPW进行记录和redo。因此walminer可以解析低级别的wal日志,可以不需要将表设置为DENTITY FULL模式。

    如下图所示,我们加载了从000000030000075100000050开始的很多wal日志。000000030000075100000050到00000003000007510000005A的wal日志可能会因为它依赖的wal日志不足而无法完全解析(表现为一些DML记录没有具体数据),在提示时间或LSN(2019-03-21 13:57:46+08 or 751/5a711300)之后的数据会完全解析。

 

联系我

发现bug或者有好的建议可以通过邮箱(lchch1990@sina.cn)联系我。



0