案例:一次非常艰难的drop多个pdb的恢复

在18年的一次恢复中,遇到了一个非常棘手的case,客户环境一套rac cdb中原本存在10个pdb在同一个ASM磁盘组中,误删除了其中6个pdb,并且使用了including datafiles子句。

针对此故障做了多种恢复方式的考虑:

1.AMDU

通常当ASM磁盘组无法mount的时候常常会想到使用AMDU去抽取数据文件,那么此次故障是否可以使用amdu呢?
当然不行了。。。amdu抽取asm文件的原理是通过asm文件号找到该文件对应的FILEDIR(asm 1号文件)的kfffde[0-59]找到file extent信息,如果extent个数大于60还需要借助kfffde[60+]指向的INDIRECT的kffixe来获取asm file每个extent所在的disk#,au#,从而完成抽取的。如果asm 1号文件FILEDIR损坏或者清空的情况下,amdu是无法完成文件抽取的。而drop datafile操作正好会清理掉FILEDIR的kfffde[0-59]和kfffde[60+]指向的INDIRECT的kffixe。另外amdu还依赖at,odu cp方式不依赖at,只依赖FILEDIR

2.ODU

那么当asm 1号文件FILEDIR损坏或者清空的情况,该如何去恢复呢?这时熊爷开发的odu工具就应该登场了。
odu在asm 1号文件FILEDIR损坏或者清空的情况下,通过配置asmdisk.txt,可以扫描该配置文件中所有的磁盘,会产生很多.odu文件,其中一个非常重要的文件是asm_fileext_meta.odu该文件以最小au也就是1M为1行记录,记录磁盘每个au所在的asmdisk#,au#,au_block#,第一个块的rdba、rfile#和block#,数据块大小等信息,相当于通过扫描磁盘建立数据文件的fileext,唯一不同的是FILEDIR记录的是asm文件号,这里记录的是相对文件号,随后即可通过extract命令根据rfile#来按照rdba的是顺序来抽取数据文件,具体操作详见http://www.oracleodu.com/cn/。但是此案例是删除了多个pdb,单纯的使用odu也无法实现(odu都不能恢复了,不敢想象),原因是pdb之间会存在相同rdba的情况,也就是说rfile#是一样的。在rdba相同的情况下此时odu根本不知道数据块是属于哪个pdb哪个数据文件的(除了数据文件头所在的第一个au,因为有且只有数据文件头中存在绝对文件号),从而就无法做出正确的抽取。

3.解析ACD和COD

想通过对asm metamata的日志记录,找出drop之前的FILEDIR里file extent的信息。

  • ACD是asm 3号文件,全称Active Change Directory,其作用是记录metadata block的变化,相当于asm的redo
  • COD是asm 4号文件,全称Continuing Operation Directory,其作用是记录metadata block中未完成的操作记录,ASM crash时可以恢复这些操作,相当于asm的undo

当时连续查看了好几个ACD块,确实记录有asm文件删除extent的记录,如下所示:

LGE为ACD redo log record,BCD为ACD block change descriptor。改动向量0和1组成的重做记录0,这点和redo基本一样。以上描述了asm file 323的FILEDIR kfffde60所指向的INDIRECT(disk#为28230 au#为7)的kffixe[3]被清空。即asm file号为323的extent号为7263的file extent map被清理。

备注:对于indirect,extent#=KFFFD_EXT.xtntcnt=KFFIX_EXT.xnum+60+indirect block#480=3+60+15480=7263,一个indirect block包含480个extent信息

以上描述了asm file 321的FILEDIR的kfffde[48] extent信息被清空。
即asm文件号为321的extent号为48的file extent map被清理。
备注:对于direct extent#=KFFFD_EXT.xtntcnt=KFFFD_EXT.xnum=48。

但是始终没有看到drop之前的file extent map记录。由于drop datafile已经完成,所以COD也没发现任何有用的信息。

正当思路一筹莫展之时,熊爷发现可以尝试通过ACD记录的AT变更记录找到asm文件的file extent map。这是一个非常关键的发现。

AT全称Allocation Table,每一块由ASM管理的磁盘都会至少包含一个AT,用来描述磁盘的AU分布情况,AT块的AT条目都代表了磁盘上的一个AU,一旦某个AU被分配/回收,AT表中此条目的内容会被更新,AT条目记录此AU属于的extent号和属于哪一个文件。
ACD记录AT块某一个AT条目的变更如下:

从ACD记录AT条目的变更记录得到了下列信息:

  • KFDAT_DEALLOC:回收AU
  • disk#=8
  • AT block#=58
  • asm file#=320
  • indirect block#=11
  • indirect kffixe=KFFIX_PEXT.xnum=313
  • curidx=2888

对于file ext#有根据direct,indirect存在两种算法,之前也提到过:

  • direct ext#=xnum
  • indirect ext#=60+xnum+indirect block#*480

所以通过此AT条目变更记录可以得到:

  • asmfile#=320
  • fileext#=60+313+11*480=5653
  • disk#=8
  • au#=(block#-2)*448+(curidx/8-5)=(58-2)*448+(2888/8-5)=25444

完美的还原了file 320 extent 5653的extmap。即asm文件320的5653号extent在磁盘8的25444号au上。

对于计算au#的公式这里解释一下,用于通过ACD记录的AT条目变更计算au#。计算au#,其实就是计算该AT条目在整个AT表的位置

  • 每个AT块可以管理448个AT条目
  • 每个磁盘的第一个stride,由于这个case磁盘并不是特别大所以只存在一个stride,磁盘头会记录AT的0号块位置(kfdhdb.altlocn=2),即blk=2为AT的0号块
  • curidx为AT块内偏移量(该AT条目在AT块内的偏移量)
  • AT块内每个AT条目占用8个offset
  • AT块头部(不算asm元数据块头)到AT块第一个AT条目的offset是40

所以au#=(block#-kfdhdb.altlocn)*448+(curidx-40)/8=(block#-2)448+(curidx/8-5)

由此就通过amdu抽取出asm 3号文件ACD,遍历ACD元数据块筛选出drop pdb的时间戳AT条目的所有变更记录,则可以完全的恢复被drop掉的asm file的extent map。当然这个需要写代码来实现,此次案例使用的代码也是熊爷写的(我用shell也实现了一个简陋版)。再重新构造asm_fileext_meta.odu文件,用唯一的asmfile#去替代可重复的rfile#,就能够使用odu完美的将删除的数据文件全部抽取出来了。

shell如下:

这个案例虽然有点老,2018年的案例,记录下来主要是因为该案例在oracle恢复中绝对算是世界级的难题。不得不佩服熊爷对于ASM的造诣之深,也让我当时从中吸收到了非常多的ASM的精髓。

此条目发表在Oracle, Oracle Recover分类目录,贴了, , , 标签。将固定链接加入收藏夹。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注