百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

经典故障:四个雷,3*2*2*3种随机方法的特殊恢复案例

ccwgpt 2024-11-26 01:08 45 浏览 0 评论

恢复专家前辈给我们精心准备了个故障,埋了四个雷,整个恢复过程感觉像是过山车,整理分享至此,希望对大家有帮助。

恢复文件

就给一个压缩的system,起库。

恢复过程

首先,获取system文件的字符集,数据库名,然后创建参数文件,重建控制文件,这里就不过多介绍,话不多说,先尝试启动数据库。

第一个雷

SQL> startup nomount pfile='/gauss/init.ora';
ORACLE instance started.

Total System Global Area  396668928 bytes
Fixed Size                  2253624 bytes
Variable Size             125832392 bytes
Database Buffers          264241152 bytes
Redo Buffers                4341760 bytes
SQL> @cf
Control file created.
ORA-00279: change 4936537 generated at 04/21/2020 00:03:57 needed for thread 1
ORA-00289: suggestion :
/guass/app/oracle/product/11.2.0/db_1/dbs/arch1_41_1033397865.dbf
ORA-00280: change 4936537 for thread 1 is in sequence #41


Specify log: {<RET>=suggested | filename | AUTO | CANCEL}
cancel
Media recovery cancelled.
SQL> alter database open resetlogs;
alter database open resetlogs
*
ERROR at line 1:
ORA-01092: ORACLE instance terminated. Disconnection forced
ORA-00704: bootstrap process failure
ORA-00704: bootstrap process failure
ORA-00604: error occurred at recursive SQL level 1
ORA-01578: ORACLE data block corrupted (file # 1, block # 338)--坏块
ORA-01110: data file 1: '/gauss/system.dbf'
Process ID: 32245
Session ID: 1 Serial number: 3

数据启动报file 1, block 338存在坏块的错误,我们来查一下这个块对应的对象。

TABLESPACE_NAME    SEGMENT_TYPE    OWNER         SEGMENT_NAME
------------------ --------------- ------------- --------------
SYSTEM             INDEX           SYS           I_OBJ1

这个对象是IOBJ1,IOBJ1是什么?

SQL> select * from bootstrap$ where SQL_TEXT like '%I_OBJ1%' order by  LINE#;

     LINE#       OBJ# SQL_TEXT
---------- ---------- --------------------------------------------------------------------------------
        36         36 CREATE UNIQUE INDEX I_OBJ1 ON OBJ$(OBJ#,OWNER#,TYPE#) PCTFREE 10 INITRANS 2 MAXT
                      RANS 255 STORAGE (  INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PC
                      TINCREASE 0 OBJNO 36 EXTENTS (FILE 1 BLOCK 336))

I_OBJ1是核心基表OBJ$的一个索引,当普通的索引出现坏块,我们可以通过重建去处理,但是OBJ#<59 的索引出现坏块,是不能够通过rebuild的方式处理。数据库open的情况下可以通过swap的方式处理,不过这里我们数据库都没打开。

首先我们先来介绍下数据库启动的过程:

1、在system 表空间的第一个数据文件的特定偏移位置,找到root dba变量

2、root dba变量的值就是指向 sys.bootstrap$表的物理位置的指针

3、sys.bootstrap$表中记录了数据库基础字典表的物理位置

4、基础字典表内记录了用户段段头的物理存储位置

下一步就是要通过某个段的segment header block从数据文件中直接读出表的数据。

在sys.bootstrap$表中记录的数据字典表的create语句,还有一部分是没有直接指定存储位置的,比如簇成员。

那么怎么去爬过第一个雷?这里有两个方案:

1)方法一

最简单的方法就是通过bbed cp同平台同版本的相同块去覆盖。

BBED> copy file 6 block 338 to file 1 block 338 

但是如果I_OBJ1存在大量的坏块情况下,cp的效率比较低。

2)方法二

删除IOBJ1,但是我们这里不是删除IND$里的IOBJ1索引,再次重启的时候又创建了,这里我们需要删除sys.bootstrap里的索引。

BBED> x /rnnc *kdbr[1]
rowdata[3681]                               @7322   
-------------
flag@7322: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@7323: 0x01
cols@7324:    3

col    0[2] @7325: 36
col    1[2] @7328: 36
col  2[208] @7331: CREATE UNIQUE INDEX I_OBJ1 ON OBJ$(OBJ#,OWNER#,TYPE#) P
CTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE (  INITIAL 64K NEXT 1024K MINEXTE
NTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 36 EXTENTS (FILE 1 BLOCK 33
6))

BBED> assign /x offset 7322 =0x3c --删除索引
ub1 rowdata[0]                              @7322     0x3c

BBED>  x /rnnc dba 1,523 *kdbr[1]
rowdata[3681]                               @7322   
-------------
flag@7322: 0x3c (KDRHFL, KDRHFF, KDRHFD, KDRHFH)
lock@7323: 0x01
cols@7324:    0  --已经删除

BBED> sum apply
Check value for File 1, Block 523:
current = 0x7e06, required = 0x7e06

3)方法三

[ora11@zdata bin]$ strings $ORACLE_HOME/bin/oracle |wc -l
1341571

11.2.0.4的执行文件包含1341571个函数,可以通过修改oracle执行文件指定,绕过索引I_OBJ1来处理。

第二个雷

通过上面两种方式排了第一个雷,我们顺利到达第二关。赶紧尝试打开,看看又会报什么错。

SQL> oradebug event 10046 trace name context forever,level 12;
Statement processed.
SQL> alter database open resetlogs;
alter database open resetlogs
*
ERROR at line 1:
ORA-01092: ORACLE instance terminated. Disconnection forced
ORA-00704: bootstrap process failure
ORA-00704: bootstrap process failure
ORA-00604: error occurred at recursive SQL level 1
ORA-01555: snapshot too old: rollback segment number 27 with name
"#34; too small
Process ID: 17397
Session ID: 1 Serial number: 5

ORA-01555快照过旧的报错,这个故障熟悉又陌生,尝试去推荐推进低位的scn,发现并没有效果,看来这个雷埋的还是很深的。

当oracle读取一个块,是否需要undo来完成一致性读,有很多种情况:

  1. itl有活动事务,回查undo段头发现事务确实是活动状态,那么肯定要undo来做一致性读;
  2. itl有活动事务,回查undo段头发现事务已经提交或者回滚,那么需要做块清除来确定commit scn,如果query scn<commit scn,则也需要undo来做一致性读块清除一直要找到大于query scn的commit scn,upper的也可以,才会做一致性读 否则直接01555了;
  3. itl事务已经提交 flag为C/U/CU,则扫描itl的commit scn,如果发现有query scn<commit scn,则也需要undo来做一致性读。
WAIT #140193663907536: nam='db file sequential read' ela= 788 file#=1 block#=241 blocks=1 obj#=18 tim=1587333670688800
=====================
PARSING IN CURSOR #140193661586512 len=142 dep=2 uid=0 oct=3 lid=0 tim=1587333670689091 hv=361892850 ad='775596a0' sqlid='7bd391hat42zk'  
select /*+ rule */ name,file#,block#,status$,user#,undosqn,xactsqn,scnbas,scnwrp,DECODE(inst#,0,NULL,inst#),ts#,spare1 from undo$ where us#=:1
END OF STMT
PARSE #140193661586512:c=242,e=243,p=0,cr=0,cu=0,mis=1,r=0,dep=2,og=3,plh=0,tim=1587333670689090
BINDS #140193661586512:

event 10046 trace 发现在访问块241的时候出现故障,这里我们就去看看这个块到底有什么问题。

BBED> p ktbbh
.........省略
         ub2 kxidusn                        @44       0x001b
         ub2 kxidslt                        @46       0x000b
         ub4 kxidsqn                        @48       0x00000186
      struct ktbituba, 8 bytes              @52      
         ub4 kubadba                        @52       0x00c00a97
         ub2 kubaseq                        @56       0x0219
         ub1 kubarec                        @58       0x26
      ub2 ktbitflg                          @60       0x2001 (KTBFUPB)
      union _ktbitun, 2 bytes               @62      
         sb2 _ktbitfsc                      @62       0
         ub2 _ktbitwrp                      @62       0x0000
      ub4 ktbitbas                          @64       0xffffffff --这里被改成0xffffffff

这里低位scn都改成最大值了,难怪怎么poke scn都没效果。。这个雷特么阴险,太坏了。

好了我们知道问题所在了,就是ktbitbas被人工改成0xffffffff,那么恢复方案也有两种。

1)方法一

修改scn,我们手动修改ktbitbas的值。

BBED> assign ktbbhitl[0].ktbitbas=0x004b531f
ub4 ktbitbas                                @64       0x004b531f

2)方法二

既然低位已经最大了,再怎么推也不会超过0xffffffff,那么我们就尝试poke推进高位scn。

SQL> oradebug setmypid
SQL> oradebug dumpvar sga kcsgscn_
kcslf kcsgscn_ [06001AE70, 06001AEA0) = 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 6001AB50 00000000
SQL> oradebug poke 0x06001AE74 4 0x50
BEFORE: [06001AE70, 06001AE78) = 00000000 00000000
AFTER:  [06001AE70, 06001AE78) = 004B60E0 00000000

第三个雷

SQL> alter database open resetlogs;
alter database open resetlogs
*
ERROR at line 1:
ORA-01092: ORACLE instance terminated. Disconnection forced
ORA-01173: data dictionary indicates missing data file from system tablespace
Process ID: 26639
Session ID: 1 Serial number: 3

看到这个报错,说明顺利进入第三关。

1)方法一

通过一键脚本设置*.corruptedrollback_segments隐患参数,屏蔽回滚段。

*._corrupted_rollback_segments='_SYSSMU28_79026890#39;,'_SYSSMU24_100127047#39;,'_SYSSMU28_79026890#39;,'_SYSSMU21_1449495591#39;,'_SYSSMU24_100127047#39;,'_SYSSMU21_1449495591#39;,'_SYSSMU30_493042799#39;,'_SYSSMU30_493042799#39;,'_SYSSMU23_1725104698#39;,'_SYSSMU23_1725104698#39;,'_SYSSMU22_3628056578#39;,'_SYSSMU22_3628056578#39;,'_SYSSMU25_3360715651#39;,'_SYSSMU22_3628056578#39;,'_SYSSMU25_3360715651#39;,'_SYSSMU22_36280565.......

2)方法二

SQL> select OWNER,SEGMENT_NAME,FILE_ID,BLOCK_ID from dba_extents where segment_name='UNDO#39;;

OWNER      SEGMENT_NAME       FILE_ID   BLOCK_ID
---------- --------------- ---------- ----------
SYS        UNDO$                    1        224

BBED> p ktetb
struct ktetb[0], 8 bytes                    @108     
   ub4 ktetbdba                             @108      0x004000e1--extent的首地址
   ub4 ktetbnbk                             @112      0x00000007--连续7个块

BBED> x /rnc *kdbr[0
rowdata[2337]                               @8146    
-------------
flag@8146: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8147: 0x00
cols@8148:   17

col    0[1] @8149: 0 
col    1[6] @8151: SYSTEM 
col    2[1] @8158: .
col    3[2] @8160: ..
......省略
BBED> x /rnc *kdbr[1
rowdata[2267]                               @8076    
-------------
flag@8076: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8077: 0x00
cols@8078:   17

col    0[2] @8079: 1 
col   1[19] @8082: _SYSSMU1_770609302$  --需要删除
col    2[2] @8102: ..
col    3[2] @8105: ..
col    4[3] @8108: ...
......省略

Oracle数据库服务进程在定位某行数据时,采用了数据字典+段头extent map的“集中—分散”存储模式,具体为:

  1. 在数据字典中存放数据段(对应表或分区)头的物理位置;
  2. 在数据段头存放段中所有extent(即连续的block集合)的物理位置 ktetb其实就是UNDO$的extent map,该结构体记录了segment中的extent的首地址 通过一键脚本找到dba 0x004000e1,也就是1,225,然后连续7个块,删除里面除了system的其他所有回滚段,这种方法实际操作太麻烦,大家有兴趣可以挑战下。

第四个雷

趟过前三个雷,恭喜顺利达到第四个雷。这个雷来者不善,毕竟是终极BOSS,处理完这个就要顺利通关了,胜利在望。

SQL> alter database open resetlogs;
alter database open resetlogs
*
ERROR at line 1:
ORA-03113: end-of-file on communication channel
Process ID: 26280
Session ID: 1 Serial number: 3

这个报错,数据库直接挂了,并没有出现什么错误,设置个10046事件去追踪下。

SQL> oradebug event 10046 trace name context forever,level 12;
SQL> alter database open resetlogs;
alter database open resetlogs

--后台alert的报错
SMON: enabling cache recovery
Exception [type: SIGSEGV, Address not mapped to object] [ADDR:0xD0C5CD7] [PC:0x97DF62E, kgebse()+776] [flags: 0x2, count: 2]
Fri Apr 24 06:42:13 2020
PMON (ospid: 19501): terminating the instance due to error 397

--file#=1 block#=140需要关注
WAIT #140452738872120: nam='db file sequential read' ela= 670 file#=1 block#=140 blocks=1 obj#=0 tim=1587681730297305
Exception [type: SIGSEGV, Address not mapped to object] [ADDR:0xD0C5CD7] [PC:0x97E0BBA, kgegpa()+40] [flags: 0x0, count: 1]
DDE previous invocation failed before phase II
DDE was called in a 'No Invocation Mode'
----- Start Diag Diagnostic Dump -----
Diag diagnostic dump is performed due to an error in the diagfw code during error handling.
DDE is switched to protected mode during the diagnostic dump to prevent recursive errors in the error hadnling code.

从SMON: enabling cache recovery这里其实也能看出来,数据库正在做一些回滚操作,file 1 block 140 对应的是system回滚段,访问到140块的时候数据库直接宕机。

TABLESPACE_NAME      SEGMENT_TYPE       OWNER      SEGMENT_NAME
-------------------- ------------------ ---------- ---------------
SYSTEM               ROLLBACK           SYS        SYSTEM

我来看窥探file 1 block 140 到底有什么问题。

BBED> p dba 1,140 ktubh
struct ktubh, 22 bytes                      @20      
   struct ktubhxid, 8 bytes                 @20      
      ub2 kxidusn                           @20       0x0000
      ub2 kxidslt                           @22       0x003b
      ub4 kxidsqn                           @24       0x0000002b
   ub2 ktubhseq                             @28       0x0025  --seq 是0x0025
   ub1 ktubhcnt                             @30       0x03
   ub1 ktubhirb                             @31       0x03
   ub1 ktubhicl                             @32       0x00
   ub1 ktubhflg                             @33       0x00


BBED> p dba 1,128 ktuxc
struct ktuxc, 104 bytes                     @4148    
   struct ktuxcscn, 8 bytes                 @4148    
      ub4 kscnbas                           @4148     0x004996f7
      ub2 kscnwrp                           @4152     0x0000
   .....省略
   struct ktuxcfbp[0], 12 bytes             @4192    
      struct ktufbuba, 8 bytes              @4192    
         ub4 kubadba                        @4192     0x0040008c
         ub2 kubaseq                        @4196     0x0030   --seq 是0x0030
         ub1 kubarec                        @4198     0x03
      sb2 ktufbext                          @4200     1
      sb2 ktufbspc                          @4202     7340

这里感觉是人为把128块的offset 4196由0x0025改成了0x0030

有三种方案恢复

1)方法一

把128块的offset 4196从0x0030改成了0x0025

BBED> assign dba 1,128 4196=0x0025

2)方法二

需要修改ktuxcnfb和ktuxcfbp[1] 即可。其中将ktuxcnfb修改为0,ktuxcfbp[1]中的uba修改为0,表示回滚的时候让oracle认为没有可以分配的undo块,相当于不回滚。

BBED> modify /x 00 offset 4168

BBED> modify /x 000000 offset 4192 

3)方法三

通过strace跟踪,得到如下的trace。

01:13:27 write(14, "[32]: ktuiup []", 15) = 15 <0.000012>  --ktuiup
01:13:27 write(15, "!gF\n", 4)          = 4 <0.000011>
01:13:27 lseek(14, 0, SEEK_CUR)         = 3425947 <0.000009>
01:13:27 write(14, "\n", 1)             = 1 <0.000011>
01:13:27 write(15, "!A1\n", 4)          = 4 <0.000012>
01:13:27 lseek(14, 0, SEEK_CUR)         = 3425948 <0.000010>
01:13:27 write(14, "[33]: ktuini []", 15) = 15 <0.000012>    ------注意这里ktuini函数
01:13:27 write(15, "!gF\n", 4)          = 4 <0.000011> 
01:13:27 lseek(14, 0, SEEK_CUR)         = 3425963 <0.000009>
01:13:27 write(14, "\n", 1)             = 1 <0.000012>
01:13:27 write(15, "!A1\n", 4)          = 4 <0.000012>
01:13:27 lseek(14, 0, SEEK_CUR)         = 3425964 <0.000010>
01:13:27 write(14, "[34]: adbdrv []", 15) = 15 <0.000011>
01:13:27 write(15, "!gF\n", 4)          = 4 <0.000012>
01:13:27 lseek(14, 0, SEEK_CUR)         = 3425979 <0.000009>
01:13:27 write(14, "\n", 1)             = 1 <0.000012>
01:13:27 write(15, "!A1\n", 4)          = 4 <0.000011>
01:13:27 lseek(14, 0, SEEK_CUR)         = 3425980 <0.000009>
01:13:27 write(14, "[35]: opiexe []", 15) = 15 <0.000012>
01:13:27 write(15, "!gF\n", 4)          = 4 <0.000011>
01:13:27 lseek(14, 0, SEEK_CUR)         = 3425995 <0.000009>
01:13:27 write(14, "\n", 1)             = 1 <0.000012>

注意这里ktuini函数,SEEK_CUR表示文件的相对当前位置,这里也能看出来数据库再做一些recovery的动作,调用ktuiup函数,开始恢复回滚段上的死事务。

既然数据库调用函数ktuini报错,那我们就通过再这个函数设置断点,然后导出数据。

--session 1
(gdb) break ktuini
Breakpoint 1 at 0xf21352
(gdb) c
Continuing.

--session 2
导出数据
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
exp \'/ as sysdba \' file=/home/ora11/meta.dmp ROWS=n  buffer=102400000

总结

通过这个3x2x2x3种随机方法来处理这个异常恢复案例分享,希望大家有所收获。另外说个题外话,今天是我在恩墨工作的4年第三天,感觉在恩墨工作还是挺有挑战,挺有意思的,尤其晋级的时候,独享与多位大咖交流,面对三小时灵魂式拷问,那种全方位沉浸式体验让人无法忘却。欢迎有志之士,各位踊跃加入恩墨大家庭,we are family!

原文阅读:https://www.modb.pro/db/24687?YYF

更多数据库相关干货,欢迎访问墨天轮官网:https://www.modb.pro/?YYF

相关推荐

一个基于.Net Core遵循Clean Architecture原则开源架构

今天给大家推荐一个遵循CleanArchitecture原则开源架构。项目简介这是基于Asp.netCore6开发的,遵循CleanArchitecture原则,可以高效、快速地构建基于Ra...

AI写代码翻车无数次,我发现只要提前做好这3步,bug立减80%

写十万行全是bug之后终于找到方法了开发"提示词管理助手"新版本那会儿,我差点被bug整崩溃。刚开始两周,全靠AI改代码架构,结果十万行程序漏洞百出。本来以为AI说没问题就稳了,结果...

OneCode低代码平台的事件驱动设计:架构解析与实践

引言:低代码平台的事件驱动范式在现代软件开发中,事件驱动架构(EDA)已成为构建灵活、松耦合系统的核心范式。OneCode低代码平台通过创新性的注解驱动设计,将事件驱动理念深度融入平台架构,实现了业务...

国内大厂AI插件评测:根据UI图生成Vue前端代码

在IDEA中安装大厂的AI插件,打开ruoyi增强项目:yudao-ui-admin-vue31.CodeBuddy插件登录腾讯的CodeBuddy后,大模型选择deepseek-v3,输入提示语:...

AI+低代码技术揭秘(二):核心架构

本文档介绍了为VTJ低代码平台提供支持的基本架构组件,包括Engine编排层、Provider服务系统、数据模型和代码生成管道。有关UI组件库和widget系统的信息,请参阅UI...

GitDiagram用AI把代码库变成可视化架构图

这是一个名为gitdiagram的开源工具,可将GitHub仓库实时转换为交互式架构图,帮助开发者快速理解代码结构。核心功能一键可视化:替换GitHubURL中的"hub...

30天自制操作系统:第六天:代码架构整理与中断处理

1.拆开bootpack.c文件。根据设计模式将对应的功能封装成独立的文件。2.初始化pic:pic(可编程中断控制器):在设计上,cpu单独只能处理一个中断。而pic是将8个中断信号集合成一个中断...

AI写代码越帮越忙?2025年研究揭露惊人真相

近年来,AI工具如雨后春笋般涌现,许多人开始幻想程序员的未来就是“对着AI说几句话”,就能轻松写出完美的代码。然而,2025年的一项最新研究却颠覆了这一期待,揭示了一个令人意外的结果。研究邀请了16位...

一键理解开源项目:两个自动生成GitHub代码架构图与说明书工具

一、GitDiagram可以一键生成github代码仓库的架构图如果想要可视化github开源项目:https://github.com/luler/reflex_ai_fast,也可以直接把域名替换...

5分钟掌握 c# 网络通讯架构及代码示例

以下是C#网络通讯架构的核心要点及代码示例,按协议类型分类整理:一、TCP协议(可靠连接)1.同步通信//服务器端usingSystem.Net.Sockets;usingTcpListene...

从复杂到优雅:用建造者和责任链重塑代码架构

引用设计模式是软件开发中的重要工具,它为解决常见问题提供了标准化的解决方案,提高了代码的可维护性和可扩展性,提升了开发效率,促进了团队协作,提高了软件质量,并帮助开发者更好地适应需求变化。通过学习和应...

低代码开发当道,我还需要学习LangChain这些框架吗?| IT杂谈

专注LLM深度应用,关注我不迷路前两天有位兄弟问了个问题:当然我很能理解这位朋友的担忧:期望效率最大化,时间用在刀刃上,“不要重新发明轮子”嘛。铺天盖地的AI信息轰炸与概念炒作,很容易让人浮躁与迷茫。...

框架设计并不是简单粗暴地写代码,而是要先弄清逻辑

3.框架设计3.框架设计本节我们要开发一个UI框架,底层以白鹭引擎为例。框架设计的第一步并不是直接撸代码,而是先想清楚设计思想,抽象。一个一个的UI窗口是独立的吗?不是的,...

大佬用 Avalonia 框架开发的 C# 代码 IDE

AvalonStudioAvalonStudio是一个开源的跨平台的开发编辑器(IDE),AvalonStudio的目标是成为一个功能齐全,并且可以让开发者快速使用的IDE,提高开发的生产力。A...

轻量级框架Lagent 仅需20行代码即可构建自己的智能代理

站长之家(ChinaZ.com)8月30日消息:Lagent是一个专注于基于LLM模型的代理开发的轻量级框架。它的设计旨在简化和提高这种模型下代理的开发效率。LLM模型是一种强大的工具,可以...

取消回复欢迎 发表评论: