概述
在Data Guard 环境中,当主库的某些日志没有成功传送到备库时,就会发生归档裂缝(Archive Gap)。目前,Oracle 提供了两种日志 GAP 的检测和处理机制:自动 GAP 处理(Automatic Gap Resolution)和 FAL 进程 GAP 处理(FAL Gap Resolution)。
- 自动 GAP 处理:主库上的 ARCn 进程会每分钟检查备库上的日志 GAP 情况并做相应处理。
- FAL 进程 GAP 处理:通过配置 FAL_SERVER 和 FAL_CLIENT 实现 GAP 检测的一种机制,备库主动发起"取"日志的过程。FAL 进程只在物理备库存在,该进程只有在需要的时候才会启动,工作完成后关闭。
大致可以分为以下几种情况来处理:
- 主库归档日志存在:可以通过配置 Fetch Archive Log (FAL) 参数,自动解决归档 GAP,或将归档日志拷贝到从库手工注册处理。
- 主库归档日志丢失 :需要人工干预来修复,11G具体步骤如下:
- 以备库的当前 SCN 号为起点,在主库上做一个增量备份。
- 在主库上创建一个备库的控制文件。
- 将增量备份拷贝到备库上。
- 使用新的控制文件将备库启动到 mount 状态。
- 将增量备份注册到 RMAN 的 catalog,取消备库的恢复应用,恢复增量备份。
- 开启备库的恢复进程。
处理 GAP 方法 1:手动拷贝归档到备库进行手工注册处理(归档未丢失)
(一)物理 DG 手动解决 GAP
在一些特殊情况下,如果 GAP 不能自动解决,那么就需要手工执行中断恢复。通过查询视图 V$ARCHIVE_GAP
可以确定断档的是哪些日志。
sql
-- 查询 GAP
SQL> SELECT * FROM V$ARCHIVE_GAP;
假设当前物理备库丢失日志文件从线程 1 的序号 10 到序号 12。接下来确定归档日志文件的路径(假设在主数据库上的本地归档目的地是 LOG_ARCHIVE_DEST_1
):
sql
-- 确定归档日志文件路径
SQL> SELECT NAME FROM V$ARCHIVED_LOG WHERE THREAD#=1 AND DEST_ID=1 AND SEQUENCE# BETWEEN 10 AND 12;
接下来,将这些日志文件拷贝到物理备库,然后在物理备库上使用 ALTER DATABASE REGISTER LOGFILE
语句来注册这些归档日志:
sql
-- 注册归档日志
SQL> ALTER DATABASE REGISTER LOGFILE '/arch/thread1_dest/arch_1_10.arc';
-- 或者
SQL> ALTER DATABASE REGISTER OR REPLACE LOGFILE '/arch/thread1_dest/arch_1_10.arc';
SQL> ALTER DATABASE REGISTER OR REPLACE PHYSICAL LOGFILE '/arch/thread1_dest/arch_1_11.arc';
在物理备库上注册这些日志文件之后,重新打开重做应用进程。如果断档的归档日志较多,可以使用以下 SQL 语句来生成要执行的 SQL 语句(也适用于逻辑 DG):
sql
SELECT 'ALTER DATABASE REGISTER OR REPLACE LOGICAL LOGFILE ''/arch/thread1_dest/arch_1_' || a || '.arc'';' LOGICAL_DG,
'ALTER DATABASE REGISTER OR REPLACE LOGFILE ''/arch/thread1_dest/arch_1_' || a || '.arc'';' PHYSICAL_DG
FROM (SELECT LEVEL A FROM DUAL CONNECT BY LEVEL <= 12)
WHERE A >= 10;
(二)逻辑 DG 手动解决 GAP
在逻辑备库上查询 DBA_LOGSTDBY_LOG
视图可以确定是否有归档中断。例如,下面的查询指出断档号为 16 至 18:
sql
-- 查询断档日志
SQL> COLUMN FILE_NAME FORMAT a60
SQL> SELECT THREAD#, SEQUENCE#, FILE_NAME
2 FROM DBA_LOGSTDBY_LOG L
3 WHERE NEXT_CHANGE# NOT IN (SELECT FIRST_CHANGE# FROM DBA_LOGSTDBY_LOG WHERE L.THREAD# = THREAD#)
4 ORDER BY THREAD#, SEQUENCE#;
接下来将丢失的日志文件拷贝到逻辑备库,并在逻辑备库上使用 ALTER DATABASE REGISTER LOGICAL LOGFILE
来注册这些日志文件。例如:
sql
-- 注册日志文件
SQL> ALTER DATABASE REGISTER LOGICAL LOGFILE '/arch/oracle/arch_1_16.arc';
在逻辑备库上注册这些日志文件之后,重启 SQL 应用。和物理 DG 一样,在逻辑备库上的 DBA_LOGSTDBY_LOG
视图只返回当前妨碍 SQL 应用继续的下一个中断。在解决指定的中断并重启 SQL 应用之后,再次在逻辑备库上查询 DBA_LOGSTDBY_LOG
视图,以确定下一个中断序号,重复这个过程直到没有更多的中断。
需要注意的是,如果需要的归档日志已经不在主库上了,但是有归档日志的 RMAN 备份,那么可以通过 RMAN 恢复把缺少的归档日志进行还原,如下所示:
sql
-- 设置归档日志目标位置
SET ARCHIVELOG DESTINATION TO '/arch';
-- 恢复归档日志
RESTORE ARCHIVELOG FROM LOGSEQ 17;
处理GAP方法2:主库基于SCN的增量备份来恢复DG(归档丢失)
如果断档的归档日志已经丢失,且RMAN又没有备份,那么在Oracle 10g之前没有办法修复了,只能重建DG,但是从Oracle 10g开始可以采用主库基于SCN的增量备份来恢复DG。
下面我们通过实验来进行展示11g环境中基于SCN的增量备份来恢复DG(常规办法):
示例
首先,模拟备库断电,主库切几个最新的归档,然后手工删掉,重新开启 DG 同步。
备库操作
sql
-- 停止备库的 redo apply
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;
-- 关闭备库
SHUTDOWN IMMEDIATE;
主库操作
sql
-- 切换多个日志
ALTER SYSTEM SWITCH LOGFILE; -- 多次执行
-- 删除最近几个归档日志
rm 1_30_1070147166.arc
rm 1_31_1070147166.arc
备库操作
sql
-- 启动备库
STARTUP
-- 使用当前日志文件恢复
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT FROM SESSION;
查看 GAP
sql
-- 查看 GAP
SQL> SELECT * FROM V$ARCHIVE_GAP;
-- 查看已应用的最大序列号
SQL> SELECT MAX(SEQUENCE#) FROM V$ARCHIVED_LOG WHERE APPLIED='YES';
-- 查看备库的状态
SQL> SELECT PROCESS, STATUS, THREAD#, SEQUENCE#, BLOCK#, BLOCKS FROM V$MANAGED_STANDBY;
假设当前 GAP 为 32-34,下面是具体的处理步骤:
-
以备库的当前 SCN 号为起点,在主库上做一个增量备份
-
备库:
sqlSELECT TO_CHAR(CURRENT_SCN) FROM V$DATABASE;
-
主库:
sqlrman target / RUN { ALLOCATE CHANNEL C1 TYPE DISK; ALLOCATE CHANNEL C2 TYPE DISK; ALLOCATE CHANNEL C3 TYPE DISK; ALLOCATE CHANNEL C4 TYPE DISK; BACKUP AS COMPRESSED BACKUPSET INCREMENTAL FROM SCN 16010653817 DATABASE FORMAT '/backup/incre_db_%d_%T_%s.bak'; BACKUP CURRENT CONTROLFILE FOR STANDBY FORMAT '/backup/standby.ctl'; RELEASE CHANNEL C1; RELEASE CHANNEL C2; RELEASE CHANNEL C3; RELEASE CHANNEL C4; }
-
-
在主库上创建一个备库的控制文件(前面备份集已经备份这里可以不用做)
sqlALTER DATABASE CREATE STANDBY CONTROLFILE AS '/backup/standby.ctl';
-
将增量备份拷贝到备库上
bashscp /backup/incre_* oracle@STANDBY:/backup/ scp /backup/standby.ctl oracle@STANDBY:/backup/
-
使用新的控制文件将备库启动到 mount 状态
sqlSHUTDOWN IMMEDIATE; STARTUP NOMOUNT; rman target / RESTORE CONTROLFILE FROM '/backup/standby.ctl'; ALTER DATABASE MOUNT;
-
增量备份注册到 RMAN 的 catalog,取消日志应用,恢复增量备份
sqlALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL; rman target / CATALOG START WITH '/backup/'; RECOVER DATABASE NOREDO;
-
备库开启日志同步进程
sqlsqlplus / as sysdba ALTER DATABASE OPEN READ ONLY; ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT FROM SESSION;
主库重新激活同步:
sqlsqlplus / as sysdba ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_2=defer; ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_2=enable;
查询是否存在 GAP,确认主备是否同步:
sqlsqlplus / as sysdba SELECT * FROM V$ARCHIVE_GAP; SELECT MAX(sequence#) FROM v$archived_log WHERE applied='YES';
至此,DG GAP 已被修复,以上方式为常规修复方式,各个版本都通用。
总结
到这里,12c版本之前的常规处理GAP 问题应该得到了解决。 后面我们会继续整理从12c开始 使用RECOVER ... FROM SERVICE
的方法以及从18c开始 使用RECOVER STANDBY DATABASE FROM SERVICE
的方法来处理 GAP 办法。