• WalMiner


    WalMiner

    什么是WalMiner

    • WalMiner是从PostgreSQL的WAL(write ahead logs)日志的解析工具,旨在挖掘wal日志所有的有用信息,从而提供PG的数据恢复支持,需要将数据库日志级别配置需要大于minimal

    主要功能

    • 从waL日志中解析出SQL,包括DML和少量DDL

      解析出执行的SQL语句的工具,并能生成对应的undo SQL语句。与传统的logical decode插件相比,walminer不要求logical日志级别且解析方式较为灵活。

    • 数据页挽回

      当数据库被执行了TRUNCATE等不被wal记录的数据清除操作,或者发生磁盘页损坏,可以使用此功能从wal日志中搜索数据,以期尽量挽回数据。

    • 支持delete,drop table,truncate,vacuum full等操作后数据恢复

    版本支持

    • walminer3.0支持PostgreSQL 10及其以上版本。(此版本放弃对9.x的支持)

    安装

    安装包下载地址

    1. 配置pg的bin路径至环境变量

      export PATH=/h2/pg_install/bin:$PATH
      
    2. 进入walminer代码路径

    3. 执行编译安装

      USE_PGXS=1 MAJORVERSION=12 make
      #MAJORVERSION支持‘10’,‘11’,‘12’,‘13’
      USE_PGXS=1 MAJORVERSION=12 make install
      

    案例1(还原delete的数据)

    1、创建walminer的extension

    postgres=# create extension walminer;
    CREATE EXTENSION
    

    2、添加解析的wal日志

    --创建表
    postgres=# create table test(id int,primary key(id));
    CREATE TABLE
    --插入数据
    postgres=# insert into test values(1);
    INSERT 0 1
    --删除数据
    postgres=# delete from test;
    DELETE 1
    postgres=# select pg_walfile_name(pg_current_wal_lsn());
         pg_walfile_name      
    --------------------------
     000000010000000700000045
    (1 row)
    
    -- 注:参数可以为目录或者文件
    postgres=# select walminer_wal_add('/home/pg12/pg_wal');
      walminer_wal_add   
    ---------------------
     24 file add success
    (1 row)
    

    3、移除wal文件

    -- 移除wal文件:
    select walminer_wal_remove('/home/pg12/pg_wal');
    --官方文档说是可以移除目录或者文件,但是测试只能移除文件,不能是目录
    postgres=#select walminer_wal_remove('/home/pg12/pg_wal');
    错误:  Argument can be file only, an not be a directory
    

    4、列出wal日志文件

    --查看那些在分析的列表里
    postgres=# select walminer_wal_list();
                              walminer_wal_list                          
    ---------------------------------------------------------------------
     (/home/pg12/pg_wal/000000010000000700000043)
     (/home/pg12/pg_wal/000000010000000700000044)
     (/home/pg12/pg_wal/000000010000000700000045)
     、、、、
    --如果没有添加,这一步会报错
     postgres=# select walminer_wal_list();
    错误:  wal list has not been loaded or has been removed.
    

    5、解析wal日志,还原删除的数据

    --解析add的全部wal日志
    select walminer_all();
    或 select wal2sql();
    
    postgres=# select walminer_all();
    注意:  Switch wal to 000000010000000700000043 on time 2021-10-09 14:01:12.821196+08
    注意:  Switch wal to 000000010000000700000044 on time 2021-10-09 14:01:12.887438+08
    注意:  Switch wal to 000000010000000700000045 on time 2021-10-09 14:01:13.025056+08
        walminer_all     
    ---------------------
     pg_minerwal success
    (1 row)
    
    --解析完成后会把所有的结果记录到walminer_contents里面,可以使用walminer_by_time获取指定时间段
    
    postgres=# select walminer_by_time('2021-10-09 12:00:00', '2021-10-09 15:00:00');
    注意:  Add wal from current pg_wal directory, do not suggest use this way in produce
    注意:  Switch wal to 000000010000000700000045 on time 2021-10-09 14:02:07.654465+08
      walminer_by_time   
    ---------------------
     pg_minerwal success
    (1 row)
    --op_text记录了操作语句,undo_text是还原语句
    postgres=# select * from walminer_contents;
     sqlno |    xid    | topxid | sqlkind | minerd |           timestamp           |                op_text                |               undo_text               | complete | schema | relation
     | start_lsn  | commit_lsn 
    -------+-----------+--------+---------+--------+-------------------------------+---------------------------------------+---------------------------------------+----------+--------+---------
    -+------------+------------
         1 | 140477556 |      0 |       1 | t      | 2021-10-09 13:57:56.836588+08 | INSERT INTO public.test(id) VALUES(1) | DELETE FROM public.test WHERE id=1    | t        | public | test    
     | 7/453F22D0 | 7/453F2418
         1 | 140477557 |      0 |       3 | t      | 2021-10-09 13:58:21.183022+08 | DELETE FROM public.test WHERE id=1    | INSERT INTO public.test(id) VALUES(1) | t        | public | test    
     | 7/453F2500 | 7/453F25B8
    (2 rows)
    

    可以将undo_text执行,用于还原数据,由于是根据wal日志还原,所以vacuum 操作不影响,也可以直接还原

    该中方法相比于直接修改xid的又是在于在发生vacuum之后或者发生误操作后又向表中插入了新的有效数据后,修改xid就不太好使

    案例2(还原vacuum full的数据)

    1、vacumm full

    --在test表中插入三条数据
    postgres=# insert into test values(4),(5),(6);
    INSERT 0 3
    postgres=# select *from test;
     id 
    ----
      4
      5
      6
    (3 rows)
    
    postgres=# select pg_relation_filepath('test');
     pg_relation_filepath 
    ----------------------
     base/13593/31828459
    (1 row)
    
    postgres=# select current_timestamp;
           current_timestamp       
    -------------------------------
     2021-10-09 15:04:50.848161+08
    (1 row)
    
    postgres=# 
    postgres=# delete from test;
    DELETE 3
    --vacuum full
    postgres=# vacuum full test;
    VACUUM
    postgres=# select current_timestamp;
           current_timestamp       
    -------------------------------
     2021-10-09 15:05:19.661514+08
    (1 row)
    
    

    2、替身解析

    • 如果一个表被drop或者被truncate,以及vacuum full等操作,导致新产生的数据字典不包含旧的数据库中所包含的relfilenode,那么使用新的数据字典无法解析出旧的wal日志中包含的某些内容。在知道旧表的表结构的前提下,可以使用替身解析模式。替身解析只能适用于从WAL日志产生的数据库中直接执行解析,不适用从非wal产生的数据库中执行wal日志解析
    --test表已经被删除了,需要找到删除前test表的relfilenode
    --新建test的替身表
    postgres=# create table test_a(id int,primary key(id));
    CREATE TABLE
    
    --在执行解析之前,先执行如下语句,即可开启系统表解析功能
    select wal2sql_with_catalog();
    select wal2sql();
    --在walminer_contents里找到修改的记录找到对应的
    select * from walminer_contents;
    
    --获取到relfilenode:31828459
    postgres=# select walminer_table_avatar('test_a',31828459);
         walminer_table_avatar      
    --------------------------------
     MAP[test_a:31828432]->31828459
    (1 row)
    
    postgres=# select wal2sql();
    注意:  Add wal from current pg_wal directory, do not suggest use this way in produce
    注意:  Switch wal to 000000010000000700000043 on time 2021-10-09 15:06:04.286037+08
    注意:  Switch wal to 000000010000000700000044 on time 2021-10-09 15:06:04.351453+08
    注意:  Switch wal to 000000010000000700000045 on time 2021-10-09 15:06:04.475823+08
           wal2sql       
    ---------------------
     pg_minerwal success
    (1 row)
    
    postgres=# select * from walminer_contents;
     sqlno |    xid    | topxid | sqlkind | minerd |           timestamp           |                       op_text                       |                     undo_text                      | c
    omplete | schema | relation | start_lsn  | commit_lsn 
    -------+-----------+--------+---------+--------+-------------------------------+-----------------------------------------------------+----------------------------------------------------+--
    --------+--------+----------+------------+------------
         1 | 140311525 |      0 |       1 | t      | 2021-10-08 15:33:28.6956+08   | INSERT INTO public.test1(id ,info) VALUES(1 ,'234') | DELETE FROM public.test1 WHERE id=1 AND info='234' | t
            | public | test1    | 7/43CCC9E8 | 7/43CCF430
         1 | 140477839 |      0 |       1 | t      | 2021-10-09 15:04:44.485147+08 | INSERT INTO public.test_a(id) VALUES(4)             | DELETE FROM public.test_a WHERE id=4               | t
            | public | test_a   | 7/455C7CE0 | 7/455C7F28
         2 | 140477839 |      0 |       1 | t      | 2021-10-09 15:04:44.485147+08 | INSERT INTO public.test_a(id) VALUES(5)             | DELETE FROM public.test_a WHERE id=5               | t
            | public | test_a   | 7/455C7DF8 | 7/455C7F28
         3 | 140477839 |      0 |       1 | t      | 2021-10-09 15:04:44.485147+08 | INSERT INTO public.test_a(id) VALUES(6)             | DELETE FROM public.test_a WHERE id=6               | t
            | public | test_a   | 7/455C7E78 | 7/455C7F28
         1 | 140477844 |      0 |       3 | t      | 2021-10-09 15:05:12.29125+08  | DELETE FROM public.test_a WHERE id=4                | INSERT INTO public.test_a(id) VALUES(4)            | t
            | public | test_a   | 7/455D0978 | 7/455D0A68
         2 | 140477844 |      0 |       3 | t      | 2021-10-09 15:05:12.29125+08  | DELETE FROM public.test_a WHERE id=5                | INSERT INTO public.test_a(id) VALUES(5)            | t
            | public | test_a   | 7/455D09B8 | 7/455D0A68
         3 | 140477844 |      0 |       3 | t      | 2021-10-09 15:05:12.29125+08  | DELETE FROM public.test_a WHERE id=6                | INSERT INTO public.test_a(id) VALUES(6)            | t
            | public | test_a   | 7/455D09F8 | 7/455D0A68
    (7 rows)
    
    --停止walminer
    select walminer_stop();
    

    能获取到delete 并且执行过vacuum full的数据

    前面都是在源库执行的,也可以将wal日志和数据字典放到任意一个跟生产库配置相同的测试库解析

    从非wal产生的数据库中执行wal日志解析

    这种适用于不动生产环境,但是将wal日志在测试环境还原

    生产库生成数据字典

    --1、创建walminer扩展
    create extension walminer;
    --2、生成数据字典
    select walminer_build_dictionary('/opt/proc/store_dictionary');
    -- 注:参数可以为目录或者文件
    会生成一个:dictionary.d的文件
    

    测试数据库中加载数据字典

    --1、创建walminer扩展
    create extension walminer;
    --2、load数据字典
    select walminer_load_dictionary('/opt/test/store_dictionary');
    --3、add wal日志文件
    select walminer_wal_add('/opt/test/wal');
    --4、移除wal文件:
    select walminer_wal_remove('/opt/test/wal');
    --5、list wal日志文件
    -- 列出wal文件:注:参数可以为目录或者文件
    select walminer_wal_list();
    --6、 执行解析
    select wal2sql();
    --7、解析结果查看
    select * from walminer_contents;
    --8、结束walminer操作,该函数作用为释放内存,结束日志分析,该函数没有参数。
    select walminer_stop();
    

    注意:walminer_contents是walminer自动生成的unlogged表(之前是临时表,由于临时表在清理上有问题,引起工具使用不便,所以改为unlogged表),在一次解析开始会首先创建或truncate walminer_contents表。

    注意事项

    1. 本版本解析DML语句。DDL语句解析功能正在不断开发。

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

    3. 当前walminer无法处理数据字典不一致问题,walminer始终以给定的数据字典为准,

      对于无法处理的relfilenode,那么会丢弃这一条wal记录(会有一个notice在解析结果中没有体现)

    4. complete属性只有在wallevel大于minimal时有效

    5. xid解析模式不支持子事务

    6. 同时只能有一个walminer解析进程,否则会出现解析混乱

  • 相关阅读:
    安装配置ssh免密码登录
    大数据学习之Linux环境搭建(导航)
    Linux下搭建sqli-labs环境
    SpringMVC freemarker 中 Could not resolve view with name 'XXX.ftl' in servlet with name 'SpringMVC'
    配置FreeMarker时IDEA提示cannot resolve property 'templateLoaderPath'
    MySQL在指定字段后添加一个新字段
    META-INF/MANIFEST.MF file not found in unnamed.war
    Java获取音频播放时长
    JS实现阿拉伯数字转韩文
    微信公众号开发-素材管理-调用接口返回结果一览表
  • 原文地址:https://www.cnblogs.com/zhangfx01/p/15587592.html
Copyright © 2020-2023  润新知