PostgreSQL 使用pg_xlogdump找到误操作事务号

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介:
一般用户在发生误操作后,可能会非常模糊的记得一个大概操作的时间点,那么通过这个线索,我们怎么能定位到用户误操作的精准事务号呢?
从而使用PITR恢复到发生误操作前的数据库状态。
我们可以使用审计日志,找到精准的时间,假设你开了所有SQL的审计日志(log_statement = 'all')。
然后找到精准的XID,需要使用pg_xlogdump。
一个例子:
用户在某个时间点2015-09-21 10:10:00 +08发生了一笔误操作,删除了某个表tbl的一批数据。
首先我们可以在日志中,根据用户给的模糊时间,找到精准的时间。

将数据库恢复到这之前的一个时间(最好是给出时间点的上一个检查点之前的时间),并停止恢复。
假设检查点时5分钟会做一次的,那么我们可以选择5分钟前的一个时间点。
这么做是为了防止PITR到误操作后,那就白搞了。

$vi $PGDATA/recovery.conf 
recovery_target_inclusive = false
restore_command = 'cp /tmp/%f %p'
recovery_target_time = '2015-09-21 10:00:00 +08'   # 选择了一个10分钟前的时间
standby_mode = on
pause_at_recovery_target = true

数据库起来之后,去查找tbl对应的filenode,要用它来分析pg_xlog
digoal=# select oid from pg_class where relname='tbl';
   oid    
----------
 34874054
(1 row)
digoal=# select pg_relation_filenode(34874054);
 pg_relation_filenode 
----------------------
             37201015
(1 row)
digoal=# select pg_relation_filepath(34874054);
  pg_relation_filepath  
------------------------
 base/34873862/37201015
(1 row)

然后下载这个误操作前的基础备份,以及到误操作时产生的所有XLOG。
000000040000006500000095
000000040000006500000096
000000040000006500000097

使用pg_xlogdump分析XLOG。
$pg_xlogdump -b 000000040000006500000097 000000040000006500000097 | less
找到误操作的XID了,就是1485021,因为这笔事务日志包含了大量的tbl表的delete,而且上一个事务结束的时间点2015-09-21 10:13:22.038262和用户给的误操作时间点吻合。
rmgr: Heap        len (rec/tot):     50/    82, tx:    1485020, lsn: 65/9760DDF8, prev 65/9760DDC0, bkp: 0000, desc: hot_update: rel 1663/13003/16387; tid 0/36 xmax 1485020 ; new tid 0/37 xmax 0
rmgr: Transaction len (rec/tot):     12/    44, tx:    1485020, lsn: 65/9760DE50, prev 65/9760DDF8, bkp: 0000, desc: commit: 2015-09-21 10:13:22.038262 CST

rmgr: Heap        len (rec/tot):     26/  8218, tx:    1485021, lsn: 65/9760DE80, prev 65/9760DE50, bkp: 1000, desc: delete: rel 1663/34873862/37201015; tid 0/1 KEYS_UPDATED 
        backup bkp #0; rel 1663/34873862/37201015; fork: main; block: 0; hole: offset: 184, length: 56
rmgr: Heap        len (rec/tot):     26/    58, tx:    1485021, lsn: 65/9760FEB8, prev 65/9760DE80, bkp: 0000, desc: delete: rel 1663/34873862/37201015; tid 0/2 KEYS_UPDATED 
rmgr: Heap        len (rec/tot):     26/    58, tx:    1485021, lsn: 65/9760FEF8, prev 65/9760FEB8, bkp: 0000, desc: delete: rel 1663/34873862/37201015; tid 0/3 KEYS_UPDATED 
rmgr: Heap        len (rec/tot):     26/    58, tx:    1485021, lsn: 65/9760FF38, prev 65/9760FEF8, bkp: 0000, desc: delete: rel 1663/34873862/37201015; tid 0/4 KEYS_UPDATED 
rmgr: Heap        len (rec/tot):     26/    58, tx:    1485021, lsn: 65/9760FF78, prev 65/9760FF38, bkp: 0000, desc: delete: rel 1663/34873862/37201015; tid 0/5 KEYS_UPDATED 
.....

解释一下
desc: delete: rel 1663/34873862/37201015;
1663表示表空间的oid
34873862对应数据库的oid
37201015对应table的filenode
contrib/pg_xlogdump/pg_xlogdump.c
                        printf("\tbackup bkp #%u; rel %u/%u/%u; fork: %s; block: %u; hole: offset: %u, length: %u\n",
                                   bkpnum,
                                   bkpb.node.spcNode, bkpb.node.dbNode, bkpb.node.relNode,
                                   forkNames[bkpb.fork],
                                   bkpb.block, bkpb.hole_offset, bkpb.hole_length);
src/include/storage/relfilenode.h
typedef struct RelFileNode
{
        Oid                     spcNode;                /* tablespace */
        Oid                     dbNode;                 /* database */
        Oid                     relNode;                /* relation */
} RelFileNode;
src/include/access/xlog_internal.h
typedef struct BkpBlock
{
        RelFileNode node;                       /* relation containing block */
        ForkNumber      fork;                   /* fork within the relation */
        BlockNumber block;                      /* block number */
        uint16          hole_offset;    /* number of bytes before "hole" */
        uint16          hole_length;    /* number of bytes in "hole" */

        /* ACTUAL BLOCK DATA FOLLOWS AT END OF STRUCT */
} BkpBlock;

现在已经知道发生误操作前的最后一笔结束事务的XID,需要把recovery.conf改为xid恢复。
recovery_target_inclusive = true
restore_command = 'cp /tmp/%f %p'
recovery_target_xid = '1485020'
standby_mode = on
pause_at_recovery_target = true
重启数据库,现在已经恢复到真正的目标了。
可以导出tbl表,恢复被删除的数据。

[参考]
1. http://blog.163.com/digoal@126/blog/static/163877040201303082942271/
2. http://blog.163.com/digoal@126/blog/static/16387704020155199222755/
相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
SQL 缓存 运维
PostgreSQL 事务号回卷分析
## XID 定义 xid 是个啥东西?xid 就是 PostgreSQL 里面的事务号,每个事物都会分配一个 xid。PostgreSQL 数据中每个元组头部都会保存着 插入 或者 删除 这条元组的事务号,即 xid,然后内核通过这个 xid 进行元组的可见性判断。简单理解,比如有两个事务,xid1=200,xid2=201,那么 xid1 中只能看到 t_xmin 200 的元组。 ```c
|
8月前
|
存储 SQL Oracle
02-PostgreSQL 存储过程的进阶介绍(含游标、错误处理、自定义函数、事务)
02-PostgreSQL 存储过程的进阶介绍(含游标、错误处理、自定义函数、事务)
|
Oracle 关系型数据库 数据库
PostgreSQL技术大讲堂 - 第20讲:事务概述与隔离级别
PostgreSQL从小白到专家,技术大讲堂 - 第20讲:事务概述与隔离级别
271 2
|
关系型数据库 PostgreSQL
PostgreSQL事务提交日志与CLOG操作初步认识
PostgreSQL事务提交日志与CLOG操作初步认识
273 0
|
SQL 存储 Oracle
PostgreSQL 事务隔离级别的实现和多版本并发控制|学习笔记
快速学习 PostgreSQL 事务隔离级别的实现和多版本并发控制
PostgreSQL 事务隔离级别的实现和多版本并发控制|学习笔记
|
SQL 关系型数据库 数据库
PostgreSQL TRANSACTION(事务)
TRANSACTION(事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。 数据库事务通常包含了一个序列的对数据库的读/写操作。包含有以下两个目的: 为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。 当事务被提交给了数据库管理系统(DBMS),则 DBMS 需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库中,如果事务中有的操作没有成功完成,则事务中的所有操作都需要回滚,回到事务执行前的
210 0
|
存储 SQL 关系型数据库
【学习资料】第16期快速入门PostgreSQL应用开发与管理 - 6 事务和锁
大家好,这里是快速入门PostgreSQL应用开发与管理 - 6 事务和锁
|
SQL Oracle 关系型数据库
Oracle/Mysql迁移到Postgresql事务回滚行为差异(开发避坑系列)
Mysql或Oracle迁移到Postgresql系产品后,经常会发生事务回滚导致的问题,具体问题一般都是类似于: **为什么我没rollback,我的事务就自己回滚了?** 下面我举一个简单的例子,说明下PG和其他两款DB在事务回滚行为上的差异 ## Oracle事务内报错后的行为 (完整代码贴在文章最后) ```java Class.fo
1057 0
|
SQL 关系型数据库 PostgreSQL
AnalyticDB for PostgreSQL 6.0新特性解析 - OLTP 高并发事务能力优化
本文介绍 ADB PG6.0版本里,面向 OLTP 的高并发执行优化
4271 0