数据库坏页!一次生产故障处理的详细记录

数据库
断电、硬件故障……这些都可能导致数据库坏页,进而引发数据库崩溃。本文记录了一次生产环境中 Db2 数据库坏页的故障处理,详细分享了如何恢复绝大部分数据,并恢复数据库的正常运行。

[[237041]]

断电、硬件故障……这些都可能导致数据库坏页,进而引发数据库崩溃。本文记录了一次生产环境中 Db2 数据库坏页的故障处理,详细分享了如何恢复绝大部分数据,并恢复数据库的正常运行。

前言

数据库最严重的故障莫过于数据库损坏。数据库坏页是数据库损坏的一种,如果数据库中有数据页出现损坏,在没有访问到坏页时,数据库可以正常提供服务,当使用到坏页所在的表,有可能导致数据库的崩溃。

导致数据库出现坏页的可能性有很多,比如突然的掉电、主机down机,或者存储、磁盘的故障等等。

当数据库出现坏页时,首先使用操作系统命令判断是否出现硬件故障,修复硬件故障后,可以尝试使用"db2 restart db dbname"命令让数据库执行崩溃恢复,这种方法有可能恢复数据库的正常。如果不适用与上述方法,那么***的办法就是从备份恢复数据库。

如果无法从备份恢复,那么在数据库可以连接的情况下,可以采用db2look导出表结构和export导出数据的方法来重建数据库。当然对于损坏的表,只能使用db2dart工具离线导出这些表的数据,处于坏页上的数据库极有可能丢失了。

如果数据库无法连接了,只能使用db2dart离线导出整个数据库的数据。导出数据之后,剩下的就是重建库并且导入数据了。

本文记录了一次生产环境中数据库页头的损坏的数据库坏页故障,经过一波三折的修复过程,最终恢复了绝大部分数据,恢复了数据库的正常运行。

环境介绍

操作系统版本 AIX 6100-07-04-1216

数据库版本 DB2 v9.7.0.7

该数据库比较大,大概2.2T,出现坏页的表数据量也比较大,大概30G。

一、问题发现

业务人员查询XXX数据库的某个报表查询,出现如下报错:

二、初步分析

查看该报错的解释:

  1. db2 "? sql1655c" 

查看数据库的nfy日志:

more db2npsh.nfy 

  1. 2017-08-07-14.14.44.308129 Instance:db2npsh Node:000  
  2. PID:12517626(db2agent (NPSH) 0) TID:25497 Appid:*LOCAL.db2npsh.170807055005  
  3. buffer pool services sqlbReadPage Probe:1199 Database:NPSH  
  4. ADM6006E DB2 encountered an error while reading page "114482656" from table   
  5. space "3" for object "1859" (located at offset "114482688" of container "/dev/rlvts_npsh_d8").  
  6.  
  7.  
  8. 2017-08-07-14.14.55.313501+480 E1900111A837 LEVEL: Critical  
  9. PID : 12517626 TID : 11548 PROC : db2sysc 0  
  10. INSTANCE: db2npsh NODE : 000  
  11. EDUID : 11548 EDUNAME: db2pfchr (NPSH) 0  
  12. FUNCTION: DB2 UDB, buffer pool services, sqlbLogReadAttemptFailure, probe:10  
  13. MESSAGE : ADM14001C An unexpected and critical error has occurred: "BadPage".   
  14. The instance may have been shutdown as a result. "Automatic" FODC   
  15. (First Occurrence Data Capture) has been invoked and diagnostic   
  16. information has been recorded in directory   
  17. "/db2/dump/npsh/FODC_BadPage_2017-08-07-10.09.10.302693_0000/".   
  18. Please look in this directory for detailed evidence about what   
  19. happened and contact IBM support if necessary to diagnose the   
  20. problem. 

同时,也发现dump目录下生成FODC_BadPage的文件。

三、进一步分析

尝试定位出现坏页的表:

根据db2npsh.nfy 日志中的信息table space "3" for object "1859",查询如下: 

  1. db2 "select tabname,status from syscat.datapartitions where tbspaceid =3 and tableid=1859" 

没有输出,怀疑是分区表的某个分区坏了,查询如下: 

  1. db2 "select tabname,DATAPARTITIONNAME from syscat.datapartitions where tbspaceid=3 and PARTITIONOBJECTID=1859" 

输出如下: 

  1. NXXXXTRFH PART201707 

可以判断是这个分区出现坏页。

查询该表的状态,正常:

 

  1. db2 "select tabname,status,tbspaceid,tableid from syscat.tables where tabname='NXXXXTRFH'" 

从该表查询数据,正常: 

  1. db2 "select * from dbnpsh. NXXXXTRFH fetch first 10 rows only" 

所以说数据库的坏页比较复杂,有时候坏页导致整个表故障,而本次,表面上查看起来,表数据一切正常。当跑报表访问到特定的页时才报出故障。

尝试通过load from cursor的方法把坏页的表分区的数据导出来,和报表查询语句报同样的错误:

尝试通过export导出数据: 

  1. db2 "export to /db2/archlog/npsh/NXXXXTRFH_PART201707.ixf of ixf select * from db2npsh.NXXXXTRFH_PART201707" 

导出hang住,两个小时后,导出400多万数据,出现同样的报错,而且数据量明显不对

收集所有的日志信息,发送给IBM800协助进行分析问题。 

  1. db2support . -d npsh -c -s 

经分析,IBM二线确认出现数据库坏页,建议使用db2dart导出表数据:

四、数据修复步骤

下面是数据找回的过程:

卸载表分区

由于该表大小达到30G,尝试将表分区卸载下来单独导出: 

  1. db2 alter table dbnpsh.NXXXXTRFH detach partition PART201707 into NXXXXTRFH_PART201707 

卸载成功

db2dart准备工作

执行db2dart之前,需要准备两点:

1、断开所有数据连接 

  1. db2 force applicaitons all 

2、扩容dump目录至能够放下整个分区的数据

db2dart导出数据

db2dart导出数据

开始执行db2dart导出数据: 

  1. db2dart npsh /DDEL  

然后输入:1859,3,0,999999

(四个参数的意义分别为:对象id,表空间id,起始页号,导出总页数)

IBM建议导出总页数设置为999999页

db2dart操作执行2小时,发现导出的页数已经达到999998,怀疑导出的页数超过设置的999999上限。看来IBM给的建议也不是完全准确。

将页数改为99999999,重新执行db2dart导出(需要先删除之前导出的dart目录): 

  1. db2dart npsh /DDEL  

然后输入:1859,3,0,99999999

历时三个小时后,导出成功,总共导出1100000多页。

导出文件名默认TS3T1859.DEL。

将dart出来的数据放入临时表

新建临时表NXXXXTRFH_PART20170702,注意指定的表空间要和NXXXXTRFH主表保持一致。

将dart出的数据导入到临时表: 

  1. db2 -v "LOAD FROM TS3T1859.DEL of del INSERT INTO DB2NPSH.NXXXXTRFH_PART20170702 NONRECOVERABLE" 

导入出现“字段类型不匹配”的报错,经过排查,是由于该表包含DBCLOB大字段,这种字段dart命令无法导出。查询原表,发现该字段为空,庆幸不会丢失大字段数据,但是由于数据文件和表结构不匹配,导入成了一个问题。

有两种方案解决这个问题:

***,编辑数据文件,定位到大字段那一列,插入一个逗号,即插入一列空列。

第二,新建不包含大字段列的表,导入数据后再添加大字段。

新建NXXXXTRFH_PART20170703不包含dbclob列,导入数据: 

  1. db2 -v "LOAD FROM TS3T1859.DEL of del INSERT INTO DB2NPSH.NXXXXTRFH_PART20170703 NONRECOVERABLE"  
  2. Number of rows read = 23771029  
  3. Number of rows skipped = 0  
  4. Number of rows loaded = 23770943  
  5. Number of rows rejected = 86  
  6. Number of rows deleted = 0  
  7. Number of rows committed = 23771029 

添加列 

  1. db2 "alter table db2npsh.NXXXXTRFH_PART20170703 add column URL DBCLOB(2048) LOGGED NOT COMPACT" 

执行成功。将临时表挂载到主表上

将临时表挂载到主表上: 

  1. db2 "alter table dbnpsh.NXXXXTRFH attach partition PART201707 starting ('20170701') ending ('20170731') from DB2NPSH.NXXXXTRFH_PART20170703" 

挂载失败: 

  1. SQL20408N Table "DB2NPSH.NXXXXTRFH_PART20170703" cannot be attached to   
  2. table "DBNPSH.NXXXXTRFH" because column "PAYEENM" of the source table and   
  3. its associated column "URL" of the target table do not match. Reason code = "8". SQLSTATE=428GE 

经分析,原因是临时表的列顺序和主表不一致。

解决方法:

将03临时表的数据通过指定列的方式insert到02临时表: 

  1. db2 -v "INSERT INTO DB2NPSH.NXXXXTRFH_PART20170702 SELECT MSGID,INSTGBKID,MSGCD,SEQNB,INSTGDRCTPTY,BIZTYP,BIZKIND,SYSCD,REGTIME,TRANCHNLTYP,CREDTTM,INSTDDRCTPTY,INSTDPTY,RMK ,PAYERNM,PAYERDPSTBKNM,DBTRDPSHDL,PAYERTELE,PAYERACCTNO,PAYERACCTYP,PWD ,PYMTAGRMT,AUTHPYMTBIZKIND,PTCID,URL,PAYEENM,CDTRDPSHDL,PAYEEDPSTBKID,PAYEEDPSTBKNM,PAYEEACCTNO,ACCTLTD,AGRINEFFCTVDT,AGREFFCTVDT,SNGLTXAMTLMT,ORIGMSGID,CSTMRNB,CDTRCSTMRID,DLTTLCNT,DAYAMTUPPERLMT,CURCD,MSLTTLCNT,MTHAMTUPPERLMT,MAGETYP,ACQFEE,CLRDATE,BIZPRCSCD,BIZRJCTCD,BIZRETSTS,RJCTRESN,BIZSTS,CTRLIND,BIZBIGTYP,ADDINFO1,ADDINFO2,ADDINFO3,ADDINFO4,ADDTBNM,SIGNATURE,TRADEFLAG,RPLIRACCT,RPLIRNM,RPLIRDPSNM,RPLIRDPSHDL,RPLIRACCTTP,QRISTACCT,QRISTNM,QRISTPTYNM,QRISTPTYHDL FROM DB2NPSH.NXXXXTRFH_PART20170703" 

将02临时表挂载到主表: 

  1. db2 "alter table dbnpsh.NXXXXTRFH attach partition PART201707 starting ('20170701') ending ('20170731') from DB2NPSH.NXXXXTRFH_PART20170702" 

挂载成功 

  1. SQL3601W The statement caused one or more tables to automatically be placed   
  2. in the Set Integrity Pending state. SQLSTATE=01586 

一致性检查

进行一致性检查: 

  1. db2 set integrity for dbnpsh.NXXXXTRFH immediate checked 

执行大概十分钟,成功。 

  1. DB20000I The SQL command completed successfully. 

数据量确认

查询201707分区的数据量: 

  1. db2 "select count(*) from DBNPSH.NXXXXTRFH where CLRDATE>='20170701' and CLRDATE<='20170731'" 

导入数据总条数:23770943

原数据条数: 

  1. db2 "select count(*) from DB2NPSH.NXXXXTRFH_PART201707" 

原数据总条数:23771388

损坏的数据条数:23771388-23770943=445条 

至此,数据恢复完成,找回23770943条数据,损坏445条。 

 

责任编辑:庞桂玉 来源: talkwithtrend
相关推荐

2022-06-01 06:17:42

微服务Kafka

2018-12-06 16:25:39

数据库服务器线程池

2021-01-12 07:57:36

MySQLBinlog故障处理

2019-07-25 08:30:58

数据库服务器故障

2019-11-18 13:42:55

MySQL数据库迁移

2019-11-22 08:05:01

数据库mysql分区

2019-08-19 01:34:38

数据库SQL数据库优化

2019-09-05 09:17:37

MySQL数据库线程

2019-12-12 10:38:10

mysql数据库nnodb

2019-09-08 17:52:10

数据库log file sy等待事件

2019-12-27 10:43:48

磁盘数据库死锁

2019-09-27 17:24:26

数据库优化sql

2019-12-16 07:18:42

数据库SQL代码

2019-01-21 11:17:13

CPU优化定位

2019-12-02 08:09:57

境数据库连接超时自动回收

2020-11-03 07:34:12

Kafka后端工程师

2021-03-01 06:14:50

环境高并发延迟

2020-12-15 11:18:43

系统磁盘lvm数据库

2020-09-25 07:57:42

生产事故系统

2017-10-27 09:01:26

Oracle存储管理
点赞
收藏

51CTO技术栈公众号