你以为和上次一样?不是,同是一台物理机上的几个虚拟机重启,但是每个环境不一样,这次主库归档没了
上次写了 rhino 库的那篇,缺 1 个 sequence,主库归档还在,修通 TNS 链路后 FAL 自动补,半小时搞定。这次是另一套环境,缺了 200 多个 sequence,主库归档也清理了,FAL 补不了。但最后还是没重做备库,RMAN 增量前滚 15 秒解决。
一、环境信息
- 主库:prod-islce-18533(db_unique_name=orcl_pri)
- 备库:prod-islce-18534(db_unique_name=orcl_sty)
- Oracle 19.3.0.0.0,CDB 架构(CDBROOT+PDBROOT+PDBSEED + ISLCE)
- 同样跑在 VMware 虚拟机上
故障起因和上次一样:物理机故障重启,虚拟机跟着重启,备库起不来。
二、排查:以为和上次一样,结果不一样
2.1 同样的开头
备库 OPEN 报的错一模一样:
ORA-10458: standby database requires recovery
ORA-01196: file 1 is inconsistent due to a failed media recovery session
ORA-01110: data file 1: '/data/app/oracle/oradata/ORCL/system01.dbf'
先按上次的流程走:查 MRP、查 GAP、查监听、查 TNS。
监听确实没起来,lsnrctl start 后服务注册正常。但这次主库 v$archive_dest 的 dest_id=2 直接就是 VALID------没报 ORA-12514。
为什么?因为备库 listener.ora 里有静态注册:
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = orcl)
(ORACLE_HOME = /data/app/oracle/product/19.3.0/db_1)
(SID_NAME = orcl)
)
)
监听一启动就有 orcl 服务(status UNKNOWN,静态注册的标志)。主库 tnsnames.ora 里 orcl_sty 别名的 SERVICE_NAME = orcl,正好匹配上了。所以主库能连备库,dest_id=2 = VALID。
但这个静态注册只是掩盖了 TNS 配置的隐患------和 rhino 库一样,SERVICE_NAME 应该写 orcl_sty(db_unique_name)而不是 orcl(db_name)。平时靠静态注册撑着,一旦 listener.ora 被改或者换了个监听配置方式,就暴露了。这个后面再说。
2.2 MRP 卡在 WAIT_FOR_GAP
链路通了,拉起 MRP:
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;
结果 MRP 卡住了:
MRP0 WAIT_FOR_GAP 1 4923 0
在等 4923。查 v$archive_gap------no rows。但 MRP 确实卡在 4923 不走。
这时候看了一眼备库的 v$archived_log:
SELECT sequence#, applied FROM v$archived_log WHERE sequence# BETWEEN 4920 AND 4930 AND thread#=1 ORDER BY sequence#;
4920~4930 全部 applied=YES。包括 4923。
再看 5155~5164:
5155 YES 5156 YES ... 5163 YES 5164 NO
5155 到 5163 全部 applied,5164 到了但没应用。
第一反应:这是个幽灵 GAP?控制文件里残留了旧的 GAP 记录,但数据实际是连续的?
2.3 不是幽灵,是真的缺
重启 MRP 试了两次,还是 WAIT_FOR_GAP 4923。不管它,直接 OPEN 试试:
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL; ALTER DATABASE OPEN;
OPEN 失败,同样报 ORA-10458。
看 alert 日志和 trc 文件,找到关键信息:
Start recovery at thread 1 ckpt scn 717730731 logseq 4923 block 2
Media Recovery Waiting for T-1.S-4923
Fetching gap from T-1.S-4923 to T-1.S-5022
Crash Recovery 从 datafile 的 checkpoint SCN 开始恢复,这个 SCN 是 717730731,对应 logseq 4923。也就是说 datafile 的文件头记录的恢复起点就是 4923,不是控制文件里的 GAP 记录在作怪。
v$archived_log 里 4923 applied=YES 只代表归档曾经注册过,datafile 的 checkpoint 没有推进到 5163。trc 里还有一行:
Highest datafile fuzzy SCN: 0x000000002cd64f56 = 752339286
In-flux buffer recovery target SCN: 0x000000002ac7b3ab = 717730731
datafile 的数据块实际已经更新到了 752339286(接近主库当前 SCN 752340840),但 checkpoint 信息还停在 717730731。Crash Recovery 要从 checkpoint SCN 开始,需要 4923 的 redo,等不到就卡住。
2.4 主库归档已经清理了
去主库查 4923:
SELECT sequence#, name, archived, deleted, status FROM v$archived_log WHERE sequence# = 4923 AND thread# = 1;
v$archived_log 里有两行:dest_id=2 那条 DEL=NO,dest_id=1 那条 DEL=YES。本地归档已经被 RMAN 清了。
去磁盘上确认:
ls /data/app/oracle/fast_recovery_area/ORCL_PRI/archivelog/ | sort | head # 最早的目录是 2026_09_18
4923 的完成时间是 7 月 29 日,主库 FRA 里最早只保留到 9 月 18 日的 5123。中间两个月的归档全清了。
三、尝试绕过 4923
3.1 RECOVER UNTIL CANCEL
RECOVER STANDBY DATABASE UNTIL CANCEL;
提示:
ORA-00279: change 717730731 generated at 07/28/2026 22:01:14 needed for thread 1
ORA-00289: suggestion : /data/app/oracle/fast_recovery_area/ORCL_STY/archivelog/2026_09_28/o1_mf_1_4923_%u_.arc
ORA-00280: change 717730731 for thread 1 is in sequence #4923
Specify log: {<RET>=suggested | filename | AUTO | CANCEL}
输入 CANCEL:
ORA-01547: warning: RECOVER succeeded but OPEN RESETLOGS would get error below
ORA-01196: file 1 is inconsistent due to a failed media recovery session
ORA-01112: media recovery not started
没恢复任何东西,datafile 还是 fuzzy。绕不过去。
3.2 备库 standby redo log 里有没有 4923
SELECT group#, thread#, sequence#, bytes, archived, status FROM v$standby_log ORDER BY group#;
最早的 standby redo log 是 sequence 5165,4923 早就被覆盖了。
走不通。4923 的归档主库备库都没有,只能走 RMAN 增量 SCN 前滚。
四、RMAN 增量前滚(第一次失败)
4.1 备库查 SCN
SELECT current_scn FROM v$database; -- 752242421
4.2 主库做增量备份
rman target / RMAN> BACKUP INCREMENTAL FROM SCN 752242421 DATABASE FORMAT '/tmp/inc_%U.bkp';
三个文件,加起来 113MB。挺小,传到备库恢复:
rman target / RMAN> SHUTDOWN IMMEDIATE; RMAN> STARTUP MOUNT; RMAN> CATALOG START WITH '/tmp/inc_'; RMAN> RECOVER DATABASE NOREDO;
一秒结束。OPEN------还是 ORA-10458。
4.3 为什么失败
查 RMAN 备份的元数据:
File LV Type Ckp SCN Ckp Time
1 Incr 752369696 2026:09:2815:45:21
备份的 Ckp SCN 是 752369696。但 datafile 的 checkpoint SCN 是 717730731。
BACKUP INCREMENTAL FROM SCN 752242421 做出来的备份只包含 752242421 之后的增量块。datafile 需要的是 717730731→752242421 之间的 redo,这些在备份里根本没有。NOREDO 恢复发现备份覆盖的范围对不上 datafile 的缺口,跳过了。
正确做法:FROM SCN 要用 datafile 的 checkpoint SCN(717730731),不是备库的 current_scn(752242421)。
五、RMAN 增量前滚(第二次成功)
5.1 主库重新做增量备份
rman target / RMAN> BACKUP INCREMENTAL FROM SCN 717730731 DATABASE FORMAT '/home/oracle/inc2_%U.bkp';
这次备份 15 秒完成,三个文件加起来约 1.9GB。比上次大很多,因为覆盖了从 7 月 29 日到 9 月 28 日两个月的增量数据。
5.2 传到备库恢复
scp /home/oracle/inc2_*.bkp oracle@10.60.185.34:/tmp/
备库上:
rman target / RMAN> SHUTDOWN IMMEDIATE; RMAN> STARTUP MOUNT; RMAN> CATALOG START WITH '/tmp/inc2_'; RMAN> RECOVER DATABASE NOREDO;
这次 RECOVER 真正执行了,不是一秒结束。
5.3 OPEN + 拉起 MRP
ALTER DATABASE OPEN; ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT FROM SESSION;
验证:
SELECT name, database_role, open_mode FROM v$database; -- ORCL PHYSICAL STANDBY READ ONLY WITH APPLY SELECT process, status, thread#, sequence#, delay_mins FROM v$managed_standby WHERE process LIKE 'MRP%'; -- MRP0 APPLYING_LOG 1 5165 0 SELECT * FROM v$archive_gap; -- no rows
ADG 完全恢复。
六、这个坑得记住:FROM SCN 怎么取值
这是这次最核心的教训。
很多人写 RMAN 增量前滚的时候,FROM SCN 用的是备库的 current_scn。这在某些场景下是对的------比如备库是全新搭建的、或者 datafile 的 checkpoint SCN 和 current_scn 差距不大的时候。
但在备库运行了很久、datafile checkpoint 远低于 current_scn的场景下,就会出问题。如下表所示。
| 取值方式 | FROM SCN | 覆盖范围 | 结果 |
|---|---|---|---|
| 备库 current_scn | 752242421 | 752242421→752369696 | datafile 缺口 717730731→752242421 没覆盖,失败 |
| datafile checkpoint SCN | 717730731 | 717730731→752369696 | 完整覆盖 datafile 缺口,成功 |
datafile 的 checkpoint SCN 从哪获取:
方法一:查 trc 文件,搜 Start recovery at thread 1 ckpt scn
Start recovery at thread 1 ckpt scn 717730731 logseq 4923 block 2
方法二:查 v$datafile_header(注意 19c 没有 last_change# 列):
SELECT file#, status, fuzzy, checkpoint_change# FROM v$datafile_header ORDER BY file#;
取最小的 checkpoint_change# 就是要恢复的起点。
七、和上次 rhino 库的对比
| 对比项 | rhino 库 (177/178) | orcl 库 (33/34) |
|---|---|---|
| Oracle 版本 | 11.2.0.4 | 19.3.0.0.0 |
| 缺失归档数量 | 1 个(seq 53800) | 200+ 个(seq 4923~5122) |
| 主库归档是否还在 | 在 | 不在(已清理) |
| 恢复路径 | 路径A:修通链路后 FAL 自动补 | 路径C:RMAN 增量 SCN 前滚 |
| TNS SERVICE_NAME 隐患 | 有,已修复 | 有,靠 listener.ora 静态注册掩盖,尚未修复 |
| listener.ora 静态注册 | 无 | 有(GLOBAL_DBNAME=orcl) |
| 增量备份大小 | 不适用 | 1.9GB |
| 恢复耗时 | 约 30 分钟 | 约 15 分钟(备份+传输+恢复) |
两套环境,两个坑,但根因是一样的:监听没加入开机自启。物理机重启后监听没跟着起来,redo 传不过去,备库重启时 Crash Recovery 缺 redo 就卡住了。
八、后续要做的事
8.1 修 TNS 配置
主库 tnsnames.ora 里 orcl_sty 别名的 SERVICE_NAME = orcl,改成 orcl_sty。现在靠 listener.ora 静态注册撑着,但静态注册的 status = UNKNOWN,有些场景下会有问题(比如 listener 重启后静态注册的服务需要手动 reload)。
8.2 监听加入开机自启
和 rhino 库一样的建议。检查 /etc/oratab 和 dbstart 脚本,确保监听随实例一起启动。
8.3 主库归档保留策略
这个库主库 FRA 50GB,归档只保留了 10 天(最早 9 月 18 日的 5123)。4923 是 7 月 29 日的,早就清了。
建议调整 RMAN 保留策略:
RMAN> CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 30 DAYS;
或者至少确保备库 GAP 检测能及时发现缺失------如果 GAP 发现得早,主库归档还没被清理,走路径A 就能解决,不用走路径C。
8.4 备库重启标准流程
和 rhino 库一样,不重复了。核心原则:先停 MRP 再 shutdown,先起监听再 OPEN。
九、总结
这已经是10多年没做处置过这类问题了。以后让AI来做吧。
datafile 的 checkpoint SCN 才是 Crash Recovery 的起点,FROM SCN 必须从这里开始。这个已经更新到 skill 文件里了。