观察rollback产生的wal

Home / Blog / Download / About me

观察rollback产生的wal

Directory

pg回滚会不会写wal呢?

我们知道Oracle肯定会写的,来看看pg的吧

用的pg11

image-20181107114328330

一、commit 时的wal

1.1 t3表插入

image-20181107114250396

1.2 查看wal

image-20181107114451301

commit的话看到insert和commit了。

二、事务中,暂时不提交

2.1 begin插入

image-20181107114621113

2.2 观察wal

image-20181107114658368

不提交的时候,我们看到有running的事务。

三、rollback

3.1 紧接着rollback掉

image-20181107114734545

3.2 观察wal

image-20181107114803886

rollback之后,607这个事务abort了,但是也记录了wal的。

四、Oracle中rollback的redo

我们用logminer挖归档,直接看v$logmnr_contents视图

image-20181107115032655

image-20181107115715859

可以看到,上面部分delete的rollback字段是1,而且这部分是按rowid来删除的,可以肯定是回滚产生的delete记录了。最下面那部分是我执行delete,然后commit看到的redo记录,rollback部分是0,而且可以看到sql是正常的显示。

五、关于

其实这个是某天客户急急忙忙让logminer挖归档看看,说是有表数据被删了,听到这话,立马判定99.99%是应用的人在胡说八道,但为了拿出证据还是挖了一下。首先当然是用闪回查询,看看时间点附近的数据,可惜回滚段太小,已经被覆盖了。那么就挖吧,挖出来一看,根本就没插进去,当时的redo就是上面提到的这样,马上就回滚了,至于为什么回滚了,oracle层面很难看出什么了。但是开发的人说,他们的日志显示程序运行没有报错,而且都是插进去其他的session查到数据了的,觉得很扯,但是他们说用了连接池,又是短连接,难道每次都用的同一个session?我能想到的只有这样了。回滚可能是commit的时候网络出了点问题,或者其他的什么。建议让他们的程序打印更详细的日志,这个事情也就这样了。审计的话,其实也可以考虑一下各种审计类工具,对重点表进行细粒度的审计。

pg的话,像oracle这样去读归档也算是一种方法吧,找到当时的归档,然后log_dump去读,再去具体分析。当前存在的wal的名字和时间可以如下查询到:

postgres=# select * from pg_ls_waldir() order by modification asc;
           name           |   size   |      modification      
--------------------------+----------+------------------------
 000000010000000100000038 | 16777216 | 2018-11-22 16:31:53+08
 000000010000000100000037 | 16777216 | 2018-11-22 16:31:53+08
 00000001000000010000003B | 16777216 | 2018-11-22 16:31:54+08
 00000001000000010000003A | 16777216 | 2018-11-22 16:31:54+08
 000000010000000100000039 | 16777216 | 2018-11-22 16:31:54+08
 00000001000000010000003D | 16777216 | 2018-11-22 16:31:55+08
 00000001000000010000003C | 16777216 | 2018-11-22 16:31:55+08
 00000001000000010000003E | 16777216 | 2018-11-22 16:32:56+08
 00000001000000010000003F | 16777216 | 2018-11-22 16:33:05+08
 000000010000000100000040 | 16777216 | 2018-11-22 16:33:12+08
 000000010000000100000041 | 16777216 | 2018-11-22 16:33:19+08
 000000010000000100000042 | 16777216 | 2018-11-22 16:33:28+08
 000000010000000100000043 | 16777216 | 2018-11-22 16:33:36+08
 000000010000000100000044 | 16777216 | 2018-11-22 16:33:43+08
 000000010000000100000046 | 16777216 | 2018-11-22 16:33:52+08
 000000010000000100000045 | 16777216 | 2018-11-22 16:34:01+08
 000000010000000100000047 | 16777216 | 2018-11-22 16:34:16+08
 000000010000000100000036 | 16777216 | 2018-11-22 16:39:25+08
(18 rows)

postgres=# 

当前的归档可以如下查询:

postgres=# select * from pg_stat_archiver;
-[ RECORD 1 ]------+------------------------------
archived_count     | 3
last_archived_wal  | 00000001000000010000003A
last_archived_time | 2018-11-23 10:11:16.877234+08
failed_count       | 0
last_failed_wal    | 
last_failed_time   | 
stats_reset        | 2018-11-14 15:07:00.294068+08

postgres=# 

但是好像查不到历史的归档时间和wal名字对应信息?虽然可以ls -rtl 按时间来看,但这样也未必太麻烦了吧。

如果把log_min_duration_statement设置为0日志全记录,那日志文件就太大了,oracle的alert打开ddl日志都太多了,这个设0 ,ddl和dml全都记录了的,得做好清理策略。