☰
Data Guard同步停止复盘:UNNAMED文件卡死MRP的排查与修复
2026/10/2 9:10:08 网站建设 项目流程

一次dg同步停止的完整复盘:UNNAME文件是怎么把Data Guard卡死的

如果你管着一套 Oracle Data Guard,那"dg同步停止"这六个字,基本等于半夜手机被监控短信打爆的序曲。我这次遇到的还不是普通的 apply gap,而是备库控制文件里直接躺了一个叫UNNAMED00018的文件——V$DATAFILE 里查得到条目,磁盘上却压根没有实体文件。这篇就把整个过程摊开说:UNNAME 文件怎么冒出来的、怎么一步步定位到它、备库上修复命令怎么敲,以及事后如何防止同类问题反复出现。适合所有负责 Data Guard 日常运维、正准备接手 DG 环境的朋友。

1. UNNAME文件现身:一次dg同步停止事故的现场还原

1.1 告警先行的周一早上

那是个再普通不过的周一,早上八点出头,监控平台的消息就炸了:PROD -> DRC 数据同步停止,apply lag 持续增长。我第一反应是网络抖动或者主库归档传输断了,这种问题一般几分钟能缓过来。结果打开备库的V$ARCHIVED_LOG一看,序列号停在1_14236_1182093407,主库的 current log 已经跑到了1_14258_1182093407,中间差了快二十个归档没应用——这不是瞬间抖动,是恢复进程彻底卡死了。

登录备库查V$DATAGUARD_STATUS,不出意外,满屏都是ORA-01157开头的报错。顺手翻备库的 alert log,关键信息就挂在日志尾部:

Media Recovery Log /archivelog/1_14236_1182093407.dbf ORA-01157: cannot identify/lock data file 18 - see DBWR trace file ORA-01110: data file 18: 'UNNAMED00018'

看到UNNAMED00018的时候,我心里其实咯噔了一下——这玩意出现了,意味着备库的恢复进程不光是被某条归档卡住,而是整个MRP0进程都会因为打不开数据文件直接退出。只要它退出,后续所有从主库传来的归档全部无法应用,gap 自然会越堆越大,看起来就像"dg同步停止"。

1.2 UNNAMED和普通数据文件有什么本质区别

说句大实话,很多 DBA 对 UNNAMED 文件只有一个模糊概念,觉得"哦,就是备库上缺文件,建一个就行了"。其实它跟普通数据文件有个关键区别:UNNAMED 文件的条目存在于控制文件里,但磁盘上没有对应的真实文件。你可以理解成控制文件里有个"空壳指针",指向一个不存在的地址,DBWR 进程每次尝试打开它都会失败。

正因为如此,v$datafile里能看到它的file#和状态,但dba_data_files查不到对应行,OS 层ls也找不到文件。备库恢复路径上也凑不齐"完整数据集",MRP 就只能在那边干瞪眼。再往深一层说,UNNAMED 通常不是一个随机故障,它的出现几乎都指向同一个根因:主库新增了数据文件,但备库侧因为路径映射、参数配置或者磁盘布局的问题,没能生成对应的物理文件。

我当时第一反应是"先查一下主库近期有没有加过表空间或数据文件",结果确实如此:上周五业务侧在 PROD 上给TS_APP表空间加了一个 8GB 的新数据文件/data/prod/ts_app01.dbf。归档传过来后,备库想按同样路径去/data/standby/创建文件,但偏偏这个新路径不在DB_FILE_NAME_CONVERT设定的映射规则里——问题就是这么一环扣一环地出来的。

2. 排查链路拆解:从告警日志到V$DATAFILE的完整取证过程

2.1 第一条命令永远不是修,而是定位

处理 DG 故障有个铁律:先确认问题边界,再动手修复。很多新手看到ORA-01157就直接去建文件,结果把状态搞得更乱。我当时的排查顺序是这样的:

首先在备库执行:

SELECT thread#, MAX(sequence#) AS last_applied_seq FROM v$archived_log WHERE applied = 'YES' GROUP BY thread#;

这一步是为了确认当前 apply 停在哪一个归档上。如果连last_applied_seq都查不出来,说明 MRP 进程状态异常,需要先看V$RECOVERY_PROGRESS或者直接查V$DATAGUARD_STATS。我这边的结果是1_14234,比前面看到的传输位置又靠后了两位,说明恢复进程在建立一致性检查点时也遇到了阻碍。

然后看 MRP 是否还活着:

SELECT process, status, thread#, sequence#, block# FROM v$managed_standby;

正常情况下这里应该能看到MRP0进程状态为APPLYING_LOG,而我这边MRP0的状态是WAIT_FOR_LOG——不是正常的等待新日志,而是"等待条件满足但永远等不到",因为打不开文件,数据库处于一种半卡死状态。

2.2 V$DATAFILE里的UNNAMED文件长什么样

接着重点来了,在备库上直接查 V$DATAFILE:

SELECT file#, name, status, bytes, con_id FROM v$datafile WHERE name LIKE 'UNNAMED%';

输出结果干净利落,就一行:

FILE#NAMESTATUSBYTES
18UNNAMED00018OFFLINE8589934592

注意这个BYTES是 8GB,跟主库新增的数据文件大小完全吻合。看到这两个信息,基本可以断定:主库新加了 8GB 数据文件,备库这边没建出对应物理文件,于是 Oracle 在控制文件里给它临时编了个UNNAMED00018的名字。此时这个文件处于 OFFLINE 状态,MRP 应用归档时一旦碰到需要访问文件 18 的 redo 记录,就会立刻报错退出。

这里我多解释一句:很多人看到 OFFLINE 以为"既然离线了,跳过它不就行了?"——在 DG 场景下不行。数据文件 offline 不等于你可以忽略它,redo 记录里包含对这个文件的 block change,恢复进程必须打开文件才能应用,打不开整个 apply 就停下来,没有任何讨价还价的余地。

2.3 对照主库找出缺失文件对应的真实路径

定位到 FILE# = 18 之后,下一步必须回到主库,查出这个文件在端上的真实路径和归属表空间:

SELECT d.file_id, d.tablespace_name, d.file_name, d.bytes/1024/1024 AS size_mb FROM dba_data_files d WHERE d.file_id = 18;

我这边的结果是:

FILE_ID TABLESPACE_NAME FILE_NAME SIZE_MB 18 TS_APP /data/prod/ts_app01.dbf 8192

到这里,整个故障链路已经清晰得不能再清晰了:

  1. 主库新增数据文件:/data/prod/ts_app01.dbf,属于TS_APP表空间
  2. 该文件对应的 redo 记录传到备库
  3. 备库尝试应用时,想把文件创建到/data/standby/ts_app01.dbf
  4. 但DB_FILE_NAME_CONVERT的映射规则只覆盖了/data/prod->/data/standby这个旧目录,而新文件虽然在/data/prod下……等等,其实问题并不是映射规则没覆盖,而是备库的 standby_file_management 参数当时是 MANUAL,导致 Oracle 宁可生成 UNNAMED 占位,也不愿意自动帮你把文件建出来

这个细节我们放到第 4 节再展开,先说排查的最后一步——确认有没有归档断层:

SELECT * FROM v$archive_gap;

如果这里能查出一行THREAD# 1, SEQUENCE# 14235..14258,说明主库对应的归档日志还在,没有丢失,后续修复完文件之后可以无缝接上。如果查出来是 NULL,反而说明没有 gap,所有日志都还在备库磁盘上,修复会更快。

3. 修复全流程:备库执行CREATE DATAFILE的正确姿势

3.1 动手前的最后一件事:确认备库目录存在

修复命令本身不长,但有个前置条件容易被忽略:备库上目标目录必须先存在。UNNAMED 文件之所以能生成,往往是 Oracle 尝试自动创建文件但发现目录不存在,或者参数不允许自动建文件。所以你执行ALTER DATABASE CREATE DATAFILE之前,得先在备库服务器上把目录建好:

mkdir -p /data/standby chown oracle:oinstall /data/standby

目录权限也得检查一下,DBA 在备库服务器上的 OS 用户通常就是 oracle,但保不齐有环境用 grid 用户管理 ASM,那就得确认 ASM 磁盘组路径是否可写。路径没准备好,命令敲下去会直接报ORA-01119(创建数据文件出错),白忙活一通。

3.2 核心修复命令:ALTER DATABASE CREATE DATAFILE

一切就绪后,在备库执行:

ALTER DATABASE CREATE DATAFILE '/u01/app/oracle/oradata/DRC/UNNAMED00018' AS '/data/standby/ts_app01.dbf';

注意第一个参数是 V$DATAFILE 里查到的名字,必须写全路径,包括那个UNNAMED00018的文件名;第二个参数是你希望创建的真实文件路径。这里我建议第二个路径跟主库的路径规则保持一致,比如主库是/data/prod/ts_app01.dbf,备库就老老实实建在/data/standby/ts_app01.dbf,不要图省事丢到默认目录去。否则以后数据文件一堆,你光靠名字根本对应不上主备关系。

执行完这条命令后,Oracle 会做一件背后的事:它会从主库自动 fetch 这个数据文件的完整内容,把它创建出来(前提是 DG 主备链路正常、归档传输通道没断)。这一步在 11g 以后基本不需要手动干预,命令执行完,你会看到类似这样的输出:

Statement processed.

看似轻描淡写,但实际过程可能持续几分钟,取决于主库上文件大小和网络带宽。8GB 的文件,千兆内网大概一分钟左右,跨公网就得看运气了。那怎么确认文件真的创建好了呢?两个验证点:

SELECT file#, name, status, online_status FROM v$datafile WHERE file# = 18;

如果状态从OFFLINE变成了ONLINE,且NAME一列变成了/data/standby/ts_app01.dbf,说明数据文件已经可用。再看 OS 层:

ls -lh /data/standby/ts_app01.dbf

文件大小应该接近 8GB,不一定严格等于主库的字节数,因为建文件时可能分配了不同的初始 extent,但整体量级不会差。

3.3 重启恢复进程并验证同步追平

数据文件就位之后,MRP 还需要重新启动才能继续干活。备库上执行:

ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;

这一条命令会把 MRP 进程拉起来,继续从上次中断的归档位置开始应用。启动之后别急着走,等两三分钟再查一次V$DATAGUARD_STATS:

SELECT name, value, unit FROM v$dataguard_stats WHERE name IN ('apply lag', 'transport lag');

两个指标都应该从分钟级/小时级往 0 收敛。我记得当时第一次查还是在00:03:21,五分钟后再查就是00:00:00。这时候再对比主备库的序列号:

-- 主库 SELECT thread#, MAX(sequence#) FROM v$archived_log GROUP BY thread#; -- 备库 SELECT thread#, MAX(sequence#) FROM v$archived_log WHERE applied='YES' GROUP BY thread#;

两者差值归零,告警自动恢复,这次"dg同步停止"才算正式画上句号。

3.4 一个容易踩的坑:UNNAMED文件名写错导致的二次故障

我在处理过程中其实还踩过一个附加坑——第一次执行ALTER DATABASE CREATE DATAFILE时,把文件名写成了UNNAMED0018(少打一个 0)。Oracle 报ORA-01189: file is from different incarnation,看着很像数据库版本问题,其实只是文件名对不上。UNNAMED 文件的数字部分必须跟 V$DATAFILE 里的 FILE# 严格对应,18 就是 UNNAMED00018,前面补零补到五位,不能自己乱拼。这个细节说大不大,说小不小,浪费了我十分钟查日志。

4. 根因复盘:备库为什么给你整出个UNNAMED文件

4.1 standby_file_management参数的角色定位

修复做完只是治标,把根因挖出来才是治本。这次事故真正的源头,是备库的standby_file_management参数被设置成了MANUAL。这个参数的作用,就是决定备库在遇到主库新增数据文件时,到底要不要自动帮你把文件建出来。它的两个取值差别巨大:

参数值行为适用场景
AUTO备库自动创建缺失的数据文件推荐生产环境使用
MANUAL不创建,MRP 报错停止手动维护、特殊演练场景

有人可能会问:设置成 AUTO 是不是就永远不会出现 UNNAMED 文件了?也不是。AUTO 只在路径映射能正确推导时才生效。如果备库侧目录不存在、权限不足、ASM 磁盘组空间不够,AUTO 也会建文件失败,最终还是可能落到 UNNAMED 的结局。所以参数对,路径也得对,两者缺一不可。

4.2 路径映射与命名规范的连锁反应

再挖一层,路径映射这块怎么个对法?DG 主备库如果目录结构完全一样(比如主备都叫/data/app),那 AUTO 模式直接用原路径创建即可;如果目录不一样,就得靠DB_FILE_NAME_CONVERT来定义映射规则。我当时的环境里,这个参数原本只配了两对映射:

-- 主库参数文件里的配置(示意) *.db_file_name_convert='/data/prod','/data/standby'

从字面上看,/data/prod到/data/standby的映射没问题。但问题恰恰出在:主库新增的数据文件路径是/data/prod/ts_app01.dbf,备库按规则应该创建/data/standby/ts_app01.dbf,这个逻辑本身是对的。可为什么没建出来?因为我当时的备库参数是 MANUAL——参数 override 了路径映射的自动行为。也就是说,你就算映射规则配得再完美,只要 standby_file_management 不是 AUTO,Oracle 也会按 MANUAL 的规则来:发现缺文件,直接报错,不自动建。

这段复盘让我意识到一个经验:排查 UNNAMED 问题不要一上来就盯着 DB_FILE_NAME_CONVERT,先看 standby_file_management 永远是第一优先级,因为它直接决定了后续动作是"自动建"还是"报错停"。

4.3 还有其他场景会生成UNNAMED文件吗

除了这次的主因,实际运维中还遇到过这么几种情况,一并列出来给大家参考:

  1. 备库做过不完全恢复或控制文件重建:控制文件里记录的数据文件和实际磁盘布局不一致,扫描时生成了 UNNAMED 条目。
  2. 快照备库(Snapshot Standby)转回物理备库:快照期间主库新增了数据文件,转换回来后部分文件未能同步,可能在 V$DATAFILE 留下 UNNAMED。
  3. ASM 磁盘组路径不匹配:主库用+DATA1磁盘组,备库只有+DATA2,又没有配置相应映射规则,AUTO 也建不出来。
  4. 手动更改了主库数据文件名称:涉及数据文件 rename 的 redo 信息传到备库后,如果备库找不到旧文件,也会触发类似问题。

以上场景有个共同特征:UNNAMED 文件出现的一瞬间,DG 同步必然停止。因为 Data Guard 的恢复进程对数据文件一致性要求极严格,任何"控制文件有而磁盘无"的文件都会让 MRP 无法继续。所以看到 UNNAMED,别想着"要不要忽略它",答案永远是"不行"。

5. 后续加固:三类配置加上一套巡检,避免UNNAMED再犯

5.1 参数层面的三条铁律

这次事故之后,我把 DG 环境的三条参数配置列为硬性检查项:

第一,standby_file_management = AUTO必须写进主备库的参数文件,并且在例行变更后复查。因为总有人在做测试、做演练的时候把它临时改成 MANUAL,改完忘了恢复。我后来在值班文档里加了一条:凡是动过这个参数的变更,结束后必须执行SHOW PARAMETER STANDBY_FILE_MANAGEMENT确认是 AUTO 才允许关闭工单。

第二,DB_FILE_NAME_CONVERT的映射规则要覆盖全库所有数据文件路径,而不是基于"当前有哪些路径"来配置。很多库的历史包袱重,有/oracle/data01、/data/prod、/u01/app/oracle等各种不同前缀的路径,新增表空间时如果没检查映射规则,AUTO 也白搭。我后来整理了一张路径规划表,把主备库所有数据文件目录的映射关系都列出来,每半年对一次,新增目录第一时间更新参数。

第三,备用文件路径要有前瞻性。比如你预计明年要加一套独立存储/data/ssd_fast,那就在规划表里提前把映射写进去,别等到真要加文件了才改参数——生产环境改参数要停机窗口,往往等不起。反正 DB_FILE_NAME_CONVERT 支持多条规则,提前配好不犯法。

5.2 变更流程里加一道"备库体检"

资深的 DG 运维都知道,主库做任何结构变更之前,必须先在备库侧做一次环境检查。这个检查不是看备库还活着就行,而是具体到:目标路径是否存在、权限是否可写、映射规则是否覆盖、空间是否充足。我建议把这个检查固化成一个脚本,每次主库建表空间、建数据文件前跑一遍。

以一个简单的加数据文件场景为例,变更前至少确认这三件事:

-- 1. 备库目标路径是否存在(OS 层面确认) -- 2. 备库剩余空间是否大于新增文件大小 -- 3. DB_FILE_NAME_CONVERT 是否覆盖目标路径 SELECT value FROM v$parameter WHERE name = 'db_file_name_convert';

如果这三项都通过,大概率不会撞上 UNNAMED 的问题。如果有一项没通过,宁可先停下来改参数、建目录、清空间,也不要带着隐患直接在主库加文件。

5.3 日常巡检脚本的四个关键查询

最后,把这次排障用到的几个查询整理成一套日常巡检脚本,建议放到监控平台或者 cron 里定期执行。四个关键查询:

-- 1. 查 UNNAMED 文件(一旦有输出,DG 基本已经出问题了) SELECT file#, name, status FROM v$datafile WHERE name LIKE 'UNNAMED%'; -- 2. 查同步延迟 SELECT name, value FROM v$dataguard_stats WHERE name IN ('apply lag', 'transport lag'); -- 3. 查 MRP 进程状态 SELECT process, status FROM v$managed_standby WHERE process = 'MRP0'; -- 4. 查归档 gap SELECT * FROM v$archive_gap;

这套巡检的价值在于,它能让你第一时间发现苗头。打个比方,UNNAMED 就像身体里的X光片上的阴影,你等到警报响起再去看,往往已经痛了很久;但定期扫一遍,出了问题当场就能按住。

我处理完这次故障之后,把 UNNAMED 的排查流程写成了一页速查卡:出现ORA-01157先查V$DATAFILE里有没有 UNNAMED,有就查主库对应 FILE# 的真实路径,然后备库建目录、执行ALTER DATABASE CREATE DATAFILE、恢复 MRP。全程十五分钟搞定,比摸黑排查舒服太多。Data Guard 故障并不可怕,可怕的是你连控制文件里那个"幽灵文件"叫什么名字都不知道——经历过这次,我至少不会再在这上面栽跟头了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询