天天看点

异版本pg_resetxlog后导致的问题处理

数据库的redo日志损坏时,或者控制文件损坏时,可能导致数据库无法启动。

如果存放pg_xlog或者pg_control文件的块设备遇到问题,可能引发这种情况。

遇到xlog或者控制文件损坏的时候,怎么处理呢?

数据库正常关闭时会写控制文件,redo是在数据库crash后需要用来恢复数据库的,如果数据库正常的关闭,实际上不需要从redo恢复。

postgresql 提供了一个工具,用来生成或改写控制文件,抹除指定的pg_xlog。

在数据库因为控制文件损坏,或者pg_xlog损坏,导致数据库不能正常启动时使用。

使用后,数据库起来之后,请务必逻辑导出后再导入一个新的集群。

导出时最好设置跳过错误的块(设置zero_damaged_pages=true),因为这种情况下十有八九块会损坏。

同时,由于pg_resetxlog会改写控制文件,如果你使用的pg_resetxlog和数据库的版本不一致,会导致生成的控制文件版本跟随pg_resetxlog的版本,导致后面一系列的问题。

查看控制文件的头文件,可以了解到控制文件的内容定义

控制文件的版本

控制文件的检查点信息

控制文件数据

通过pg_controldata命令则可以输出控制文件的内容,源码如下。

src/bin/pg_controldata/pg_controldata.c

例子

如果数据库集群时9.5,而你使用其他版本的pg_resetxlog修改其控制文件,结果会怎样呢?

例如使用9.2的pg_resetxlog设置9.5集群的pg_control文件。

如果你使用-f选项强制刷了这个pg_control文件,则版本号会变成9.2的,这个时候,你再使用9.5去启动数据库是会失败的。

那么使用9.2就能启动成功了吗?

当然也不行,因为数据库还有其他地方记录了版本号,那就是在$pgdata以及数据库的数据文件目录对应的pg_version文件。

这个文件是不会被pg_resetxlog纂改的,因为可以用来追溯真正的版本。

被不同版本的pg_resetxlog强制重建控制文件后,数据库将无法启动。

怎么办呢?

方法很简单,使用pg_version对应版本的pg_resetxlog重新生成一遍控制文件即可。

pg_resetxlog参数有几个,分别用来设置控制文件中对应的next xid , next oid, next multi-xact xid, ......

这些值有固定的算法,而且有安全范围,例如,不能设置比实际已创建事务更小的事务号,否则会造成对应事务产生的数据在事务号未消耗前数据不可见。

安全值的计算方法,可以参考pg_resetxlog的说明。

其实就是使用xlog中的文件名推算next xid。使用pg_multixact中的members , offsets推断oldest multixact id, next multi-xact。等等。

推断出正确的值后,就可以开始通过pg_resetxlog设置控制文件了。

除了pg_controldata以外,还可以查看文件pg_version得到。

<a href="http://blog.163.com/digoal@126/blog/static/163877040201171233710582/">http://blog.163.com/digoal@126/blog/static/163877040201171233710582/</a>

<a href="http://blog.163.com/digoal@126/blog/static/16387704020130109400557/">http://blog.163.com/digoal@126/blog/static/16387704020130109400557/</a>

使用与数据文件异版本的pg_resetxlog,将导致数据文件对应到 控制文件损坏。 无法启动数据库。

解决版本,使用与数据文件版本一致的pg_resetxlog,重新生成控制文件,需要加-f强制执行。

pg_resetxlog参数的安全值计算方法,见pg_resetxlog的参考手册。

祝大家玩得开心,欢迎随时来 阿里云促膝长谈业务需求 ,恭候光临。

阿里云的小伙伴们加油,努力 做好内核与服务,打造最贴地气的云数据库 。