Oracle 本地部署 RMAN 备份脚本定时备份数据库
Oracle 本地部署 RMAN 备份脚本定时备份数据库
想必大家都听过一句话:备份是数据安全的最后一道防线。数据库是整个系统以及公司最重要的数据存放仓库,如果数据损坏丢失,将直接影响到公司业务以及财产的损失,Oracle RMAN 是官方推出最流行的在线热备方式,安全高效,部署简单。

一、Oracle RMAN
在讲解如何使用 RMAN 进行备份之前,先了解下什么是 RMAN 备份吧!Recovery Manager (RMAN) 是一个 Oracle 数据库客户端,可以对数据库执行备份和恢复任务,并自动管理数据库备份策略,极大地简化了备份、还原和恢复数据库文件。
关于 Oracle RMAN 的入门使用,可以参考官方文档:RMAN 入门 写的很详细,我这里就不再赘述。

本文主要讲解如何在主机上部署 Oracle RMAN 备份脚本。
二、部署备份脚本
Oracle RMAN 在生产环境使用一般都是热备的方式,冷备需要关掉数据库才可以进行,生产环境一般是没有停机时间给你做备份的,所以冷备不太适合生产备份。热备的方式需要打开归档模式!
1、打开数据库归档模式
如果数据库已打开归档模式,执行 archive log list 可以看到以下结果:

如果未打开归档模式,一般结果显示如下:

打开数据库归档模式需要重启数据库,完整步骤如下:
-- 设置归档日志路径
alter system set log_archive_dest_1='LOCATION=/archivelog';
-- 关闭数据库,重启至mount模式
shutdown immediate
startup mount
-- 开启归档模式
alter database archivelog;
-- 打开数据库
alter database open;
-- 检查归档模式是否打开
archive log list

如上图,数据库打开归档模式之后,接下来就可以开始部署 RMAN 脚本进行在线备份了。
由于打开归档模式后会源源不断的产生归档日志,所以建议部署一个定期删除归档的任务:
## oracle 用户下执行
SCRIPTSDIR=/home/oracle/scripts
mkdir -p ${SCRIPTSDIR}
{
echo '#!/bin/bash'
echo 'source ~/.bash_profile'
echo 'deltime=`date +"20%y%m%d%H%M%S"`'
echo "rman target / nocatalog msglog ${SCRIPTSDIR}/del_arch_\${deltime}.log<<EOF"
echo 'crosscheck archivelog all;'
echo "delete noprompt archivelog until time 'sysdate-7';"
echo "delete noprompt force archivelog until time 'SYSDATE-10';"
echo 'EOF'
} >>${SCRIPTSDIR}/del_arch.sh
chmod +x ${SCRIPTSDIR}/del_arch.sh
## root 用户下执行
SCRIPTSDIR=/home/oracle/scripts
{
echo "#00 02 * * * ${SCRIPTSDIR}/del_arch.sh"
} >>/var/spool/cron/oracle
2、本地备份脚本
Oracle RMAN 备份脚本的写法多种多样,根据不同的数据库环境可能有不同的写法。比如空间不够使用压缩备份,又比如数据库太大选择增量备份等等情况,我也不能全部照顾到大家的情况,所以这里就分享一个我比较常用的备份脚本,仅供参考!该脚本为增量备份脚本,分为 0 级和 1 级,周日 0 级全备,周一至周六 1 级备份。
首先需要在本地磁盘创建一个备份目录,需要有足够的磁盘空间:
## root 用户下执行
mkdir /backup
chown -R oracle:oinstall /backup
chmod -R 775 /backup
📢 注意: 以下脚本直接复制粘贴即可使用,只需注意修改对应的备份路径即可!
周日为 0 级备份脚本:
#!/bin/bash
source ~/.bash_profile
backtime=`date +"20%y%m%d%H%M%S"`
rman target / log=/backup/level0_backup_${backtime}.log<<EOF
run {
allocate channel c1 device type disk;
allocate channel c2 device type disk;
crosscheck backup;
crosscheck archivelog all;
sql"alter system archive log current";
delete noprompt expired backup;
delete noprompt obsolete device type disk;
backup incremental level 0 database include current controlfile format '/backup/backlv0_%d_%T_%t_%s_%p';
backup archivelog all DELETE INPUT format '/backup/arch_%d_%T_%t_%s_%p';
release channel c1;
release channel c2;
}
EOF
周一至周六为 1 级备份脚本内容:
#!/bin/bash
source ~/.bash_profile
backtime=`date +"20%y%m%d%H%M%S"`
rman target / log=/backup/level1_backup_${backtime}.log<<EOF
run {
allocate channel c1 device type disk;
allocate channel c2 device type disk;
crosscheck backup;
crosscheck archivelog all;
sql"alter system archive log current";
delete noprompt expired backup;
delete noprompt obsolete device type disk;
backup incremental level 1 database include current controlfile format '/backup/backlv1_%d_%T_%t_%s_%p';
backup archivelog all DELETE INPUT format '/backup/arch_%d_%T_%t_%s_%p';
release channel c1;
release channel c2;
}
EOF
📢 注意: 如果有多个实例,每个实例对应的脚本需要手动指定实例
export ORACLE_SID。
脚本创建完之后,记得给脚本赋予可执行权限:
cd /home/oracle/scripts
chmod +x dbbackup_lv0.sh
chmod +x dbbackup_lv1.sh
ls -lrth

3、定时任务
Oracle RMAN 本地备份脚本一般是与定时任务(crontab)配合使用,选择合适的时间段进行备份很重要,建议尽量挑选业务空闲或者负载较低的时间段进行备份。假设凌晨是业务空闲时段,部署定时任务:
## 在 root 用户下执行
su - root
echo "00 00 * * 0 /home/oracle/scripts/dbbackup_lv0.sh" >> /var/spool/cron/oracle
echo "00 00 * * 1,2,3,4,5,6 /home/oracle/scripts/dbbackup_lv1.sh" >> /var/spool/cron/oracle

关于 crontab 命令可以参考:Linux crontab 命令
这里设置好定时任务执行脚本,基本脚本部署就完成了。
三、备份脚本验证
一般备份脚本部署完之后,如果条件允许的情况下,我们都需要进行一次备份测试,来保证脚本的可执行性以及正确性,下面就简单的来做一次备份测试,验证一下咱们的备份脚本是否可以正常运行?
1、备份数据库
首先需要执行 0 级备份脚本进行数据库的备份,最好放在后台执行:
sh /home/oracle/scripts/dbbackup_lv0.sh &

也可以连接到 RMAN 查看备份详细情况:
rman target /
list backup;

也可以连接到数据库查询视图:
set line222
set pagesize1000
col status for a10
col input_type for a20
col INPUT_BYTES_DISPLAY for a10
col OUTPUT_BYTES_DISPLAY for a10
col TIME_TAKEN_DISPLAY for a10
select input_type,
status,
to_char(start_time,
'yyyy-mm-dd hh24:mi:ss'),
to_char(end_time,
'yyyy-mm-dd hh24:mi:ss'),
input_bytes_display,
output_bytes_display,
time_taken_display,
COMPRESSION_RATIO
from v$rman_backup_job_details
order by 3 desc;

从上图也可以看出数据库备份的情况,分别有2次备份,一次是 18 号进行了全备,一次是 19 号进行了增量备份,备份状态,备份大小以及备份起始时间都可以看到。
接着再执行一次 1 级增量备份:
sh /home/oracle/scripts/dbbackup_lv1.sh &
由于没有什么数据更改,所以这次备份很快,再次查询一下备份情况:
1 级增量备份也成功,代表部署的备份脚本可以正常运行。
2、验证备份集
RMAN 也提供了备份集的验证功能,通过简单的几行命令即可验证备份是否可用:
restore validate database;
restore validate spfile;
restore validate controlfile;


如上图所示,备份集验证均成功!
四、拓展
Windows 和 Linux 的脚本语法不太一样,这边也分享一下 Windows 的备份脚本,仅供参考!同样的分为 0 级和 1 级备份,Windows 部署定时任务的方式也有所区别。
0、 开启归档
-- 检查归档模式是否打开
archive log list
-- 关闭数据库,重启至mount模式
shutdown immediate
startup mount
-- 开启归档模式
alter database archivelog;
-- 打开数据库
alter database open;
-- 检查归档模式是否打开
archive log list
1、备份脚本
0 级备份脚本:
可执行 bat 文件:
新建文件和log目录
## 数据备份目录
D:\backup
## 日志目录
D:\backupscript\log
## 备份脚本
D:\backupscript\backupscriptV0.bat
D:\backupscript\backupscriptV1.bat
## 备份sql
D:\backupscript\backupscriptV0.sql
D:\backupscript\backupscriptV1.sql
@echo off
set "filename=backup_lv0_task_log_%date:~0,4%%date:~5,2%%date:~8,2%.log"
(
echo.
echo ====================backup %date% %time% =========================
echo.
D:\app\Administrator\product\11.2.0\dbhome_1\BIN\rman target / cmdfile=D:\backupscript\backupscriptV0.sql
echo.
echo ===================== finish %date% %time% =========================
echo.
)>>d:\backupscript\log\%filename% 2>&1<nul
exit
调用备份 SQL 文件:
run{
allocate channel c1 device type disk;
allocate channel c2 device type disk;
crosscheck backup;
crosscheck archivelog all;
sql"alter system archive log current";
delete noprompt expired backup;
delete noprompt obsolete device type disk;
backup incremental level 0 database include current controlfile format 'D:\backup\backlv0_%d_%T_%t_%s_%p';
backup archivelog all DELETE INPUT format 'D:\backup\arch_%d_%T_%t_%s_%p';
release channel c1;
release channel c2;
}
1 级备份脚本:
可执行 bat 文件:
@echo off
set "filename=backup_lv1_task_log_%date:~0,4%%date:~5,2%%date:~8,2%.log"
(
echo.
echo ====================backup %date% %time% =========================
echo.
D:\app\Administrator\product\11.2.0\dbhome_1\BIN\rman target / cmdfile=D:\backupscript\backupscriptV1.sql
echo.
echo ===================== finish %date% %time% =========================
echo.
)>>D:\backupscript\log\%filename% 2>&1<nul
exit
调用备份 SQL 文件:
run{
allocate channel c1 device type disk;
allocate channel c2 device type disk;
crosscheck backup;
crosscheck archivelog all;
sql"alter system archive log current";
delete noprompt expired backup;
delete noprompt obsolete device type disk;
backup incremental level 1 database include current controlfile format 'D:\backup\backlv1_%d_%T_%t_%s_%p';
backup archivelog all DELETE INPUT format 'D:\backup\arch_%d_%T_%t_%s_%p';
release channel c1;
release channel c2;
}
2、配置定时任务
Windows 的定时任务叫做 任务计划程序,需要在这里配置:

配置比较简单,下面跟着我简单走一遍流程!
首先,在空白处右键新增一个任务:

填好任务名称:

新建一个触发器,配置为每周日 0 点开始执行:


选择配置好的备份脚本可执行文件:


最后,直接点击确定完成创建:

可以看到任务已经布置完成:

Windows 配置本地 RMAN 备份跟 Linux 主机还是有点差异,但是本质是一样的。
删除Archive log
# 新建文件
D:\backupscript\delArchive.bat
D:\backupscript\delArchive.sql
delArchive.bat 脚本内容
@echo off
set "filename=archive_task_log_%date:~0,4%%date:~5,2%%date:~8,2%.log"
(
echo.
echo ====================backup %date% %time% =========================
echo.
D:\app\Administrator\product\11.2.0\dbhome_1\BIN\rman target / cmdfile=delArchive.sql
echo.
echo ===================== finish %date% %time% =========================
echo.
)>>D:\backupscript\log\%filename% 2>&1<nul
exit
delArchive.sql 脚本内容
run{
crosscheck archivelog all;
delete noprompt archivelog until time 'sysdate-7';
delete noprompt force archivelog until time 'SYSDATE-10';
}
控制文件删除恢复验证
# 删除控制文件
rm -rf /data/SPECTRA/control01.ctl
rm -rf /data/SPECTRA/control02.ctl
# 关闭数据库,将报错
shutdown immediate
# 强制关闭
shutdown abort
# startup 启动时会报错ORA-00205: error in identifying control file, check alert log for more info
startup
# 显示not mount
rman target /
# 进行恢复,不过中间过程比较痛苦,要一个个实验过来
restore controlfile from '/backup/data_SPECTRA_20240115_1158330783_96_1';
shutdown immediate;
startup mount;
# 继续用rman
restore database;
recover database;
# rman下启动数据库
sql 'alter database open resetlogs';
数据文件删除验证
# 删除控制文件
rm -rf /oradata/SPECTRA/datafile/o1_mf_testdb1_lt9nc80o_.dbf
rm -rf /oradata/SPECTRA/datafile/o1_mf_testdb_lt9mlwpz_.dbf
# 关闭数据库
shutdown immediate
#将报错ORA-01116: error in opening database file 2
#ORA-01110: data file 2: '/oradata/SPECTRA/datafile/o1_mf_testdb1_lt9nc80o_.dbf'
#ORA-27041: unable to open file
#Linux-x86_64 Error: 2: No such file or directory
# 强制关闭
shutdown abort
# startup 启动时会报错ORA-00205: error in identifying control file, check alert log for more info
startup
# 显示 mount
rman target /
# 恢复被删除的数据文件
restore database;
# 继续用rman进行数据库的信息恢复
recover database;
删除重做日志redolog验证
rm -rf /oradata/SPECTRA/redo*.log
shutdown immediate
# 将报错
#ORA-03113: end-of-file on communication channel
#Process ID: 22134
#Session ID: 17 Serial number: 8523
startup
# 再启动到mount状态
startup mount
# 报错RESETLOGS option only valid after an incomplete database recovery
alter database open resetlogs;
recover database until time '2024-01-15 15:25:00';
RMAN-06054 报错处理办法
主要原因是control文件和数据文件不一致引起的
最简单的办法就是把现有的control 文件也删除,然后从备份文件中恢复
# 删除这个控制文件,或者移动到其他地方
mv xxx xxxxx
# 数据库启动到nomount状态
sqlplus / as sysdba
startup nomount
rman target /
# 进行恢复,不过中间过程比较痛苦,要一个个实验过来
restore controlfile from '/backup/data_SPECTRA_20240115_1158330783_96_1';
# 启动到mount状态
startup mount
# 恢复被删除的数据文件
restore database;
# 继续用rman进行数据库的信息恢复
recover database;
# 开启数据库
alter database open;
删除spfile文件恢复
# 删除spfile文件
rm -rf /u01/app/oracle/product/19.3.0/db/dbs/spfilespectra.ora
# 或者移动文件
mv /u01/app/oracle/product/19.3.0/db/dbs/spfilespectra.ora /u01/app/oracle/product/19.3.0/db/dbs/spfilespectra.ora.bak
# rman 登陆
rman target /
# 强制启动到nomount
startup nomount force;
# 恢复spfile文件
restore spfile from '/u01/app/oracle/product/19.3.0/db/dbs/c-2905618578-20240115-06'
模拟坏块
- 准备数据
-- 删除表空间和用户
drop user testDB cascade;
drop tablespace testDB including contents and datafiles;
-- 创建表空间
create tablespace testDB datafile '/oradata/SPECTRA/testDB.dbf' size 1G;
-- 创建用户
create user testDB identified by testDB default tablespace testDB;
grant dba to testDB;
-- 创建测试表
conn testDB/testDB
create table testDB as select * from dba_objects;
-- 创建表索引
create index idx_testDB_01 on testDB(object_id);
-- 查出包含行记录的数据块:
select distinct dbms_rowid.rowid_block_number(rowid) from testDB2.testDB2 order by 1;
select * from dba_extents where segment_name='TESTDB';
-- 在区间内,随机破坏 888、1030、1560 数据块的内容:
! dd if=/dev/zero of=/oradata/SPECTRA/testDB.dbf bs=8192 conv=notrunc seek=888 count=1
! dd if=/dev/zero of=/oradata/SPECTRA/testDB.dbf bs=8192 conv=notrunc seek=1030 count=1
! dd if=/dev/zero of=/oradata/SPECTRA/testDB.dbf bs=8192 conv=notrunc seek=1560 count=1
-- 清除buffer cache的内容
alter system flush buffer_cache;
-- 再次查询表 lucifer,此时查询已经报错,发现有坏块:
select * from testDB.testDB;
-- 遇到第一个坏块就会停止:
ERROR:
ORA-01578: ORACLE data block corrupted (file # 8, block # 888)
ORA-01110: data file 8: '/oradata/SPECTRA/testDB.dbf'
-
坏块检查
## 检查对应的数据文件 backup check logical validate datafile 8; -- 会列出坏块 List of Datafiles ================= File Status Marked Corrupt Empty Blocks Blocks Examined High SCN ---- ------ -------------- ------------ --------------- ---------- 8 FAILED 0 129334 131072 3685503 File Name: /oradata/SPECTRA/testDB.dbf Block Type Blocks Failing Blocks Processed ---------- -------------- ---------------- Data 0 1398 Index 0 166 Other 3 174 validate found one or more corrupt blocks See trace file /u01/app/oracle/diag/rdbms/spectra/spectra/trace/spectra_ora_22937.trc for details Finished backup at 22-JAN-24 -- 结合 V$DATABASE_BLOCK_CORRUPTION 视图查看,更加方便: select * from V$DATABASE_BLOCK_CORRUPTION; FILE# BLOCK# BLOCKS CORRUPTION_CHANGE# CORRUPTIO CON_ID ---------- ---------- ---------- ------------------ --------- ---------- 8 888 1 0 ALL ZERO 0 8 1030 1 0 ALL ZERO 0 8 1560 1 0 ALL ZERO 0 -- 通过报错信息快照可以查找对应的坏表,依次填写数据文件ID8和坏块ID 888: SELECT tablespace_name, segment_type, owner, segment_name FROM dba_extents WHERE file_id = &fileid and &blockid between block_id AND block_id + blocks - 1; TABLESPACE_NAME SEGMENT_TYPE OWNER ------------------------------ ------------------ -------------------------------------------------------------------------------------------------------------------------------- SEGMENT_NAME -------------------------------------------------------------------------------------------------------------------------------- TESTDB2 TABLE TESTDB2 TESTDB2 -
RMAN 恢复坏块
-- 使用备份来恢复坏块
blockrecover datafile 5 block 888,1030,1560;
Starting recover at 22-JAN-24
using channel ORA_DISK_1
channel ORA_DISK_1: restoring block(s)
channel ORA_DISK_1: specifying block(s) to restore from backup set
restoring blocks of datafile 00005
channel ORA_DISK_1: reading from backup piece /backup/backlv0_SPECTRA_20240122_1158940478_156_1
channel ORA_DISK_1: piece handle=/backup/backlv0_SPECTRA_20240122_1158940478_156_1 tag=TAG20240122T155438
channel ORA_DISK_1: restored block(s) from backup piece 1
channel ORA_DISK_1: block restore complete, elapsed time: 00:00:01
starting media recovery
media recovery complete, elapsed time: 00:00:03
Finished recover at 22-JAN-24
记录删除恢复验证
- 建立测试数据
## 创建用户
create user testDB identified by testDB;
grant dba to testDB;
## 用户登陆
sqlplus testDB/testDB@spectra
## 创建表空间
create tablespace testDB2 datafile ' /data/datafile/SPECTRA/testdb.dbf' size 10M autoextend off;
## 创建表
create table testDB(id number not null,name varchar2(20)) tablespace testDB;
## 插入数据
insert into testDB values(1,'test0');
insert into testDB values(2,'test1');
insert into testDB values(3,'test2');
commit;
## 查询数据
select * from testDB;
- rman备份数据
su - oracle
rman target /
## 执行全库备份
run {
allocate channel c1 device type disk;
allocate channel c2 device type disk;
crosscheck backup;
crosscheck archivelog all;
sql"alter system switch logfile";
delete noprompt expired backup;
delete noprompt obsolete device type disk;
backup database include current controlfile format '/backup/data_%d_%T_%t_%s_%p';
backup archivelog all DELETE INPUT format '/backup/arch_%d_%T_%t_%s_%p';
release channel c1;
release channel c2;
}
## 查询rman备份结果
set line222
set pagesize1000
col status for a10
col input_type for a20
col INPUT_BYTES_DISPLAY for a10
col OUTPUT_BYTES_DISPLAY for a10
col TIME_TAKEN_DISPLAY for a10
select input_type,
status,
to_char(start_time,
'yyyy-mm-dd hh24:mi:ss'),
to_char(end_time,
'yyyy-mm-dd hh24:mi:ss'),
input_bytes_display,
output_bytes_display,
time_taken_display,
COMPRESSION_RATIO
from v$rman_backup_job_details
order by 3 desc;
- 删除数据
## 用户登陆
sqlplus testDB/testDB@spectra
-- 删除前查询
select * from testDB;
-- 删除表 lucifer,最极端方式,确保无法通过回收站等方式恢复
drop table testDB purge;
-- 删除后再次查询报错
select * from testDB;
-
单表恢复(19c以后)
## oracle 用户下执行 新建辅助目录 mkdir -p /backup/tablereovery ## rman 下执行,在生产执行单表恢复,需要注意误删表的时间点,越精准数据丢失越少: rman target / RECOVER TABLE testDB.testDB UNTIL TIME "to_date('2024-01-15 14:33:00','yyyy-mm-dd hh24:mi:ss')" AUXILIARY DESTINATION '/backup/tablereovery/';