Oracle 19c RMAN历史备份清理失败:CONTROL_FILE_RECORD_KEEP_TIME 问题排查与整改实战

一、问题背景

在 Oracle 19c RAC/ODA 环境进行日常备份巡检时,发现 NFS 备份目录中长期残留大量历史 RMAN 备份文件。

按照原有备份保留策略,超过保留周期的备份理论上应该被自动清理,但实际发现:

  • NFS 中十几天前的 Backup Piece 仍然存在;

  • RMAN 无法正常按照时间范围识别部分历史备份;

  • 旧备份长期无法清理,导致 NFS 空间持续增长。

原脚本中存在类似按时间直接清理历史备份的逻辑:

复制代码
DELETE NOPROMPT BACKUP COMPLETED BEFORE 'SYSDATE-14';

但实际执行时出现:

复制代码
specification does not match any backup in the repository

由此开始排查 RMAN Repository 与控制文件中的历史备份记录。


二、问题现象

首先检查 NFS 备份目录,可以确认历史 Backup Piece 文件实际仍然存在:

复制代码
ERPCDB_01_DATAFILE_20260812_...
ERPCDB_01_DATAFILE_20260813_...
ERPCDB_01_DATAFILE_20260814_...
...

但在 RMAN 中按照时间范围查询这些历史备份时,却无法正常识别。

进一步检查其中一个历史 Backup Set,发现:

复制代码
V$BACKUP_SET       有记录
V$BACKUP_PIECE     有记录
V$BACKUP_DATAFILE  无对应记录

例如:

复制代码
SELECT
    bs.recid,
    TO_CHAR(bs.completion_time,'YYYY-MM-DD HH24:MI:SS') completion_time,
    COUNT(bd.file#) datafile_records
FROM v$backup_set bs
LEFT JOIN v$backup_datafile bd
       ON bd.set_stamp = bs.set_stamp
      AND bd.set_count = bs.set_count
WHERE bs.recid = 6584
GROUP BY
    bs.recid,
    bs.completion_time;

结果中:

复制代码
DATAFILE_RECORDS = 0

说明:

Backup Set 和 Backup Piece 的部分记录还存在,但数据文件备份的详细元数据已经丢失。

此时问题已经不再是简单的"DELETE 为什么没执行",而是:

为什么 RMAN 的历史备份元数据提前丢失了?


三、排查分析

1. 确认 RMAN Repository 存储位置

当前环境没有使用独立的 RMAN Recovery Catalog。

因此 RMAN 的历史备份信息主要保存在数据库 Control File 中。

这意味着:

复制代码
Control File 中 RMAN Metadata 的保留能力

会直接影响 RMAN 对历史备份的识别和管理。


2. 检查 CONTROL_FILE_RECORD_KEEP_TIME

检查参数:

复制代码
SHOW PARAMETER control_file_record_keep_time;

发现:

复制代码
CONTROL_FILE_RECORD_KEEP_TIME = 7

该参数用于控制:

Control File 中可循环复用记录,在被重新使用之前至少保留多少天。

RMAN 相关记录包括:

复制代码
BACKUP SET
BACKUP PIECE
BACKUP DATAFILE
BACKUP REDOLOG
ARCHIVED LOG

如果这些记录达到可复用条件,Oracle 就可能重新使用对应记录槽位。

因此可能出现:

复制代码
Backup Piece物理文件仍然存在
        ↓
Control File中的部分RMAN元数据已经被覆盖
        ↓
RMAN无法完整识别历史备份
        ↓
历史文件无法正常通过RMAN清理

3. 检查 Control File Record Section

进一步检查:

复制代码
SELECT
    type,
    records_total,
    records_used
FROM v$controlfile_record_section
WHERE type IN (
    'ARCHIVED LOG',
    'BACKUP SET',
    'BACKUP PIECE',
    'BACKUP DATAFILE',
    'BACKUP REDOLOG'
);

现场发现多个 RMAN Record Section:

复制代码
RECORDS_USED = RECORDS_TOTAL

这本身并不代表控制文件异常,因为这些区域本来就是循环使用的。

但结合:

复制代码
CONTROL_FILE_RECORD_KEEP_TIME = 7

以及历史 V$BACKUP_DATAFILE 记录已经消失,可以判断:

Control File 中的历史 RMAN Metadata 已经发生循环复用。


四、问题定位

最终问题链路可以概括为:

复制代码
每天产生大量RMAN备份记录
        ↓
CONTROL_FILE_RECORD_KEEP_TIME仅7天
        ↓
历史RMAN记录较早进入可复用状态
        ↓
部分Backup Datafile元数据被覆盖
        ↓
NFS上的Backup Piece仍然存在
        ↓
RMAN无法完整识别这些历史备份
        ↓
DELETE/LIST无法正常管理
        ↓
历史备份长期残留
        ↓
NFS空间持续增长

最终根因:

RMAN 实际备份保留周期,与 Control File 中 RMAN Metadata 的保留周期不匹配。


五、相关整改

1. 调整 CONTROL_FILE_RECORD_KEEP_TIME

整改后计划采用:

复制代码
RMAN Recovery Window = 14天

如果仍然保持:

复制代码
CONTROL_FILE_RECORD_KEEP_TIME = 7天

就会出现:

复制代码
希望RMAN管理14天的恢复窗口
        ↓
但RMAN元数据7天后就可能被复用

因此最终调整为:

复制代码
CONTROL_FILE_RECORD_KEEP_TIME = 21天
RMAN Recovery Window          = 14天

即:

复制代码
14天恢复窗口
+
7天RMAN元数据缓冲
=
21天

RAC 环境只需要在任意一个实例执行一次:

复制代码
ALTER SYSTEM SET control_file_record_keep_time=21
SCOPE=BOTH
SID='*';

其中:

复制代码
SID='*'

表示使用 RAC 全局配置。

复制代码
SCOPE=BOTH

表示同时修改当前运行参数和 SPFILE。

该参数支持动态修改,因此无需重启数据库。

修改后通过:

复制代码
SELECT inst_id, value
FROM gv$parameter
WHERE name = 'control_file_record_keep_time'
ORDER BY inst_id;

确认两个 RAC 实例均为:

复制代码
21

2. 修改 RMAN Retention Policy

原环境:

复制代码
CONFIGURE RETENTION POLICY TO REDUNDANCY 1;

调整为:

复制代码
CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 14 DAYS;

检查:

复制代码
SHOW RETENTION POLICY;

应看到:

复制代码
CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 14 DAYS;

整改后形成:

复制代码
CONTROL_FILE_RECORD_KEEP_TIME = 21天
              >
RECOVERY WINDOW               = 14天

3. 为什么不再按 SYSDATE 硬删除全备?

原脚本类似:

复制代码
DELETE BACKUP COMPLETED BEFORE 'SYSDATE-14';

这种方式主要按照 Backup 完成时间进行删除。

整改后改为:

复制代码
DELETE NOPROMPT OBSOLETE;

由 RMAN 根据:

复制代码
RECOVERY WINDOW OF 14 DAYS

判断哪些 Backup 已经不再需要。

需要特别注意:

复制代码
RECOVERY WINDOW OF 14 DAYS

并不等于:

复制代码
超过14天的文件全部删除

RMAN 可能仍然需要某个更早的 Full Backup 作为恢复窗口的基线,因此这个 Backup 可能继续保留。

所以:

复制代码
RECOVERY WINDOW + DELETE OBSOLETE

比固定日期硬删除更符合 RMAN 的备份生命周期管理机制。


六、历史异常备份处理

修改参数只能避免未来继续出现同类问题。

对于之前已经发生元数据丢失的历史 Backup Piece:

复制代码
物理文件仍然存在
+
RMAN元数据已经不完整

无法通过修改参数自动恢复这些历史 Repository 信息。

因此需要进行一次性专项清理。

本次首先确认:

复制代码
当前可正常识别的备份起始时间
历史异常文件范围
当前恢复保留需求

随后将确认不再需要的历史异常 Backup Piece 清理。

清理完成后:

复制代码
历史异常Backup Piece:已清理
历史残留文件:0
剩余Backup:AVAILABLE
NFS空间恢复正常

此类历史异常文件只需要专项处理一次。

后续正常备份不再通过操作系统按时间清理,而统一交给 RMAN:

复制代码
DELETE OBSOLETE;

七、整改后的 RMAN 脚本

脚本整改主要有三个重点。

1. 删除原来的时间硬删除逻辑

取消类似:

复制代码
DELETE BACKUP COMPLETED BEFORE 'SYSDATE-7';
DELETE BACKUP COMPLETED BEFORE 'SYSDATE-14';

统一使用:

复制代码
DELETE NOPROMPT OBSOLETE;

2. 主库 RMAN 核心逻辑

最终核心逻辑如下:

复制代码
RUN {

    ALLOCATE CHANNEL c1 DEVICE TYPE DISK;
    ALLOCATE CHANNEL c2 DEVICE TYPE DISK;
    ALLOCATE CHANNEL c3 DEVICE TYPE DISK;
    ALLOCATE CHANNEL c4 DEVICE TYPE DISK;

    CROSSCHECK BACKUP;
    CROSSCHECK ARCHIVELOG ALL;

    DELETE NOPROMPT EXPIRED ARCHIVELOG ALL;
    DELETE NOPROMPT EXPIRED BACKUP;

    DELETE NOPROMPT OBSOLETE;

    SQL 'ALTER SYSTEM ARCHIVE LOG CURRENT';

    BACKUP AS COMPRESSED BACKUPSET DATABASE
        FORMAT '/backup_nfs/oracle/rman/%d_01_DATAFILE_%T_%U';

    BACKUP AS COMPRESSED BACKUPSET ARCHIVELOG ALL
        FORMAT '/backup_nfs/oracle/rman/%d_02_ARCHIVELOG_%T_%s_%U';

    BACKUP AS COMPRESSED BACKUPSET CURRENT CONTROLFILE
        FORMAT '/backup_nfs/oracle/rman/%d_03_CONTROLFILE_%T_%p_%s_%U';

    BACKUP AS COMPRESSED BACKUPSET SPFILE
        FORMAT '/backup_nfs/oracle/rman/%d_04_SPFILE_%T_%U';

    DELETE NOPROMPT ARCHIVELOG
        UNTIL TIME 'SYSDATE-3'
        BACKED UP 1 TIMES TO DISK;

    DELETE NOPROMPT OBSOLETE;

    RELEASE CHANNEL c1;
    RELEASE CHANNEL c2;
    RELEASE CHANNEL c3;
    RELEASE CHANNEL c4;
}

清理逻辑最终分成三类:

复制代码
EXPIRED
→ RMAN有记录,但实际文件已经不存在

OBSOLETE
→ 文件存在,但根据14天Recovery Window已经不再需要

ARCHIVELOG
→ 超过3天并且至少已经备份1次后删除

3. 增加 NFS 挂载检查

在执行 RMAN 之前增加:

复制代码
检查NFS是否真正挂载
检查RMAN目录是否存在
检查RMAN目录是否可写

如果任意一项异常:

复制代码
立即停止备份脚本

主要防止:

复制代码
NFS掉挂
      ↓
RMAN写入本地挂载点目录
      ↓
数据库服务器本地磁盘被写满
      ↓
影响数据库稳定运行

八、整改后的最终关系

整改完成后的整体策略:

复制代码
CONTROL_FILE_RECORD_KEEP_TIME
            21天
              │
              ▼
     RMAN Metadata保留
              │
              ▼
RECOVERY WINDOW OF 14 DAYS
              │
              ▼
       DELETE OBSOLETE
              │
              ▼
      自动管理历史全备

主库归档:

复制代码
超过3天
+
已备份至少1次
=
删除

ADG 备库:

复制代码
本地归档保留3天

脚本日志:

复制代码
保留14天

九、以后遇到同类问题怎么快速排查?

以后如果再次遇到:

复制代码
物理Backup Piece明明存在
但是RMAN查询不到
或者DELETE无法正常清理

按照下面顺序检查即可:

复制代码
① 查看物理Backup Piece是否存在
        ↓
② RMAN LIST能否正常识别历史Backup
        ↓
③ 检查V$BACKUP_SET
        ↓
④ 检查V$BACKUP_PIECE
        ↓
⑤ 检查V$BACKUP_DATAFILE是否还有明细
        ↓
⑥ 检查CONTROL_FILE_RECORD_KEEP_TIME
        ↓
⑦ 检查RMAN RETENTION POLICY
        ↓
⑧ 判断Metadata保留周期是否小于实际备份保留需求

最关键的判断是:

复制代码
Backup Set有记录
Backup Piece有记录
Backup Datafile已经没有记录

出现这种情况时,就要重点怀疑:

Control File 中 RMAN 历史元数据已经发生循环覆盖。

而不是继续反复修改 DELETE 命令。


十、总结

本次问题表面现象是:

复制代码
历史RMAN备份无法正常清理

实际问题是:

复制代码
CONTROL_FILE_RECORD_KEEP_TIME过短
        ↓
RMAN历史Metadata提前被循环复用
        ↓
Backup Piece仍在
但RMAN已经无法完整识别
        ↓
历史文件长期残留

最终整改:

复制代码
CONTROL_FILE_RECORD_KEEP_TIME = 21天

RMAN RETENTION POLICY
= RECOVERY WINDOW OF 14 DAYS

全备历史清理
= DELETE OBSOLETE

主库归档
= 3天 + BACKED UP 1 TIMES TO DISK

增加NFS挂载保护

这次问题最值得记录的一点是:

RMAN 备份保留不能只关注磁盘上的 Backup Piece,还必须同时考虑 Control File 中 RMAN Repository 能保存多久。

以后碰到"文件还在,但 RMAN 已经不认识"的问题,优先检查:

复制代码
V$BACKUP_SET
V$BACKUP_PIECE
V$BACKUP_DATAFILE
CONTROL_FILE_RECORD_KEEP_TIME
RMAN RETENTION POLICY

基本就能快速判断是不是 RMAN Metadata 生命周期导致的问题。

相关推荐
2601_9620739724 分钟前
【MySQL】全面学习数据库查询技巧:查询指令深度学习指南
数据库·学习·mysql
新知图书27 分钟前
12.3 智能体中Skill的约束与自进化实战
java·前端·数据库
Alphapeople35 分钟前
moveit真机部署
linux·运维·服务器
小小龙学IT1 小时前
Qt 数据库编程(Qt SQL 模块)深度解析
数据库·sql·qt
pt10431 小时前
网络自动化Python课程:Netconf与Restconf及Cisco自动化配置实验
网络·python·自动化
Eminem891 小时前
2、k8s环境规划
linux·运维·kubernetes
神仙别闹1 小时前
基于C++ WinPcap 的网络抓包软件
网络·c++·php
TDengine (老段)1 小时前
TDengine vs InfluxDB — 全方位对比
大数据·数据库·物联网·时序数据库·tdengine·涛思数据·iotdb
我的xiaodoujiao1 小时前
Django 基础知识详细图文教程 4-Django 视图定义与使用
开发语言·数据库·后端·测试工具·django·sqlite