☰
Oracle Data Guard同步停止+UNNAME文件故障排查与恢复实战
2026/10/1 11:31:07 网站建设 项目流程

很多刚接触Oracle Data Guard的DBA都有过这种经历:某天登录备库一看,MRP0进程状态不是“APPLYING_LOG”,而是“WAITING_FOR_LOG”,同步早就悄悄停了;再翻alert日志,发现一条带着UNNAME字段的错误记录,还跟着一串类似UNNAMED00518.arc或者UNNAMED00003.dbf的文件名。这就是标题里说的“dg同步停止+UNNAME文件”场景。这篇文章就把这个组合故障从原理到恢复讲透,包括UNNAME文件是怎么来的、怎么确认同步停在哪一段日志、以及归档日志丢失时最稳妥的追平方式。不管你是刚上手DG的新手,还是负责生产库的运维老手,这套排查思路和恢复动作都能直接照用。

1. 先搞清楚UNNAME文件是怎么冒出来的

1.1 Oracle Data Guard同步链路里的三个关键角色

要理解UNNAME文件,先得说清楚DG同步的正常工作链路。主库那边的日志传输,要么靠LGWR进程实时把redo推给备库,要么靠ARCH进程归档后传输;备库这边接收到日志的进程叫RFS,它会把redo写进standby redo log(如果配置了)或者直接归档;最终真正把日志内容应用进备库数据文件的进程是MRP0。MRP0扫到一个日志文件,打开它、读取redo记录、apply进去,然后继续扫下一个。

这条链路里任何一环出了问题,同步都会卡住。但“卡住”也分两种:一种是RFS还在正常收日志,只是MRP0应用不过来,这种通常表现为备库不断累积延迟,不一定会立刻产生UNNAME文件;另一种是MRP0需要的某个归档日志“根本不存在”,这个时候Oracle就会尝试用UNNAME占位文件名去引用它,同时把同步状态改成WAITING或中断。所以UNNAME文件可以理解为“MRP0找不到日志时打的一张欠条”,是故障结果而不是故障原因。

1.2 UNNAME文件在“同步停止”里扮演什么角色

UNNAME文件的典型出现过程是这样:备库的MRP0正按序列号(sequence)顺序应用归档,比如已经应用到了1_128,下一个需要的是1_129;但备库上翻遍自己的归档目录、FRA闪回恢复区,都找不到1_129对应的物理文件。于是MRP0尝试在配置好的归档目标位置创建一个名为UNNAMExxxxx的文件,同时在alert日志里报出错误。常见伴随错误是ORA-00308(无法打开归档日志)和ORA-01291(缺少日志文件)。

这里有一点容易误导人:UNNAME文件不一定是真实落盘的大文件,很多时候它只是Oracle内部元数据里的一个占位记录。你可能会在备库的db_recovery_file_dest目录下看到一个0字节或者几KB的UNNAME文件,也可能什么都看不到,但DBA视图里它已经存在了。我在实际环境里两种都见过。如果是RAC双实例备库,还可能在两个实例各自的FRA下各出现一个UNNAME占位文件,排查时要多看一个维度。

搞清楚这个机制后,后面所有排查都应该围绕一个问题展开:MRP0要的那段日志,到底还在不在?在的话在哪里?不在的话怎么补?

2. 同步停止排查:从确认进程到定位缺失归档

2.1 用三个视图快速给备库“体检”

发现同步停止后,不要急着去补日志,先把备库的当前状态完整摸一遍。我习惯按下面顺序执行三组SQL。

第一组,看MRP0和RFS进程状态:

SELECT PROCESS, STATUS, THREAD#, SEQUENCE#, BLOCK#, DELAY_MINS FROM V$MANAGED_STANDBY;

重点看MRP0这一行。状态如果是WAITING_FOR_LOG,说明MRP0已经不再继续应用,正在等某个日志;如果看到APPLYING_LOG,说明它还在尽力往后追,同步停止可能是刚发生或者应用速度跟不上;RFS一行如果状态异常,则问题出在日志接收环节。

第二组,直接查缺口(gap):

SELECT * FROM V$ARCHIVE_GAP;

这个视图是Oracle专门用来显示备库当前缺失日志范围的。如果查询有返回,第一列是thread,第二列是缺失的起始sequence,第三列是结束sequence。比如返回1, 130, 132,意思就是备库缺1号线程的130到132三段日志。没有返回不代表万事大吉,只能说明当前没有检测到连续缺口,仍需要结合归档列表确认。

第三组,看备库已应用日志的完整清单:

SELECT THREAD#, SEQUENCE#, APPLIED, DELETED, NAME FROM V$ARCHIVED_LOG ORDER BY THREAD#, SEQUENCE#;

这里主要看APPLIED列。如果有大量归档处于NO状态,说明MRP0停在那里很久了;再结合NAME列,可能就是UNNAME文件出现在那个位置附近。

2.2 alert日志和trace里该看什么

视图查完后,一定要去备库alert日志里核实具体报错。大部分时候你会看到类似下面的内容:

Errors in file /u01/app/oracle/diag/rdbms/standby/standby/trace/standby_mrp0_12345.trc: ORA-00308: cannot open archived log '/u01/app/oracle/fast_recovery_area/STANDBY/archivelog/2024_11_03/o1_mf_1_130_UNNAME.arc' ORA-01291: missing log file

注意看两个关键信息:一个是报错路径,它会直接告诉你MRP0在哪个目录下找文件;另一个是trace文件名里的进程ID,方便进一步翻trace。顺着手上的UNNAMED1_130.arc这个文件名,已经能定位到缺失的序列号是130。

我还遇到过一种情况:alert日志里报的是RFS进程的错,比如RFS: Possible network disconnect,但MRP0还在正常应用。这种其实不是真正的UNNAME问题,只是归档传输短暂中断,RFS和MRP0之间的等待拉长了。先查网络和监听,不要一上来就用增量备份把备库重建一遍,那样反而把简单问题复杂化。

3. 恢复同步的两种实操路线

3.1 归档文件还在,只是没传到备库

这是最理想的情况。确认备库缺少某段归档后,先去主库查这段日志是否还存在。主库执行:

SELECT NAME, SEQUENCE#, DELETED FROM V$ARCHIVED_LOG WHERE THREAD# = 1 AND SEQUENCE# BETWEEN 130 AND 132 ORDER BY SEQUENCE#;

如果主库返回的DELETED='NO',说明物理文件还在。接下来只要把它从主库拷贝到备库对应目录,再在备库手动注册归档,MRP0就能继续。具体步骤:

先取消当前的恢复进程,避免它和你抢文件:

ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;

然后在主库把归档文件拷贝到备库。可以用操作系统scp,也可以用Oracle的DBMS_FILE_TRANSFER包。我在生产环境更倾向于直接在备库从主库拉文件,因为这样不占用主库本地磁盘IO写路径。拷贝的目标目录必须和alert日志里报错路径一致,比如上次报错路径是/u01/app/oracle/fast_recovery_area/STANDBY/archivelog/2024_11_03/,就要把文件放到同样的年月子目录下。

拷贝完成后,在备库注册这段日志,让Oracle认可它:

ALTER DATABASE REGISTER LOGFILE '/u01/app/oracle/fast_recovery_area/STANDBY/archivelog/2024_11_03/o1_mf_1_130_xxxxx.arc';

注册无误后重新启动恢复进程:

ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;

之后等几分钟,再查V$MANAGED_STANDBY,MRP0状态应该变成APPLYING_LOG,V$ARCHIVE_GAP也没有记录了。如果备库一直处于实时应用模式,理论上它会自动开始追平主库新产生的日志。

3.2 归档文件已经丢失,用增量备份追平

如果主库上那些缺失的归档也已经被删除,那就不能靠“补文件”解决,因为文件物理上已经不存在了。这种情况下最稳妥、我实站使用最多的方案,是用RMAN增量备份把备库追平到断点附近,而不是直接重建备库。

操作思路并不复杂:找一个主库上的SCN作为增量起点,这个SCN就是备库已经应用到的位置之后的那个点。可以从备库查询最近一个成功应用日志的NEXT_SCN,也可以直接用主库当前scn往前推。实际操作我建议用下面方法确认起点:

在备库查最近已应用日志:

SELECT THREAD#, MAX(SEQUENCE#) KEEP (DENSE_RANK LAST ORDER BY SEQUENCE#) AS LAST_APPLIED_SEQ, MAX(NEXT_CHANGE#) KEEP (DENSE_RANK LAST ORDER BY SEQUENCE#) AS NEXT_SCN FROM V$ARCHIVED_LOG WHERE APPLIED = 'YES' GROUP BY THREAD#;

拿到对应SCN后,在主库执行增量备份:

rman target / BACKUP INCREMENTAL FROM SCN 636967240 DATABASE FORMAT '/backup/incr_%U' TAG 'DG_CATCHUP' INCLUDE CURRENT CONTROLFILE FOR STANDBY;

这里的关键点是FROM SCN,它决定了增量备份只包含从断点之后产生的数据块,体积远小于全量备份,传输时间和恢复时间都可控。如果断点离当前时间已经很久,增量备份也可能很大,但那也比全备好。

把生成的备份集传给备库后,在备库RMAN里执行:

rman target / CATALOG START WITH '/backup/incr'; RESTORE STANDBY CONTROLFILE FROM TAG 'DG_CATCHUP'; ALTER DATABASE MOUNT; RESTORE DATABASE FROM TAG 'DG_CATCHUP'; RECOVER DATABASE NOREDO;

RECOVER DATABASE NOREDO在这里值得解释一下:它的意思是只更新数据文件头,不实际应用数据块,因为增量备份已经包含了断点以来所有变化的块;随后再启动MRP0应用断点之后的归档日志即可。

最后别忘了在备库重新启动日志应用:

ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;

这项工作做完后,备库的UNNAME报错会消失,MRP0会从新的一致性点继续追日志。我处理过的几个案例里,这种方式追平的时间基本都在半小时到两小时之间,取决于日志量和网络带宽。

3.3 UNNAME文件到底能不能直接删

很多人在恢复过程中会犹豫:既然UNNAME文件是个“错的占位文件”,能不能直接rm掉?我的建议是:不要在没有解决GAP之前动手删它。

原因很简单:UNNAME文件虽然看着碍眼,但它记录的是MRP0找不到日志时的引用信息。一旦你强行删除了文件,而MRP0还在等待那段日志,后续日志应用时可能直接报更严重的文件打开错误。正确顺序永远是——先解决缺失归档或增量追平,等MRP0已经正常继续应用后,再检查那个UNNAME文件是否还存在。如果它作为一个实际文件还存在,且没有进程占用,可以用操作系统命令删除,或者留着不管,对恢复没有实质影响。曾经有个同事在处理过程中直接删了UNNAME文件,接着MRP0立刻从WAITING变成ABORTED,最后只能重新做增量恢复,多花了一个多小时。这个坑希望你能避开。

4. 常见报错和避坑经验

4.1 报错速查表

DG同步停止时alert日志里可能同时出现好几类错误,我把常见的组合整理成了下面的速查表,方便遇到问题先对号入座。

错误或状态根因方向处理优先动作
ORA-00308归档日志文件不存在或路径不对查主备库归档是否还在,补传并REGISTER
ORA-01291缺少连续的多段归档,GAP未解决查V$ARCHIVE_GAP,按缺段范围处理
ORA-16055FAL自动补日志失败,fal_server配置问题核对主备TNS、fal客户端与服务端配置
MRP0: WAITING_FOR_LOG等不到可用归档,可能网络或GAP导致检查进程状态和归档路径,再决定是否增量追平
RFS: POSSIBLE NETWORK DISCONNECT主备网络或监听中断先修网络和监听,不急于操作备库
RFS: NO RECOVERY备库未处于恢复/归档模式确认备库MOUNT状态并重新启动MRP

这张表不是让你死记硬背,而是排查时先看报错属于“文件缺失”还是“进程等待”类别。方向定对了,动作就不会乱。

4.2 哪些配置能从源头减少UNNAME文件的出现

上一次线上故障解决后,我顺手优化了几处配置,后面同类问题明显少了很多,分享出来。

第一,备库的归档目标和FRA要设计清晰。很多UNNAME问题本质是备库的LOG_ARCHIVE_DEST和DB_RECOVERY_FILE_DEST配置混乱,RFS收到的日志被放置到某个不明确路径,MRP0却去另一个路径找文件。我建议备库统一使用FRA接收归档,并固定目录结构;同时主库和备库的DB_RECOVERY_FILE_DEST_SIZE都给足余量,至少保留一天的归档容量。

第二,FAL配置一定要正确。备库自动请求缺失日志靠的是FAL_SERVER参数,它要指向主库的TNS别名;而FAL_CLIENT指向备库自己。很多人把两个参数写反,导致备库永远无法自动请求补日志,只能靠人工处理。每次DG搭建完,我都会在主备库分别执行SHOW PARAMETER FAL核对配置。

第三,主库归档删除策略要照顾备库。生产环境经常有人设置主库归档超过3天就自动删除,备库因为网络或维护原因停了几天,等备库恢复时主库已经把中间日志删光了。这种情况几乎必出UNNAME文件。我现在的做法是:做好归档备份的前提下,主库归档保留策略中额外判断备库是否已应用该段日志,没应用就不允许清理。

4.3 监控脚本的设计经验

因为UNNAME文件是同步停止的典型信号,我把它写进了日常监控。简单做法是定时脚本扫描备库alert日志,一旦出现UNNAMED字样,立即触发告警,并顺手抓取V$MANAGED_STANDBY和V$ARCHIVE_GAP快照留档。这样即使DBA在睡梦中,第二天也能直接定位到缺失范围。

有条件的朋友,还可以对V$ARCHIVE_GAP做轮询检查,每5分钟一次;查到非空结果就发短信和邮件,同时自动执行主库归档日志存在性检查。这一步能大幅缩短故障发现时间。要知道DG同步停止不可怕,可怕的是停了很久没有人发现,UNNAME文件出现得越早,恢复成本越低。我经历过一次半夜备库同步中断,第二天上班才被业务侧发现的情况,从那以后监控脚本里UNNAME关键字就再也没去掉过。

最后再分享一个实际体会:UNNAME文件只是表象,核心永远是GAP。整个处理过程我都在心里默念“找到缺的日志,补上它,或者用增量追平它”。只要顺着这个思路走,不管遇到UNNAMED00518还是UNNAMExxxxx,都不会被吓住。顺手把备库的FRA容量和归档保留策略调整好,这类问题出一次的频率会大幅下降。如果你也按这套流程处理过类似故障,欢迎交流你那边见过的UNNAME变体形态,很多新版本的Oracle在错误信息呈现上还会有些细微差别。

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

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

立即咨询