绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
PostgreSQL数据库故障修复技巧
2022-03-02 15:59:27



IT运维的恐惧主要来自于对运维对象的内在原理的认知不足,而数据库运维的底线在于数据的保全。

90年代末的时候,我们对Oracle数据库的理解并不深入,而且那时候企业在数据库备份等方面的投入也不足。正是那时候我次遇到了Oracle数据库服务器故障的情况。当时客户的操作系统彻底坏掉了,重装操作系统并重新安装了Oracle数据库软件,把磁盘阵列上的Oracle挂载起来后,数据库实例无法启动。在客户必须尽快恢复数据库服务的需求下,我一边翻阅手头仅有的几本技术资料,一边猜测其原理,一边尝试打开数据库。

我也打电话咨询了很多Oracle方面的专家,当时有不少人都认为这样情况,没有做数据库备份的情况下,这套数据库恢复无望。而我则觉得所有的数据库文件都没有损坏,数据库是一定能恢复的。经过近两天的努力,数据库终于恢复了。幸亏当时是周末,只影响了周六几个小时的业务,也算是万幸了。

从那以后,我才感受到理解Oracle数据库内部原理的重要性,开始研究起来,这也是我后来写作《DBA的思想天空》的一个起点。

随着对Oracle内部原理的理解的不断深入,我们对于Oracle的运维也越加自信。很多以前不敢关闭数据库进行系统维护的客户也都明白了数据库重启并不是一件高风险的事情。甚至90年代面试DBA的时候经常考的为什么不能shutdown abort关闭数据库也成了一道错题。这种运维能力的提升也让运维工作变得更科学起来了。而Oracle数据库无论出现何种问题,只要数据文件还在,我们总是能有办法解决其存在的问题。

刚刚开始使用PG数据库的时候,我也在考虑,如果PG数据库也出现了类似的问题,比如数据库处于不一致状态,操作系统故障,丢失某些文件等,我们是不是也能像运维Oracle数据库一样来解决这些问题呢?今天我就给大家分享一些这样的干货。

实际上各种数据库丢失文件、数据文件不一致,存在某些损坏,要解决这些问题,实际上涉及的都是REDO和UNDO的问题,解决REDO的不一致问题,可以让数据库在损失部分数据(甚至不损失数据)的情况下强行启动,从而减少部分损失。解决UNDO的问题,可以确保在丢失部分数据的一致性的情况下强行打开数据库,从而让数据损失减少到少。无论是Oracle、DB2还是今天我们讨论的PG,通过重置日志文件(REDO或者WAL)都可以强行打开一个不一致的数据库。

和Oracle一样,不管PG数据库出现什么样的问题,只要数据文件都还在,修复数据库的可能性是很大的。只要找到一个和本数据库版本一致的运行环境,后续一步步的修复数据库,打开数据库实例是大概率的。在修复数据库的时候,尽可能使用完全一致的数据库软件版本,从而避免一些不必要的麻烦。

PG数据库提供了一个重置WAL文件的工具pg_resetwal/pg_resetxlog(10以前版本),这个工具对于丢失一些PG的文件导致PG数据库无法启动可以进行强制修复。大家要注意的是,使用这个工具修复数据库是不得已而为之的做法,不过这个工具在一些非专业运维人员手里被当成了一个日常使用的工具,用来做各种各样的事情,包括误删数据恢复等。这实际上是十分危险的,一些常规性的恢复操作好还是用常规手段来进行,这种操作只是作为没办法情况下的操作手段。使用这种手段修复的数据库,也有可能因为修复使用的参数存在不准确而导致数据库能正常启动,但是数据库本身存在问题的情况。另外就是不同版本的工具的参数上可能会有略微的差异,使用前一定要认真阅读相关版本的文档。

如果仅仅是数据库存在一些不一致,或者丢失了部分WAL文件,那么我们只需要通过这个工具生成一个新的WAL文件就可以强制打开数据库了。我们来看一个例子,比如一数据库实例突然宕机了,而且WAL文件丢失了。因为这个WAL里可能包含了活跃的记录,因此数据库启动的时候会出现错误。看下面的例子:

然后Postmaster被异常终止。删除所有的WAL文件,删掉共享内存段。

然后重启数据库。

可以看到,因为WAL文件都丢失了此时数据库是无法启动。这种时候可以通过pg_resetwal工具去修复这个错误。

使用pg_resetwal $PGDATA就可以完成修复,如果数据库存在不一致情况,需要使用-f参数强制修复。可以看到修复后数据库启动了。不过刚才CHECKPOINT之后写入的一条数据丢失了。

上面的例子是简单的,我们再来看一个稍微复杂一些的例子。如果pg_control文件也丢失了,那么除了简单的reset wal之外,我们还需要首先恢复pg_control文件。pg_control文件位于$PGDATA/global目录下,是PG数据库中十分重要的记录各种重要数据库基本信息的文件,和Oracle的controlfile十分类似。如果这个文件损坏或者丢失,PG数据库就无法打开了。

今天我们以这个文件顺坏的场景,来学习一下如何使用这个工具来修复PG数据库。要想用pg_resetwal来修复数据库,重修生成丢失或者损坏的pg_control文件,需要确定几个参数。


1) -l, --next-wal-file=WALFILE,这个参数设置下一个新的WAL文件的小值,这个值可以从$PGDATA/pg_wal目录下去看后一个WAL 文件,这个文件的id+1就可以了。

这个文件+1,-l 000000010000099B00000035

2)-x, --next-transaction-id=XID,这个参数设置pg_control中的下一个XID的值,这个值可以从pg_xact目录下的文件中查询到。

后一个是0392,那么下一个XID就是0393,然后乘以 1048576 (0x100000),实际上后面直接加5个0就行了。注意,这个值是16进制的。-x 0x039300000

3)-m, --multixact-ids=MXID1,MXID2,这个参数包含两个部分,MXID1和MXID2,都可以从$PGDATA/pg_multixact/offsets目录下获得。MXID1的值,首先找到大值,+1,再乘以 65536 (0x10000,相当于后面加4个0)作为这个参数的前半部分。找到小的值,后面加4个0,作为MXID2的值。

这个例子中,-m 0x00570000, 0x00080000


4)-O, --multixact-offset=OFFSET,这个参数可以从$PGDATA/pg_multixact/members目录下获得。找到大值,+1,乘以 52352 (0xCC80),这个需要进行计算,没有简单的加0的方法。

-O 0x00BAED00


根据上面所述的参数的情况,这个例子要修复pg_control文件的命令为:

pg_resetwal -O 0x00BAED00 -m 0x00570000,0x00080000 -x 0x039300000 -l 000000010000099B00000037 $PGDATA


准备好命令后,首先要做几个准备动作。如果你的数据库是异常宕机的,那么$PGDATA/postmaster.pid文件可能还没删掉,需要手工删除。

然后到$PGDATA/global目录下,生成一个空的pg_control文件(touch pg_control)。否则执行命令会报错。

准备好之后,就可以执行命令了。

上面的命令执行过程中,所有的参数都已经被校验了,而且是可接受的。不过因为需要强制执行,所以需要加上-f参数。执行结束后,就可以尝试重启启动数据库了。


数据库能够成功启动了。要注意的是,命令执行成功,并不一定说明pg_control文件就正确修复了。如果你输入的参数有问题,那么数据库还是无法启动的。

如果你的数据库成功启动了,那么校验一下你所需要的书是否都是正确的。要说明的是这个命令的各种参数的确定要十分谨慎,一旦错误,数据库打开后,一些不一致带来的问题就比较麻烦了。在实际的生产环境中做这件事,你一定要首先完整备份书后再操作,否则你没有犯错误的机会。

实际上pg_resetwal工具还有很多十分重要的作用,今天时间有限,我们就不多说了,以后找时间再给大家分享。

以上文章来源于白鳝的洞穴 ,作者白鳝  


戳我,来吐槽~