1 说明
在Oracle Data Guard中,GAP是指在备库无法接收到一个或多个来自主库的归档日志文件时发生的情况,会导致数据保护和实时数据复制的能力受到影响。
Oracle Data Guard架构日志同步有三个阶段:
- 日志发送;
- 日志接收;
- 日志应用。
GAP问题常发生在第一阶段日志发送环节,Primary在运行过程中,会不断产生Redo日志,这些Redo日志需要发送到Standy,这个发送动作由Primary的LGWR或者ARCH进程完成,选择使用什么进程进行日志发送,由log_archive_dest_2参数控制。
2 故障模拟
原理是阻断主库日志发送,然后删除新产生的归档,这样就生成GAP了。log_archive_dest_2参数定义了主库归档日志传输到备用数据库的方式和目标,当此参数不生效时,主库就无法将日志发送至备库。
步骤大致如下:
- 阻止日志发送;
- 主库切日志;
- 主库删除归档;
- 恢复日志发送。
2.0 当前状态
查看是否有gap:
SQL> select thread#, low_sequence#, high_sequence# from v$archive_gap;
当前不存在gap
查看日志应用状态:
set lines 200
col name for a70
alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';
select *
from (select name, sequence#, first_time, next_time, archived, applied
from v$archived_log
where name is not null
order by sequence# desc)
where rownum <= 20;
最新应用的归档序列号是349。
2.1 阻止日志发送
有多种方式可以阻止主库将日志发送到备库,比如将备库关闭,或设置log_archive_dest_state_2为defer。
这里采用第二中方式,不用麻烦关机。
一、设置log_archive_dest_state_2参数
在主库中将此参数设置为defer
,暂停日志的发送到standby。
SQL> alter system set log_archive_dest_state_2 = 'defer' scope = both;
System altered.
刷新日志:
查看LNS进程状态:
SQL> select process, status, SEQUENCE#, delay_mins, block#, blocks from v$managed_standby where process = 'LNS';
PROCESS STATUS SEQUENCE# DELAY_MINS BLOCK# BLOCKS
--------- ------------ ---------- ---------- ---------- ----------
LNS CLOSING 320 0 13560 1
LNS进程已经关闭,此时主库已经停止日志发送。
2.2 主库切日志
主库多切几次日志,生成新的归档。
SQL> alter system switch logfile;
System altered.
SQL> /
System altered.
SQL> /
System altered.
SQL> /
System altered.
查看日志发送情况:
SQL> select process, status, SEQUENCE#, delay_mins, block#, blocks from v$managed_standby order by SEQUENCE#;
可以看到最新的归档日志是355,但是日志发送停止在了351,还有3个日志未发送。
2.3 创建新数据
创建测试数据,用于恢复后验证。
SQL> create tablespace ts_gaptest datafile '+DATA';
Tablespace created.
SQL> select file_name from dba_data_files where tablespace_name = 'TS_GAPTEST';
FILE_NAME
----------------------------------------------------------------------
+DATA/orcl/datafile/ts_gaptest.278.1183716375
SQL> create user us_gaptest identified by us_gaptest default tablespace ts_gaptest;
User created.
SQL> grant dba to us_gaptest;
Grant succeeded.
SQL> create table us_gaptest.tab_gaptest as select * from dba_objects;
Table created.
SQL> select count(*) from us_gaptest.tab_gaptest;
COUNT(*)
----------
86358
SQL> alter system switch logfile;
System altered.
新增了数据文件+DATA/orcl/datafile/ts_gaptest.278.1183716375
,创建了表us_gaptest.tab_gaptest
。
2.4 主库删除归档
将新生成的那几个还未发送到standby的归档日志删除掉。首先,找到要删除的归档文件:
set lines 200
col name for a70
alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';
select *
from (select name, sequence#, first_time, next_time, archived, applied
from v$archived_log
where name is not null
order by sequence# desc)
where rownum <= 20;
备库:
主库:
可以看到,主库多了352至357号归档,将这几个文件删除。
[oracle@oracle11g ~]$ cd /u01/app/oracle/arch/
[oracle@oracle11g arch]$ rm -rf 1_352_1166397622.dbf 1_353_1166397622.dbf 1_354_1166397622.dbf 1_355_1166397622.dbf 1_356_1166397622.dbf 1_357_1166397622.dbf
RMAN检查已经发现这几个归档无效:
RMAN> crosscheck archivelog all;
2.5 恢复日志发送
在主库中将log_archive_dest_state_2参数还原,恢复日志发送。
SQL> alter system set log_archive_dest_state_2 = 'enable' scope = both;
切个日志:
SQL> alter system switch logfile;
System altered.
2.6 查看GAP
备库告警日志提示出现GAP:
备库查看GAP相关视图:
SQL> select thread#, low_sequence#, high_sequence# from v$archive_gap;
上述结果都提示了缺失352到357号归档日志文件。
3 处理过程
3.1 备库查看当前scn
SQL> select CURRENT_SCN FROM V$DATABASE;
CURRENT_SCN
-----------
2687514
此scn为恢复的起点。
3.2 查看新增数据文件
SQL> SELECT FILE#, NAME FROM V$DATAFILE WHERE CREATION_CHANGE# > 2687514;
FILE# NAME
---------- ----------------------------------------------------------------------
8 +DATA/orcl/datafile/ts_gaptest.278.1183716375
在scn为2687514后有一个新创建的数据文件8,需要进行恢复。
3.3 增量备份缺失数据和控制文件
在主库上,做一个基于scn为2687514的数据库增量备份:
RMAN> backup incremental from scn 2687514 database format '/home/oracle/orabak/scn2687514_%d_%T_%U_%s';
创建备库控制文件:
SQL> alter database create standby controlfile as '/home/oracle/orabak/controlfile.ctl';
Database altered.
3.4 将备份发送到备库
将刚刚创建的增备和控制文件发送到备库。
[oracle@oracle11g orabak]$ scp * oracle11gadg:/home/oracle/orabak/
oracle@oracle11gadg's password:
controlfile.ctl 100% 13MB 13.3MB/s 00:00
scn2687514_ORCL_20241030_mk38s8bj_1_1_724 100% 29MB 29.0MB/s 00:00
scn2687514_ORCL_20241030_ml38s8bq_1_1_725 100% 13MB 13.3MB/s 00:0
3.5 备库重启到nomount状态
关闭日志应用:
SQL> alter database recover managed standby database cancel;
闭库:
SQL> shutdown immediate;
启动至nomount状态:
SQL> startup nomount;
3.6 控制文件恢复
使用备份恢复控制文件。
RMAN> restore controlfile from '/home/oracle/orabak/controlfile.ctl';
恢复后启动之mount状态:
RMAN> alter database mount;
将增量备份集信息导入到当前控制文件:
RMAN> catalog start with '/home/oracle/orabak/';
3.7 恢复缺失的数据文件
查看文件8信息:
RMAN> report schema;
对比主库发现,主库中Size为100,而备库这里size为0。
执行恢复:
RMAN> restore datafile 8;
恢复后再次查看发现size已经为100:
数据文件8恢复完成。
3.8 增备恢复
RMAN> recover database noredo;
4 备库开启日志应用
打开备库:
SQL> alter database open read only;
开启日志应用:
SQL> alter database recover managed standby database using current logfile disconnect;
查看进程状态:
SQL> select process, status, SEQUENCE#, delay_mins, block#, blocks from v$managed_standby order by SEQUENCE#;
MRP0进程应用日志正常。
5 恢复后检查
备库查看gap:
SQL> select thread#, low_sequence#, high_sequence# from v$archive_gap;
no rows selected
gap已经消失。
查看归档是否一致:
SQL> select max(sequence#) from v$archived_log;
MAX(SEQUENCE#)
--------------
362
主备库都为362。
查看新建的表是否恢复:
SQL> select count(*) from us_gaptest.tab_gaptest;
COUNT(*)
----------
86358
表已经恢复。