前言
本章目标:掌握本章核心知识点
前置要求:完成前序章节学习
预计时长:60 分钟
从业多年,经常遇到 DBA 嫌弃备份恢复演练麻烦,抱着能不做就不做的心态去对待,本文以一个 Veeam 备份恢复报错案例(绝对干货)的解决过程,正好可以探讨一下备份恢复演练是否应该定期做?有没有必要做?
今天做恢复演练,从 Veeam 备份恢复一套 RAC 数据库到单实例环境,本想着做过好多次了,应该是轻车熟路,没想到报错了:

这个报错没见过,也没啥头绪,网上也搜不到相关内容,只能分析日志了,本文记录整体分析过程以及解决方案。
问题分析
恢复日志一般存放于 VBR 的 C:\Users\Administrator\AppData\Local\Veeam\Backup\OracleExplorer\Logs 目录下:

打开日志,搜索关键词 Cleanup:


从错误日志可以看到参数文件被识别为 +DATA/orcl/spfileorcl.ora,但是目标端是个单实例数据库,不应该是 +DATA,查看恢复过程中生成的参数文件内容:

可以看到 PFILE 参数文件中竟然是 *.SPFILE='+DATA/orcl/spfileorcl.ora',为啥呢?
从恢复日志中的恢复命令可以发现:
1SET DBID=1599048745;
2RUN {
3ALLOCATE CHANNEL c0 DEVICE TYPE sbt PARMS 'SBT_LIBRARY=/opt/veeam/VeeamPluginforOracleRMAN/libOracleRMANPlugin.so';
4SEND "product=VEOR;jobId=4f4c136a-7c7b-42fa-9b49-9f9ddefe3fbd";
5RESTORE SPFILE TO PFILE '/var/tmp/be264f88364f49048380d9b81764ea21/49549b5e20804993aac22620a93e6f36.ORA' FROM 'c-1599048745-20251021-01.vab';
6}
这个参数文件是从源端的备份恢复来的,那源端是怎么备份的?
通过源端 Veeam 备份日志可以抓到 RUN 块:
1## 0 级备份脚本
2RUN {
3CONFIGURE CONTROLFILE AUTOBACKUP ON;
4CONFIGURE COMPRESSION ALGORITHM 'BASIC';
5ALLOCATE CHANNEL VeeamAgentChannel1 DEVICE TYPE SBT_TAPE PARMS 'SBT_LIBRARY=/opt/veeam/VeeamPluginforOracleRMAN/libOracleRMANPlugin.so' FORMAT 'f20cb2d5-2665-43a3-8864-3fc0e8215d07/RMAN_%I_%d_%T_%U.vab';
6ALLOCATE CHANNEL VeeamAgentChannel2 DEVICE TYPE SBT_TAPE PARMS 'SBT_LIBRARY=/opt/veeam/VeeamPluginforOracleRMAN/libOracleRMANPlugin.so' FORMAT 'f20cb2d5-2665-43a3-8864-3fc0e8215d07/RMAN_%I_%d_%T_%U.vab';
7ALLOCATE CHANNEL VeeamAgentChannel3 DEVICE TYPE SBT_TAPE PARMS 'SBT_LIBRARY=/opt/veeam/VeeamPluginforOracleRMAN/libOracleRMANPlugin.so' FORMAT 'f20cb2d5-2665-43a3-8864-3fc0e8215d07/RMAN_%I_%d_%T_%U.vab';
8SEND 'setPolicyJobId=b3c565cc-1cb5-4e17-9516-54c8c5038663';
9SEND 'bObjectId={68b0796d-cfb1-4fe0-b8dd-27a33093755e}';
10SEND 'backupSessionParentJobId={b3c565cc-1cb5-4e17-9516-54c8c5038663}';
11SEND 'dbCredentials-:';
12BACKUP INCREMENTAL LEVEL 0 AS COMPRESSED BACKUPSET DATABASE PLUS ARCHIVELOG NOT BACKED UP 1 TIMES;
13SEND 'makeBackupConsistent';
14}
15
16## 1 级备份脚本
17RUN {
18CONFIGURE CONTROLFILE AUTOBACKUP ON;
19ALLOCATE CHANNEL VeeamAgentChannel1 DEVICE TYPE SBT_TAPE PARMS 'SBT_LIBRARY=/opt/veeam/VeeamPluginforOracleRMAN/libOracleRMANPlugin.so' FORMAT 'f20cb2d5-2665-43a3-8864-3fc0e8215d07/RMAN_%I_%d_%T_%U.vab';
20ALLOCATE CHANNEL VeeamAgentChannel2 DEVICE TYPE SBT_TAPE PARMS 'SBT_LIBRARY=/opt/veeam/VeeamPluginforOracleRMAN/libOracleRMANPlugin.so' FORMAT 'f20cb2d5-2665-43a3-8864-3fc0e8215d07/RMAN_%I_%d_%T_%U.vab';
21ALLOCATE CHANNEL VeeamAgentChannel3 DEVICE TYPE SBT_TAPE PARMS 'SBT_LIBRARY=/opt/veeam/VeeamPluginforOracleRMAN/libOracleRMANPlugin.so' FORMAT 'f20cb2d5-2665-43a3-8864-3fc0e8215d07/RMAN_%I_%d_%T_%U.vab';
22SEND 'setPolicyJobId=b3c565cc-1cb5-4e17-9516-54c8c5038663';
23SEND 'bObjectId={68b0796d-cfb1-4fe0-b8dd-27a33093755e}';
24SEND 'backupSessionParentJobId={b3c565cc-1cb5-4e17-9516-54c8c5038663}';
25SEND 'dbCredentials-:';
26BACKUP INCREMENTAL LEVEL 1 DATABASE PLUS ARCHIVELOG NOT BACKED UP 1 TIMES;
27SEND 'makeBackupConsistent';
28}
其实也是调用 RMAN 进行备份,手动触发一下备份参数文件,看看备份出来的参数文件内容:
1[oracle@orcl1:/dbbak/orcl]$ strings /u01/app/oracle/product/11.2.0/db_1/dbs/be46pqp6_1_1
2}|{z
3O_ORCL
4lHna
5TAG20251021T150718
6ORCL
7*.SPFILE='+DATA/orcl/spfileorcl.ora'
8/u01/app/oracle/product/11.2.0/db_1/dbs/spfileorcl1.ora
这个明显是不对,看一下 $ORACLE_HOME/dbs 目录下的内容:
1[oracle@orcl1:/u01/app/oracle/product/11.2.0/db_1/dbs]$ ls
2be46pqp6_1_1 hc_orcl1.dat init.ora initorcl1.ora orapworcl1 orapworcl2 snapcf_orcl1.f spfileorcl1.ora tmp.ora
怎么 initorcl1.ora 和 spfileorcl1.ora 同时存在?这种情况下,spfileorcl1.ora 的优先级最高,所以数据库启动默认读取 spfileorcl1.ora,而 RMAN 备份是根据 spfile 参数的值指向进行备份。
查看 spfile 参数:
1SQL> show parameter pfile
2
3NAME TYPE VALUE
4------------------------------------ ----------- ------------------------------
5spfile string /u01/app/oracle/product/11.2.0
6 /db_1/dbs/spfileorcl1.ora
查看 spfileorcl1.ora 的内容:
1[oracle@orcl1:/u01/app/oracle/product/11.2.0/db_1/dbs]$ strings spfileorcl1.ora
2*.SPFILE='+DATA/orcl/spfileorcl.ora'
这个文件的内容明显不对,又多套了一层,这样备份出来的参数文件就是无效的,因为根本没有记录实际的参数文件内容,所以 Veeam 备份恢复出来自然就是报错了。
我们可以手动执行验证一下:
1SQL> create pfile='/home/oracle/pfile.ora' from spfile;
2
3File created.
4
5[oracle@sqmespmdb01:/home/oracle]$ strings pfile.ora
6*.SPFILE='+DATA/orcl/spfileorcl.ora'
这种情况下,使用这个 pfile.ora 是无法打开数据库实例的,也就导致了我们的恢复失败:

问题分析到这,原因已经找到了,接下来就是如何处理这个问题了。
问题解决
目前需要解决的问题是,如何能获取到参数文件的实际内容?我的做法比较简单,直接从 asm 磁盘里拷贝出来:
1ASMCMD [+] > cp +DATA/orcl/spfileorcl.ora /home/grid
2copying +DATA/orcl/spfileorcl.ora -> /home/grid/spfileorcl.ora
然后查看编辑一下内容,适配一下单机环境:
1*.audit_file_dest='/u01/app/oracle/admin/orcl/adump'
2*.audit_trail='db'
3*.compatible='11.2.0.4.0'
4*.control_files='/data/orcl/CONTROLFILE/control01.ctl','/data/orcl/CONTROLFILE/control02.ctl'
5*.db_block_size=8192
6*.db_create_file_dest='/data'
7*.db_domain=''
8*.db_name='orcl'
9*.deferred_segment_creation=FALSE
10*.diagnostic_dest='/u01/app/oracle'
11*.dispatchers='(PROTOCOL=TCP) (SERVICE=orclXDB)'
12*.log_archive_dest_1='location=/data/archivelog'
13*.log_archive_format='%t_%s_%r.dbf'
14*.open_cursors=300
15*.pga_aggregate_target=4G
16*.processes=1000
17*.remote_login_passwordfile='exclusive'
18*.sessions=1105
19*.sga_target=8G
20*.undo_tablespace='UNDOTBS1'
在恢复主机上创建 pfile 并启动数据库实例到 nomount 状态:
1SQL> create spfile from pfile;
2
3File created.
4
5SQL> startup nomount
6ORACLE instance started.
7
8Total System Global Area 8551575552 bytes
9Fixed Size 2270360 bytes
10Variable Size 1744833384 bytes
11Database Buffers 6794772480 bytes
12Redo Buffers 9699328 bytes
但是,很可惜,Veeam 恢复时不能提前把实例开启到 nomount 状态:

看来不能通过 Explorer 来操作恢复了,得用 RMAN 命令行调用恢复了。
Veeam RMAN Plugin 恢复
在恢复目标机上,查询 sbt_library 参数和 srcbackup 参数:
1[oracle@test:/home/oracle]$ OracleRMANConfigTool --get-backup-for-restore
2Select backup to be used:
31. xxxxxx Oracle backup (xxxxxx)
4Enter backup number:1
5To perform restore operations, use ID of the selected backup from the example below as srcBackup parameter value in SEND command:
6ALLOCATE CHANNEL VeeamAgentChannel1 DEVICE TYPE SBT_TAPE
7PARMS 'SBT_LIBRARY=/opt/veeam/VeeamPluginforOracleRMAN/libOracleRMANPlugin.so';
8SEND 'srcBackup=52e80707-e5d2-4f0c-9643-b408f3c62ad9';

在源端通过 RMAN 获取最近备份的控制文件名称:
1BS Key Type LV Size Device Type Elapsed Time Completion Time
2------- ---- -- ---------- ----------- ------------ ---------------
324015 Full 32.00M SBT_TAPE 00:00:04 21-OCT-25
4 BP Key: 24015 Status: AVAILABLE Compressed: NO Tag: TAG20251021T135357
5 Handle: c-1599048745-20251021-02 Media: {650a4d3a-a045-4a9d-92fa-32805e5aaf42}
6 Control File Included: Ckp SCN: 79127664575 Ckp time: 21-OCT-25
在目标端进行恢复控制文件(使用上面获取到的参数):
1## dbid 连接源端 rman 就可以看到 connected to target database: ORCL (DBID=1599048745)
2RMAN> RUN {
3set dbid=1599048745;
4ALLOCATE CHANNEL VeeamAgentChannel1 DEVICE TYPE SBT_TAPE
5PARMS 'SBT_LIBRARY=/opt/veeam/VeeamPluginforOracleRMAN/libOracleRMANPlugin.so';
6SEND 'srcBackup=52e80707-e5d2-4f0c-9643-b408f3c62ad9';
7SET CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE 'SBT_TAPE' TO '%F_RMAN_AUTOBACKUP.vab';
8RESTORE controlfile FROM 'c-1599048745-20251021-02';
9}

打开数据库到 mount 状态:
1RMAN> alter database mount;
2
3database mounted
写一个脚本,后台执行 RMAN 恢复:
1[oracle@test:/home/oracle]$ cat<<-\RMAN>/home/oracle/veeam_restore.sh
2#!/bin/bash
3source ~/.bash_profile
4DAY_TAG=`date +"%Y-%m-%d"`
5rman target / nocatalog msglog /home/oracle/restore_$DAY_TAG.log<<EOF
6RUN {
7ALLOCATE CHANNEL VeeamAgentChannel1 DEVICE TYPE SBT_TAPE
8PARMS 'SBT_LIBRARY=/opt/veeam/VeeamPluginforOracleRMAN/libOracleRMANPlugin.so';
9ALLOCATE CHANNEL VeeamAgentChannel2 DEVICE TYPE SBT_TAPE
10PARMS 'SBT_LIBRARY=/opt/veeam/VeeamPluginforOracleRMAN/libOracleRMANPlugin.so';
11ALLOCATE CHANNEL VeeamAgentChannel3 DEVICE TYPE SBT_TAPE
12PARMS 'SBT_LIBRARY=/opt/veeam/VeeamPluginforOracleRMAN/libOracleRMANPlugin.so';
13SEND 'srcBackup=52e80707-e5d2-4f0c-9643-b408f3c62ad9';
14SET NEWNAME FOR DATABASE TO '/data/orcl/%b';
15RESTORE DATABASE;
16SWITCH DATAFILE ALL;
17SWITCH TEMPFILE ALL;
18RECOVER DATABASE;
19}
20EOF
21RMAN
22
23[oracle@test:/home/oracle]$ chmod +x veeam_restore.sh
24## 执行恢复
25[oracle@test:/home/oracle]$ sh /home/oracle/veeam_restore.sh &

可以看到开始正常恢复了:

等待恢复完成后,打开数据库即可:
1SQL> alter database open resetlogs;
本次备份恢复成功完成!但是,问题依然没有解决,需要修复参数文件的问题。
后续处理
因为数据库使用错误的参数文件进行启动,所以无法在线去更换 spfile 路径,需要关闭数据库进行替换调整。
等到有停机时间时,关闭数据库:
1[oracle@orcl1:/home/oracle]$ srvctl stop db -d orcl
检查集群已经配置 spfile 参数:
1[oracle@orcl1:/home/oracle]$ srvctl config db -d orcl | grep Spfile
2Spfile: +DATA/orcl/spfileorcl.ora
确保集群已配置 spfile 参数后,即可移走或者删掉所有节点 dbs 目录下的 spfile[SID].ora 和 init[SID].ora 文件(如果集群未配置 Spfile 参数,则需要保留 init[SID].ora 文件):
1## 所有节点均需要删除
2rm $ORACLE_HOME/dbs/spfileorcl1.ora
3rm $ORACLE_HOME/dbs/initorcl1.ora
然后重新启动数据库:
1[oracle@orcl1:/home/oracle]$ srvctl start db -d orcl
再次使用 Veeam 发起一次完整备份,确保备份成功即可。
写在最后
通过本文再次体现了恢复演练的重要性,很多时候光看备份是否成功是无法发现一些问题的,只有切身实地的去恢复验证了,才能发现这些问题并且解决它,所以一定要定期去做恢复演练。
记得之前听说有一个国外 DBA 干了 20 多年从未做过恢复演练,结果真到了要恢复的时候,没有恢复出来数据,面临重大赔偿,直接跳楼(是否真实无从考证)。
❗️❗️❗️切记:DBA 的首要工作是备份!!! 备份永远都是你的最后一根救命稻草。