Oracle RMAN 备份与恢复

目录


简介

RMAN(Recovery Manager)是 Oracle 提供的官方备份与恢复工具,支持:

  • 物理备份(数据文件、控制文件、归档日志)
  • 块级增量备份
  • 自动化恢复
  • 与 Oracle Secure Backup、NFS、磁带库等集成

本文重点讲解如何通过 RMAN 实现 全量 + 增量备份策略,并提供可直接用于生产环境的脚本。


环境准备

确保以下条件满足:

# 设置环境变量(建议写入 ~/.bash_profile)
export ORACLE_SID=orcl
export ORACLE_HOME=/u01/app/oracle/product/19.0.0/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
变量作用
ORACLE_SID指定要操作的数据库实例名(必须与实际一致)。
ORACLE_HOMEOracle 软件安装目录,RMAN 可执行文件在此目录的 bin/ 下。
PATH让系统能找到 rman 命令。
NLS_LANG设置字符集和语言,避免日志中出现乱码或日期格式错误。

启用归档模式(必须):

SQL> SHUTDOWN IMMEDIATE;
SQL> STARTUP MOUNT;
SQL> ALTER DATABASE ARCHIVELOG;
SQL> ALTER DATABASE OPEN;
SQL> ARCHIVE LOG LIST;  -- 确认处于 Archive Mode

配置 RMAN 默认参数(可选但推荐):

RMAN> CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 7 DAYS;
RMAN> CONFIGURE CONTROLFILE AUTOBACKUP ON;
RMAN> CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/backup/rman/cf_%F';
RMAN> CONFIGURE CHANNEL DEVICE TYPE DISK FORMAT '/backup/rman/%U';
命令作用说明
CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 7 DAYS;设置保留策略:RMAN 只保留足够恢复到最近 7 天内任意时间点的备份。超过 7 天的备份会被标记为“obsolete”(过期),可用 DELETE OBSOLETE 删除。
CONFIGURE CONTROLFILE AUTOBACKUP ON;启用控制文件自动备份。每次 RMAN 备份后(或结构变更如添加数据文件),RMAN 会自动备份控制文件和 SPFILE。
CONFIGURE CONTROLFILE AUTOBACKUP FORMAT ... TO '/backup/rman/cf_%F';指定自动备份的控制文件保存路径和命名格式。
- %F 是一个特殊占位符,生成唯一名称(如 c-1234567890-20250101-00),包含 DBID、日期、序列号,确保不冲突。
CONFIGURE CHANNEL DEVICE TYPE DISK FORMAT '/backup/rman/%U';设置默认磁盘通道的备份文件命名规则。
- %U 生成唯一文件名(如 01abc123_1_1),避免重名。

为什么重要?
这些配置让 RMAN 自动化程度更高,减少手动指定路径的错误,也便于恢复时定位文件。

全量备份(Full Backup)

全量备份 = Level 0 增量备份(Oracle 中全备通常用 BACKUP INCREMENTAL LEVEL 0 实现)。

RMAN 命令

RUN {
  ALLOCATE CHANNEL c1 TYPE DISK;
  BACKUP INCREMENTAL LEVEL 0 
    DATABASE 
    PLUS ARCHIVELOG 
    DELETE INPUT;
  BACKUP CURRENT CONTROLFILE;
  RELEASE CHANNEL c1;
}
说明
RUN { ... }RMAN 的执行块,用于组合多个命令。
ALLOCATE CHANNEL c1 TYPE DISK;手动分配一个名为 c1 的磁盘通道。通道是 RMAN 与存储设备通信的“管道”。这里使用本地磁盘。
BACKUP INCREMENTAL LEVEL 0 DATABASE执行 Level 0 增量备份,即备份数据库中所有使用过的数据块(等效于全量备份)。
⚠️ 注意:Oracle 中没有单独的 “FULL BACKUP” 命令,Level 0 就是全量。
PLUS ARCHIVELOG在备份数据库前/后,自动备份所有归档日志。确保恢复时有完整的 redo 流。
DELETE INPUT备份完归档日志后,删除源归档日志文件(仅限已成功备份的)。节省空间,但需确保备份可靠!
BACKUP CURRENT CONTROLFILE;显式备份当前控制文件(虽然启用了 autobackup,但显式再备一次更保险)。
RELEASE CHANNEL c1;释放通道资源。

📌 关键概念

  • Level 0 ≠ FULL?实际上在恢复时,Level 0 被当作全量使用。
  • PLUS ARCHIVELOG DELETE INPUT 是生产环境常用组合,但务必监控归档空间!

增量备份(Incremental Backup)

Oracle 支持两种增量:

  • Level 0:包含所有数据块(等同于全量)
  • Level 1
    • Differential(默认):备份自上次 Level 0 或 Level 1 以来变化的块
    • Cumulative:备份自上次 Level 0 以来所有变化的块

Level 1 差异增量备份(推荐)

RUN {
  ALLOCATE CHANNEL c1 TYPE DISK;
  BACKUP INCREMENTAL LEVEL 1 
    DATABASE 
    PLUS ARCHIVELOG 
    DELETE INPUT;
  RELEASE CHANNEL c1;
}
  • LEVEL 1:只备份自上一次 Level 0 或 Level 1 以来发生变化的数据块(差异增量)。
  • 默认是 Differential(差异),不是 Cumulative。
  • 例如:
    • 周日:Level 0
    • 周一:Level 1 → 备周一变化
    • 周二:Level 1 → 备周二变化(不是周一周二总和)
  • 恢复时需:Level 0 + 所有后续 Level 1 + 归档日志。

优点:节省备份时间和空间。
风险:若中间某天 Level 1 丢失,之后所有增量都无法用。

恢复操作

完全恢复(数据库崩溃后)

假设整个数据库丢失(如磁盘故障),需从备份完全恢复:

# 启动到 nomount
RMAN> STARTUP FORCE NOMOUNT;

# 恢复控制文件(若启用了 autobackup)
RMAN> RESTORE CONTROLFILE FROM '/backup/rman/cf_c-1234567890-20250101-00';

RMAN> ALTER DATABASE MOUNT;

# 恢复数据库
RMAN> RESTORE DATABASE;

# 应用归档日志进行恢复
RMAN> RECOVER DATABASE;

# 打开数据库(需 resetlogs,因控制文件是恢复的)
RMAN> ALTER DATABASE OPEN RESETLOGS;

⚠️ 注意:OPEN RESETLOGS 会重置日志序列号,之后需立即做一次 Level 0 备份!


表空间级恢复

RMAN> SQL 'ALTER TABLESPACE users OFFLINE IMMEDIATE';
RMAN> RESTORE TABLESPACE users;
RMAN> RECOVER TABLESPACE users;
RMAN> SQL 'ALTER TABLESPACE users ONLINE';

不完全恢复(时间点恢复)

例如恢复到 2025-01-05 14:00:00:

RMAN> STARTUP MOUNT;
RMAN> RUN {
  SET UNTIL TIME "TO_DATE('2025-01-05 14:00:00', 'YYYY-MM-DD HH24:MI:SS')";
  RESTORE DATABASE;
  RECOVER DATABASE;
  ALTER DATABASE OPEN RESETLOGS;
}

自动化备份脚本

全量备份脚本(rman_full_backup.sh

#!/bin/bash
# Oracle RMAN Level 0 Backup Script (Optimized)
# Author: DBA Team
# Date: 2026-01-06

# --- 1. 加载环境变量 ---
source /home/oracle/.bash_profile

# --- 2. 强制设置关键环境变量 ---
export ORACLE_SID=orcl1
export DBNAME=orcl
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8  # 防止日期格式或字符集问题

# --- 3. 时间变量 ---
year=$(date "+%Y")
month=$(date "+%m")
day=$( date "+%d")
hour=$(date "+%H")
min=$(date "+%M")
sec=$(date "+%S")
bakdate=${year}${month}${day}
baktime=${hour}${min}${sec}

# --- 4. 路径定义 ---
BACKUP_DIR=/orabak/scsbgjb/${bakdate}
DATABAK=${BACKUP_DIR}/databak
ARCHBAK=${BACKUP_DIR}/archbak
SCRIPT_DIR=/home/oracle/enmo/backup/scripts
LOG_DIR=/home/oracle/enmo/backup/log

CMDFILE=${SCRIPT_DIR}/scsbgjb_level_0_${bakdate}_${baktime}.rman
LOGFILE=${LOG_DIR}/${bakdate}_${baktime}_level_0.log

# --- 5. 创建目录 ---
mkdir -p "${DATABAK}" "${ARCHBAK}" "${SCRIPT_DIR}" "${LOG_DIR}"

# --- 6. 记录开始时间 ---
echo "[$(date)] Starting RMAN Level 0 Backup for DB: ${DBNAME} (SID: ${ORACLE_SID})" | tee "${LOGFILE}"

# --- 7. 生成 RMAN 命令文件 ---
cat > "${CMDFILE}" << EOF
RUN {
  # 分配 10 个并行通道(根据 I/O 能力调整)
  ALLOCATE CHANNEL ch1 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch2 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch3 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch4 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch5 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch6 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch7 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch8 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch9 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch10 DEVICE TYPE DISK;

  # 强制归档当前日志,确保一致性
  SQL 'ALTER SYSTEM ARCHIVE LOG CURRENT';

  # 备份数据库(Level 0 + 压缩)
  BACKUP AS COMPRESSED BACKUPSET
    INCREMENTAL LEVEL 0
    FILESPERSET 20
    FORMAT '${DATABAK}/${DBNAME}_level_0_%U_%T'
    DATABASE;

  # 备份所有尚未备份过的归档日志(更安全)
  BACKUP AS COMPRESSED BACKUPSET
    SKIP INACCESSIBLE
    FILESPERSET 20
    FORMAT '${ARCHBAK}/${DBNAME}_arch_%U_%T'
    ARCHIVELOG ALL NOT BACKED UP 1 TIMES;

  # 显式备份控制文件和 SPFILE(即使启用了 autobackup)
  BACKUP CURRENT CONTROLFILE FORMAT '${BACKUP_DIR}/${DBNAME}_control_bak_%T';
  BACKUP SPFILE TAG 'spfile' FORMAT '${BACKUP_DIR}/${DBNAME}_spfile_%U_%T';

  # 释放通道
  RELEASE CHANNEL ch1; RELEASE CHANNEL ch2; RELEASE CHANNEL ch3; RELEASE CHANNEL ch4;
  RELEASE CHANNEL ch5; RELEASE CHANNEL ch6; RELEASE CHANNEL ch7; RELEASE CHANNEL ch8;
  RELEASE CHANNEL ch9; RELEASE CHANNEL ch10;
}

# 清理:仅本次使用 30 天保留策略(不修改全局配置)
REPORT OBSOLETE RECOVERY WINDOW OF 30 DAYS;
DELETE NOPROMPT OBSOLETE RECOVERY WINDOW OF 30 DAYS;

# 校验并清理失效备份
CROSSCHECK BACKUP;
CROSSCHECK ARCHIVELOG ALL;
DELETE NOPROMPT EXPIRED BACKUP;
DELETE NOPROMPT EXPIRED ARCHIVELOG;
EOF

# --- 8. 执行 RMAN ---
echo "[$(date)] Executing RMAN command from: ${CMDFILE}" >> "${LOGFILE}"
$ORACLE_HOME/bin/rman TARGET / CMDLINE="SET ECHO ON" LOG="${LOGFILE}" < "${CMDFILE}"

# --- 9. 检查执行结果 ---
if [ ${?} -eq 0 ]; then
  echo "[$(date)] ✅ RMAN Level 0 Backup SUCCESSFUL." >> "${LOGFILE}"
  echo "Backup completed successfully. Log: ${LOGFILE}"
else
  echo "[$(date)] ❌ RMAN Level 0 Backup FAILED!" >> "${LOGFILE}"
  echo "ERROR: Backup failed! Check log: ${LOGFILE}" >&2
  exit 1
fi

增量 Level 1 备份脚本(rman_incr_backup.sh

#!/bin/bash
# Oracle RMAN Level 1 Incremental Backup Script (Optimized)
# Author: DBA Team
# Date: 2026-01-06

# --- 1. 加载环境变量 ---
source /home/oracle/.bash_profile

# --- 2. 强制设置关键环境变量 ---
export ORACLE_SID=orcl1
export DBNAME=orcl
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8  # 避免日期/字符集问题

# --- 3. 时间变量 ---
year=$(date "+%Y")
month=$(date "+%m")
day=$(date "+%d")
hour=$(date "+%H")
min=$(date "+%M")
sec=$(date "+%S")
bakdate=${year}${month}${day}
baktime=${hour}${min}${sec}

# --- 4. 路径定义 ---
BACKUP_DIR=/orabak/scsbgjb/${bakdate}
DATABAK=${BACKUP_DIR}/databak
ARCHBAK=${BACKUP_DIR}/archbak
SCRIPT_DIR=/home/oracle/enmo/backup/scripts
LOG_DIR=/home/oracle/enmo/backup/log

CMDFILE=${SCRIPT_DIR}/scsbgjb_level_1_${bakdate}_${baktime}.rman
LOGFILE=${LOG_DIR}/${bakdate}_${baktime}_level_1.log

# --- 5. 创建目录 ---
mkdir -p "${DATABAK}" "${ARCHBAK}" "${SCRIPT_DIR}" "${LOG_DIR}"

# --- 6. 记录开始时间 ---
echo "[$(date)] Starting RMAN Level 1 Incremental Backup for DB: ${DBNAME} (SID: ${ORACLE_SID})" | tee "${LOGFILE}"

# --- 7. 生成 RMAN 命令文件 ---
cat > "${CMDFILE}" << EOF
RUN {
  # 分配 10 个并行通道
  ALLOCATE CHANNEL ch1 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch2 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch3 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch4 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch5 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch6 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch7 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch8 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch9 DEVICE TYPE DISK;
  ALLOCATE CHANNEL ch10 DEVICE TYPE DISK;

  # 强制切换日志,确保最新变更被归档
  SQL 'ALTER SYSTEM ARCHIVE LOG CURRENT';

  # Level 1 增量备份(仅备份自上次 Level 0/1 后变化的块)
  BACKUP AS COMPRESSED BACKUPSET
    INCREMENTAL LEVEL 1
    FILESPERSET 20
    FORMAT '${DATABAK}/${DBNAME}_level_1_%U_%T'
    DATABASE;

  # 备份所有尚未备份过的归档日志(比 sysdate-1 更可靠)
  BACKUP AS COMPRESSED BACKUPSET
    SKIP INACCESSIBLE
    FILESPERSET 20
    FORMAT '${ARCHBAK}/${DBNAME}_arch_%U_%T'
    ARCHIVELOG ALL NOT BACKED UP 1 TIMES;

  # 显式备份控制文件和 SPFILE(双重保障)
  BACKUP CURRENT CONTROLFILE FORMAT '${BACKUP_DIR}/${DBNAME}_control_bak_%T';
  BACKUP SPFILE TAG 'spfile' FORMAT '${BACKUP_DIR}/${DBNAME}_spfile_%U_%T';

  # 释放通道
  RELEASE CHANNEL ch1; RELEASE CHANNEL ch2; RELEASE CHANNEL ch3; RELEASE CHANNEL ch4;
  RELEASE CHANNEL ch5; RELEASE CHANNEL ch6; RELEASE CHANNEL ch7; RELEASE CHANNEL ch8;
  RELEASE CHANNEL ch9; RELEASE CHANNEL ch10;
}

# 清理:仅本次使用 30 天保留策略(不修改全局配置)
REPORT OBSOLETE RECOVERY WINDOW OF 30 DAYS;
DELETE NOPROMPT OBSOLETE RECOVERY WINDOW OF 30 DAYS;

# 校验并清理失效备份
CROSSCHECK BACKUP;
CROSSCHECK ARCHIVELOG ALL;
DELETE NOPROMPT EXPIRED BACKUP;
DELETE NOPROMPT EXPIRED ARCHIVELOG;
EOF

# --- 8. 执行 RMAN ---
echo "[$(date)] Executing RMAN command from: ${CMDFILE}" >> "${LOGFILE}"
$ORACLE_HOME/bin/rman TARGET / CMDLINE="SET ECHO ON" LOG="${LOGFILE}" < "${CMDFILE}"

# --- 9. 检查执行结果 ---
if [ ${?} -eq 0 ]; then
  echo "[$(date)] ✅ RMAN Level 1 Backup SUCCESSFUL." >> "${LOGFILE}"
  echo "Incremental backup completed successfully. Log: ${LOGFILE}"
else
  echo "[$(date)] ❌ RMAN Level 1 Backup FAILED!" >> "${LOGFILE}"
  echo "ERROR: Incremental backup failed! Check log: ${LOGFILE}" >&2
  exit 1
fi

赋予执行权限:

chmod +x rman_full_backup.sh rman_incr_backup.sh

定期调度(crontab)

编辑 crontab:

crontab -e

添加以下内容(每周日全备,其他天增量):

# 每周日凌晨 2 点全量备份
0 2 * * 0 /home/oracle/scripts/rman_full_backup.sh

# 周一至周六凌晨 2 点增量备份
0 2 * * 1-6 /home/oracle/scripts/rman_incr_backup.sh

注意事项

  • 归档日志必须保留:恢复依赖归档日志,确保磁盘空间充足。
  • 测试恢复流程:定期在测试环境演练恢复,避免“备份成功但无法恢复”。
  • 监控日志:检查 $BACKUP_LOG 是否有 RMAN- 错误。
  • 保留策略:根据业务需求调整 RETENTION POLICY
  • 加密与压缩(可选):
    CONFIGURE COMPRESSION ALGORITHM 'BASIC';
    CONFIGURE ENCRYPTION FOR DATABASE ON;