postpresql查询空间占用情况 plsql查询所有表空间_表空间


马晓亮

中国PG分会认证专家

金风科技DBA,恩墨学院PostgreSQL金牌讲师,从事10余年的数据库相关工作,对通讯信息化、电网安全改造有丰富经验,为公司主要产品的国产化技术转型做了很多工作,未来主要基于开源构建公司相关业务支撑。

【摘要】

Global 默认是PG的系统表空间,存储的是共享系统字典表还有控制文件相关信息,此表空间下的文件是整个数据库系统访问控制的核心,一旦损坏数据库访问将会受限,尤其是控制文件受损将会导致系统的不可用,本文通过实际的现场global下文件受损导致数据库不可用案例,来讲述如何重构系统表空间以及控制文件来恢复数据库,从而通过逻辑备份快速导出数据,对以后postgresql 的global下的文件损坏而导致的数据库问题可以尝试使用此方法。

1. 问题的提出


接到客户现场反馈说业务应用连接数据库异常,提示global目录下对象存在无效的页,通过远程过去查看日志发现确实pg数据库的核心表空间下的对象出问题,详细的跟现场了解下情况,现场反馈说服务器硬盘坏了(服务器有raid 磁盘冗余保护),很难理解怎么会影响上层的业务应用,原来是客户要定期的从服务器上要拷贝生产业务报告(电网内有隔离),当时U盘不可用服务器厂商让客户重启服务器试试,谁知道起不来了,据说服务器厂商让客户又做了拔掉电源等系列匪夷所思的操作后系统能够正常登陆了,但是此时数据库就挂了,从整体的描述来看初步判断是服务器的raid卡出问题了导致系统登录问题以及识别不到U盘。

报错信息:

postpresql查询空间占用情况 plsql查询所有表空间_数据库_02

2. 解决思路


根据以上的信息联想到是否可以通过跳过无效的页来解决问题,仔细分析后发现此问题跟我们实际当中碰到的数据页损坏还是有区别的,因为数据页损坏我们跳过数据不访问便是,但是系统表空间下对象信息是一点也不能被忽视,也想过是否可以向oracle那样重建系统表空间呢,可是并找到pg相关重建系统表空间的方法,那怎么办呢? 比较惨的事情远远没有结束,检查备份发现近一年的备份都是无效备份,看来通过备份的方式是没戏了,当时感觉天是黑黑的!

无效备份文件:

postpresql查询空间占用情况 plsql查询所有表空间_数据库_03

好消息是数据库可以正常登陆:

postpresql查询空间占用情况 plsql查询所有表空间_postpresql查询空间占用情况_04

2.1. 如何解决问题

1、是否可以尝试别的方式恢复global:有个想法既然global下存储的是共享系统字典表,那么我们是不是就可以通过初始化一个库来重新生成新的global呢?感觉可行,但是这里面有个问题就是需要重建控制文件,ok有思路总比一头雾水强,说干就干.

1):通过物理拷贝的方式备份数据库副本来进行验证操作

2):我通过initdb 初始化一个实例

3):拷贝原备份副本里面的global文件到global_bak

4):拷贝新生成的global表空间目录到原备份副本中

5):尝试重建控制文件

6):尝试拉起数据库

[highgo@localhost highgo]$ ll

总用量 16

drwx------. 21 highgo highgo 4096 12月 25 09:25 9.4        --原数据库数据文件

drwx------. 20 highgo highgo 4096 12月 24 18:06 9.4_bak    --备份数据库副本

drwx------. 18 highgo highgo 4096 12月 24 17:27 9.5        --初始化数据库数据文件

[highgo@localhost 9.4_bak]$ ll

总用量 152

drwx------. 7 highgo highgo  4096 12月 24 17:45 base

drwx------. 2 highgo highgo  4096 12月 25 09:26 global        --初始化拷贝新global文件   

drwx------. 2 highgo highgo  4096 12月 24 18:33 global_bak    --原表空间备份副本

drwxr-x---. 2 highgo highgo  4096 12月 24 17:59 hgdb_log

drwx------. 2 highgo highgo  4096 12月 24 18:46 pg_clog

2.2. 计算控制文件信息

1、查看pg_xlog

postpresql查询空间占用情况 plsql查询所有表空间_数据库_05


按照早期9.2的版本pg_resetxlog –l 参数需要-l timelineid,fileid,seg三个参数现场是9.4的版本 只 需要一 个参数指定下一个事务日志号即可。

2、查看pg_clog   

-x 参数来自pg_clog

postpresql查询空间占用情况 plsql查询所有表空间_数据库_06

查看pg_multixact

-O参数来自members

postpresql查询空间占用情况 plsql查询所有表空间_数据库_07

-m参数来自offsets

postpresql查询空间占用情况 plsql查询所有表空间_控制文件_08

根据以上三个文件的内容我们计算的控制文件信息如下:

pg_resetxlog -l 00000001000000300000003D -x 0x002000000 -m 0x0003,0x0003 -O 0x0006 /opt/goldwind/pgdata/data/highgo/9.4_bak  -f

2.3. 异常情况

1、 准备好了一切按照我们的设想需要重启库来验证下是否可行。

postpresql查询空间占用情况 plsql查询所有表空间_表空间_09

数据库启动正常,心理安心了不少。

postpresql查询空间占用情况 plsql查询所有表空间_数据库_10

Ok 数据库可以正常访问,心理的一块石头落地了!

2、 高兴的有点早啊,因为发现数据库是正常了,但是我们业务数据库没有想象中一样出现,检查发现数据肯定是存在的。

postpresql查询空间占用情况 plsql查询所有表空间_表空间_11

2.4. 恢复

1、 果然问题并没有想的那么简单,我们忽略了重要的信息,那就是字典表里面有部分对象存储着初始化后新增对象的字典信息,既然这样那么开始尝试查看无效页的对象:

postpresql查询空间占用情况 plsql查询所有表空间_数据库_12

由于对象没有办法确认那么我们只能尝试着去规避这个对象了:

1) 清理此对象涉及的物理文件

2) 拷贝清理后的global所有对象到备份副本下

3) 尝试再次重建控制文件

4) 尝试启动数据库

5) 尝试连接数据库

6) 验证成功后尝试备份数据

postpresql查询空间占用情况 plsql查询所有表空间_数据库_13

postpresql查询空间占用情况 plsql查询所有表空间_表空间_14

postpresql查询空间占用情况 plsql查询所有表空间_数据库_15

3. 实践情况

此文档通过另一种方式恢复了数据库的global表空间,幸运的是没有碰到记录系统对象的表,恢复之后在想如果碰到是类似pg_database数据丢失我们是不是也能通过此方法来处理呢,答案应可以,为什么呢,因为只要知道系统内的数据库信息一样可以人为的补全。

4. 效果评价

此现场没有备份如果恢复不了面临的就是20G生产业务数据的丢失,随时不可估量,但是我们恢复了就说明此方法可行。

5. 推广建议


建议极端情况下可以尝试此方法,一般恢复后建议立即备份。

6. 参考资料