接到需求的时候我其实是有一点意外的:生产环境明明是两节点的 11g R2 RAC,灾备却只肯配一台单实例服务器。后来想想也合理,灾备端平时不承载业务,没必要为两个节点买两套授权、养两套机器,单实例备库把数据续上、关键时候能接管就够了。于是我就按“RAC 主库到单实例 Data Guard”这个拓扑开始搭,采用 RMAN 备份恢复的方式。整套流程走下来,我最大的感受是:单机对单机的 DG 教程满网都是,一换成 RAC 主库,情况立刻不一样,ASM 路径、多线程归档、PFILE 里的实例级参数,每一样都可能让备库起不来。这篇文章就把我实测过的完整流程和踩坑点写出来,给正准备做同样事情的同行一个参考。
这套方案里主库还是正常对外服务的 RAC,备库只是一个普通的单实例物理备库。搭建手段用的是最经典的思路:在主库用 RMAN 做全量备份,同时准备好 standby 控制文件,把备份和参数文件一起送往备机,恢复成备库,再配置 Data Guard 的日志传输和应用。没有用到DUPLICATE DATABASE FOR STANDBY的自动化方式,原因很简单:很多生产环境里备份集本来就有一套异地归档机制,顺着备份走更符合现有运维习惯,而且手动方式对路径和参数的掌控更细,出了问题也好排查。
1. RAC 到单实例 DG:业务场景与前置条件核查
1.1 这套组合通常出现在哪些场景
我接触到的需求主要有三类。第一类是容灾降配,主库因为性能或在线交易需要跑 RAC,备库只做灾备和恢复演练,单实例完全够用,这是最常见的一种。第二类是迁移过渡,准备从 RAC 迁移到单实例,或者从老机房搬到新机房,先在备库把数据同步起来,切换后新主库直接就是单实例,省去一次迁移。第三类是读写分离和报表查询,把备库打开成只读模式分担查询压力,单实例备库成本低,运维也简单。
这些场景的共同点是:备库的定位不是“承接同等负载”,而是“保证数据完整、可切换、可读”。理解了这一点,你就能接受备库做很多简化,比如不用 ASM 也可以,不用配 SCAN 监听也可以,只要路径转换对、日志能持续应用,就没有问题。
1.2 硬性条件:版本、补丁、字符集、时区
开始搭之前,我建议先做一轮环境核查,不要上来就拷贝备份。Data Guard 对主备两端的“同源性”要求很严格,四项必须确认:
| 核查项 | 命令或方法 | 要求 |
|---|---|---|
| 数据库版本 | SELECT * FROM V$VERSION; | 备库不低于主库,11g R2 建议同版本 |
| 补丁级别 | 主备两端跑opatch lsinventory | 尽量一致,最少备库不落后于主库 |
| 字符集 | SELECT VALUE FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER IN ('NLS_CHARACTERSET','NLS_NCHAR_CHARACTERSET'); | 必须完全一致 |
| 时区 | SELECT DBTIMEZONE FROM DUAL; | 必须一致,否则时间函数结果会错乱 |
字符集这块尤其容易忽略。Oracle 字符集种类不少,常见的有 AL32UTF8、ZHS16GBK、WE8MSWIN1252 等,如果主库是 ZHS16GBK,备库建库时用了 AL32UTF8,DG 配置后可能一开始能同步,数据一复杂就报错,甚至ORA-12721。备库字符集在建库时选对,后面会省掉一堆麻烦。
除了字符集,我还要提醒一句:Data Guard 只在 Enterprise Edition 下可用。有的环境主库是 RAC,但可能拿到的授权并不是 EE,这会影响后续。开工前先用V$VERSION看清楚,别等配了半天发现功能根本不可用。
1.3 RAC 特有的归档前提
单机 DG 只需要确保数据库处于归档模式,但 RAC 主库多了一个概念:redo 线程。两节点 RAC 里,实例 1 写 thread 1,实例 2 写 thread 2,Data Guard 必须同时接收和应用两个线程的日志,缺任何一个都会产生 gap。
所以搭建前要确认三点:
- 数据库处于
ARCHIVELOG模式,执行ARCHIVE LOG LIST能看到确认信息。 - 开启了
FORCE LOGGING,执行SELECT FORCE_LOGGING FROM V$DATABASE;应为 YES。如果主库存在 direct path insert 或 nologging 操作,没有强制日志的话备库会缺数据块。 - 两个线程的归档都连续。可以通过
SELECT THREAD#, MAX(SEQUENCE#) FROM V$ARCHIVED_LOG GROUP BY THREAD#;先看一眼现状。
还有一个容易忽略的点:主备库之间的网络服务名解析。备库通过 Oracle Net 访问主库,主库也要能访问备库。RAC 环境里如果配了 SCAN,tnsnames 里直接指向 SCAN 名最省事;没有 SCAN 就写两个节点的 VIP 地址轮询。
2. 主库 RMAN 备份的完整顺序:全库 + 多线程归档 + Standby 控制文件
2.1 为什么用 BACKUP DATABASE PLUS ARCHIVELOG
搭建备库时,RMAN 备份的目标不只是“留个全量备份”,而是要让备库恢复到和主库尽量接近的 SCN。BACKUP DATABASE PLUS ARCHIVELOG会在备份数据文件前自动做一次日志切换,把当前在线日志归档,然后再备份控制文件和数据文件。这样备份出来的数据文件本身是一致的,而且归档日志也包含在备份集里,后面恢复备库时不需要额外去主库找历史日志。
RAC 环境有一点可以放心:RMAN 连接任意一个实例执行备份,都能看到整个集群的 redo 线程信息,控制文件里记录了两个 thread 的归档序列,不需要分别连两个实例备份。
2.2 备份命令与顺序
我实际操作时的顺序是固定的,避免乱:
# 主库任意节点,以 sysdba 登录 rman target / RMAN> CONFIGURE CONTROLFILE AUTOBACKUP ON; RMAN> BACKUP DATABASE PLUS ARCHIVELOG FORMAT '/backup/orcl/full_%U.bkp';CONFIGURE CONTROLFILE AUTOBACKUP ON这一步建议加上,备份控制文件是后续生成 standby 控制文件之外的第二道保险。如果后面恢复时备用控制文件损坏,至少还能用 autobackup 的控制文件兜底。
备份结束后,马上在主库生成 standby 控制文件:
SQL> ALTER DATABASE CREATE STANDBY CONTROLFILE AS '/backup/orcl/stby_ctl.ctl';这里有个时间窗口问题:数据文件备份的 SCN 是“备份那一刻”,standby 控制文件记录的 SCN 是“创建控制文件那一刻”。两者之间的归档日志是备库补齐 SCN 差异的关键,所以创建完 standby 控制文件后,再强制切换一次日志:
SQL> ALTER SYSTEM ARCHIVE LOG CURRENT;然后把主库归档目录里最新的 thread 1 和 thread 2 归档日志一并收集。最简单的办法是直接查看:
SELECT THREAD#, SEQUENCE#, NAME FROM V$ARCHIVED_LOG WHERE SEQUENCE# > (SELECT MAX(SEQUENCE#) - 10 FROM V$ARCHIVED_LOG GROUP BY THREAD#) ORDER BY THREAD#, SEQUENCE#;实际操作时判断标准是:从数据文件备份开始时刻到 standby 控制文件创建时刻,这段时间内产生的归档都带上。如果怕漏,干脆把最近几个小时的归档日志全部拷贝到备机,反正多拷贝不影响恢复。
2.3 备份集和归档日志怎么传给备机
我的习惯是把备份文件、standby 控制文件、导出的 PFILE 放到同一个目录下,整体用 scp 或 rsync 传到备机:
scp -r /backup/orcl oracle@standby:/backup/如果网络带宽有限,可以在 RMAN 备份时就开启压缩:
RMAN> BACKUP AS COMPRESSED BACKUPSET DATABASE PLUS ARCHIVELOG FORMAT '/backup/orcl/full_%U.bkp';压缩备份会稍微增加备份时间,但传输和落盘都能省不少空间,对于异地机房拉备份很实用。
2.4 顺手用 ASMCMD 确认路径
RAC 环境经常用 ASM 存放数据文件,备库如果不用 ASM,路径转换就得先弄清楚主库的文件结构。在主库上执行asmcmd进入 ASM 命令行,然后:
asmcmd> ls +DATA/orcl/datafile这样能看到所有数据文件在 ASM 磁盘组里的完整路径。后面写db_file_name_convert的时候,这些路径就是转换来源。很多人在备库恢复时报ORA-15001或文件找不到,多半就是 ASM 路径没写对。
3. 备库 PFILE 改造:从 RAC 参数集“减配”到单实例
3.1 从 SPFILE 导出 PFILE
RAC 的参数文件一般是 SPFILE,里面既有全局参数,也有每个实例的个性化参数。第一步先导出成 PFILE,方便编辑:
SQL> CREATE PFILE='/backup/orcl/initORCL_rac.ora' FROM SPFILE;拿到这个文件后,不要直接拿去做备库 PFILE,它包含很多 RAC 专属参数,直接用在单实例上会报错或者行为异常。
3.2 必须修改的参数清单
以一套两节点 RAC 的 PFILE 为例,原文件里会有类似这样的内容:
orcl1.instance_number=1 orcl1.thread=1 orcl2.instance_number=2 orcl2.thread=2 *.cluster_database=TRUE *.db_name='orcl' *.db_unique_name='orcl' *.control_files='+DATA/orcl/controlfile/current.260.1034671895' *.db_create_file_dest='+DATA' *.db_create_online_log_dest_1='+DATA' *.db_create_online_log_dest_2='+FRA' *.log_archive_dest_1='location=USE_DB_RECOVERY_FILE_DEST valid_for=(all_logfiles,all_roles) db_unique_name=orcl' *.log_archive_dest_2='service=orclstby lgwr async valid_for=(online_logfiles,primary_role) db_unique_name=orclstby' *.compatible='11.2.0.4.0'改造为单实例备库 PFILE 时,重点是“删”和“改”:
- 删除两行实例级参数,比如
orcl1.instance_number、orcl2.thread这类带库名前缀的行,单实例不需要。 - 把
*.cluster_database=TRUE改成*.cluster_database=FALSE。 - 设置
*.db_unique_name='orclstby',和主库区分开。 - 控制文件路径改成备库本地路径,比如
/u01/app/oracle/oradata/orcl/control01.ctl。 - 如果备库不用 ASM,设置
db_file_name_convert和log_file_name_convert,把+DATA/orcl/datafile这类路径映射到文件系统目录。 - 原 PFILE 中的
db_create_file_dest、db_create_online_log_dest_1/2建议删掉,不然备库建 redo 日志时可能又自动写到 ASM 路径去。
我整理后的备库 PFILE 关键部分如下:
*.cluster_database=FALSE *.db_name='orcl' *.db_unique_name='orclstby' *.control_files='/u01/app/oracle/oradata/orcl/control01.ctl','/u01/app/oracle/oradata/orcl/control02.ctl' *.db_file_name_convert='+DATA/orcl/datafile','/u01/app/oracle/oradata/orcl' *.log_file_name_convert='+DATA/orcl/onlinelog','/u01/app/oracle/oradata/orcl','+FRA/orcl/onlinelog','/u01/app/oracle/oradata/orcl' *.db_recovery_file_dest='/u01/app/oracle/fast_recovery_area' *.db_recovery_file_dest_size=60G *.log_archive_dest_1='location=USE_DB_RECOVERY_FILE_DEST valid_for=(all_logfiles,all_roles) db_unique_name=orclstby' *.log_archive_dest_2='service=orcl lgwr async valid_for=(online_logfiles,primary_role) db_unique_name=orcl' *.log_archive_config='dg_config=(orcl,orclstby)' *.fal_server='orcl' *.fal_client='orclstby' *.standby_file_management='auto' *.compatible='11.2.0.4.0' *.processes=1000 *.memory_target=8G *.undo_tablespace='UNDOTBS1'注意db_file_name_convert的写法:Oracle 解析时是按照参数里成对出现的字符串进行替换,顺序不能反。它只替换匹配到的第一部分,比如+DATA/orcl/datafile下的 OMF 文件名都会被转到/u01/app/oracle/oradata/orcl下。
3.3 备库实例和监听的基础配置
备库的 ORACLE_SID 要和 PFILE 里db_name保持一致吗?不需要。db_name是数据库名,两个库必须相同;ORACLE_SID是实例名,备库可以随便设,比如orclstby。启动时用 PFILE 指向即可。
监听配置建议单独给备库起一个静态注册的名字,保证主库日志传输和 dgmgrl 都能连上。tnsnames.ora里至少要有两条记录:
orcl:指向主库 SCAN 或 VIP。orclstby:指向备库主机。
11g 里如果监听注册有问题,常常报ORA-28547: connection to server failed, probable Oracle Net admin error。这个问题大多数时候不是 DG 本身的问题,而是 tnsnames 或 listener.ora 写错了,先tnsping两个服务名,确认通不通再继续。
4. 备库还原与恢复:RESTORE、RECOVER 和 SCN 衔接问题
4.1 启动到 NOMOUNT 并放置控制文件
备库 PFILE 准备好之后,先建目录,再启动到 NOMOUNT:
mkdir -p /u01/app/oracle/oradata/orcl export ORACLE_SID=orclstby sqlplus / as sysdba SQL> STARTUP NOMOUNT PFILE='/u01/app/oracle/product/11.2.0/dbhome_1/dbs/initorclstby.ora';然后拷贝 standby 控制文件到 PFILE 里指定的位置:
cp /backup/orcl/stby_ctl.ctl /u01/app/oracle/oradata/orcl/control01.ctl cp /backup/orcl/stby_ctl.ctl /u01/app/oracle/oradata/orcl/control02.ctl再次进入 SQL*Plus 执行:
SQL> ALTER DATABASE MOUNT;如果 PFILE 里的控制文件路径没有问题,这一步会顺利进入 MOUNT。这个阶段不用急着打开数据库,备库在没有完成 recovery 之前,本来也不应该直接 open。
4.2 RMAN 恢复:为什么 RECOVER 要特别关注 SCN
现在到了整篇文章最核心的部分:用 RMAN 把备份还原成数据文件。命令本身不复杂:
rman target / RMAN> SET ARCHIVELOG DESTINATION TO '/backup/orcl/arch'; RMAN> RESTORE DATABASE; RMAN> RECOVER DATABASE;但要理解背后的 SCN 衔接逻辑。数据文件备份的 SCN 停在备份完成那一刻,而 standby 控制文件的 SCN 在你执行CREATE STANDBY CONTROLFILE那一刻,两者之间存在时间差。RMAN 执行RECOVER DATABASE时,会利用备份集里自带的归档日志,把数据文件从备份 SCN 向前推进,尽量追平控制文件的 SCN。
如果这段时间内产生的归档日志没有全部出现在备份集或备机目录里,恢复时会报类似ORA-00283或ORA-19870的错误,告诉你缺少某个日志文件。解决办法就是把主库对应的归档日志拷到备机,放到log_archive_dest_1指定的目录里,然后重新执行:
RMAN> RECOVER DATABASE;所以我在第 2 章强调要收集“备份之后、创建 standby 控制文件之后”的归档日志,就是为了让这个恢复过程一次通过,不至于来回补日志。
4.3 恢复完成后检查数据文件状态
恢复完成后,用 SQL 确认备库文件状态:
SELECT FILE#, STATUS, NAME FROM V$DATAFILE; SELECT THREAD#, SEQUENCE#, APPLIED FROM V$ARCHIVED_LOG;如果数据文件状态正常,且能看到最近几个序列的归档已经标记为YES或IN-MEMORY,说明备库的基础已经打好了。
有一个常见误解要澄清:备库在完成 DG 配置之前,不需要非得“追到和主库完全一致”。真正开始日志传输后,主库会把缺失的归档继续送过来,备库会自动应用。恢复阶段只要保证备用控制文件和数据文件之间的一致性成立,剩下的可以由 DG 接管。
5. Data Guard 参数落位与日志应用启动
5.1 主备库 DG 参数到底在控制什么
参数看起来很绕,但拆开看就三类:一是告诉数据库“我是一个 DG 配置中的哪个角色”,二是确认日志往哪里发,三是缺日志时从哪里要。
主库端,在 RAC 的 SPFILE 中需要保证以下参数生效:
*.log_archive_config='dg_config=(orcl,orclstby)' *.log_archive_dest_1='location=USE_DB_RECOVERY_FILE_DEST valid_for=(all_logfiles,all_roles) db_unique_name=orcl' *.log_archive_dest_2='service=orclstby lgwr async valid_for=(online_logfiles,primary_role) db_unique_name=orclstby'log_archive_config里的dg_config必须列出所有库的db_unique_name,有多个备库都要列全。log_archive_dest_1是本地归档,USE_DB_RECOVERY_FILE_DEST表示写到 FRA。log_archive_dest_2是发送到备库,service=orclstby指定备库网络服务名,db_unique_name=orclstby是备库在 DG 配置里的唯一名字。
备库端对称配置,只是把 service 和 db_unique_name 换成主库:
*.log_archive_dest_1='location=USE_DB_RECOVERY_FILE_DEST valid_for=(all_logfiles,all_roles) db_unique_name=orclstby' *.log_archive_dest_2='service=orcl lgwr async valid_for=(online_logfiles,primary_role) db_unique_name=orcl'valid_for这个参数很多人忽略,但它决定了角色切换后的归档方向。大多数生产环境直接写成valid_for=(online_logfiles,primary_role),意思是“只有当前库处于 primary 角色时才往对端发日志”。这样切换后,新主库会自动接管发送,新备库只负责接收,不需要人再去改配置。如果整行写成了all_logfiles,all_roles,切换后可能两边互相发日志,造成混乱。
5.2 LGWR 和 ARCH 传输怎么选
11g R2 里日志传输支持两种方式:ARCH 进程在日志切换时传输,机制简单,但 RPO 取决于切换频率;LGWR 进程在 redo 写入时就实时传输,RPO 更小。
| 保护级别 | 推荐参数写法 | 特点 |
|---|---|---|
| 最大性能(默认) | service=orclstby lgwr async | 异步传输,对主库影响小,RPO 秒级 |
| 最大可用 | service=orclstby lgwr sync affirm | 同步确认,网络故障自动降级 |
| 最大保护 | service=orclstby lgwr sync affirm,并设置DB_PROTECTION_MODE | RPO=0,但要求备库必须可达 |
我个人的建议是:除非业务明确要求零丢失,否则默认用lgwr async。sync模式下主库每个提交都要等备库确认,对 RAC 公网链路质量要求很高,网络稍微抖动主库事务就会受影响。不要为了“看起来保险”而牺牲生产稳定性。
5.3 创建 Standby Redo Log
备库必须有自己的 standby redo log,用于接收主库传过来的 redo。组数可以按“主库单实例 redo group 数 + 1”来算,RAC 两节点通常意味着主库每个实例各有几组 redo log,备库建议至少 4 组。文件大小要大于或等于主库 redo log 的最大尺寸,不然日志传过来写不下。
ALTER DATABASE ADD STANDBY LOGFILE GROUP 10 ('/u01/app/oracle/oradata/orcl/srl01.log') SIZE 200M; ALTER DATABASE ADD STANDBY LOGFILE GROUP 11 ('/u01/app/oracle/oradata/orcl/srl02.log') SIZE 200M; ALTER DATABASE ADD STANDBY LOGFILE GROUP 12 ('/u01/app/oracle/oradata/orcl/srl03.log') SIZE 200M; ALTER DATABASE ADD STANDBY LOGFILE GROUP 13 ('/u01/app/oracle/oradata/orcl/srl04.log') SIZE 200M;创建完可以用SELECT GROUP#, STATUS, TYPE FROM V$STANDBY_LOG;检查。
5.4 启动日志应用
基础配置完成后,启动备库日志应用:
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;这条命令会在备库后台启动 MRP 进程,持续应用主库传来的归档。如果想打开只读模式做查询,按这个顺序来:
SQL> ALTER DATABASE OPEN; SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT FROM SESSION;USING CURRENT LOGFILE的作用是让备库实时应用主库当前在线日志,而不必等日志切换成归档,RPO 更小。
6. dgmgrl 注册验证与 RAC 特有的同步检查
6.1 用 dgmgrl 把配置管起来
DG 配置如果只用 SQL*Plus 手管也能跑,但切换、监控都不方便。11g 里建议用 Data Guard Broker,通过 dgmgrl 管理。注册命令如下:
dgmgrl sys/****@orcl DGMGRL> CREATE CONFIGURATION 'orcl_dg' AS PRIMARY DATABASE IS 'orcl' CONNECT IDENTIFIER IS orcl; DGMGRL> ADD DATABASE 'orclstby' AS CONNECT IDENTIFIER IS orclstby MAINTAINED AS PHYSICAL; DGMGRL> ENABLE CONFIGURATION; DGMGRL> SHOW CONFIGURATION;SHOW CONFIGURATION的输出里重点看Configuration Status,正常应该是SUCCESS。如果显示WARNING,多半是日志传输延迟或某些参数不一致,可以用:
DGMGRL> VALIDATE DATABASE orcl; DGMGRL> VALIDATE DATABASE orclstby;查看具体哪一项不合格。最常见的输出差异集中在Transport On和Lag Time两栏。
6.2 RAC 主库的同步指标怎么看
RAC 主库因为有两个线程,单独看一个线程的序列号不能代表整体状态。我习惯用这几条 SQL 检查:
SELECT THREAD#, MAX(SEQUENCE#) FROM V$ARCHIVED_LOG GROUP BY THREAD#; SELECT THREAD#, MAX(SEQUENCE#) FROM V$ARCHIVED_LOG WHERE APPLIED='YES' GROUP BY THREAD#;如果两个线程的 max sequence 相差很多,或者已应用的最大序列号长期落后,就要检查是哪个实例的日志传输出了问题。还可以看:
SELECT DEST_NAME, STATUS, ERROR FROM V$ARCHIVE_DEST_STATUS WHERE DEST_ID IN (1,2);正常状态下STATUS为VALID,ERROR为空。如果ERROR有内容,说明备库路径或网络存在问题。
7. 搭建后最容易遇到的坑:gap 补齐、双备库与杂项排查
7.1 “resolvable gap”到底怎么处理
很多人都搜过oracle主备切换resolvable gap这个问题,我在实搭过程中也遇到过。先理解什么叫 gap:备库应该按顺序应用主库发来的日志,主库归档日志的 thread 1 和 thread 2 是并行产生的,备库要按 thread 内序列号连续应用。如果中间有一段日志因为网络、归档目录变更、备库 FRA 空间不足等原因没有收到,就会出现 gap。
查询 gap 最简单的方式:
SELECT * FROM V$ARCHIVE_GAP;输出会列出来THREAD#、LOW_SEQUENCE#、HIGH_SEQUENCE#,就是要补的范围。补齐步骤是:
- 在主库找到对应线程和序列号的归档日志文件路径。
- 用 scp 拷贝到备库本地目录。
- 在备库执行:
SQL> ALTER DATABASE REGISTER LOGFILE '/backup/orcl/archivelog_1_102_110227.arc';- 全部注册后重新启动日志应用:
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;gap 之所以叫“resolvable gap”,就是因为它可以通过手动补归档解决。怕的是没有提前发现,等切换时才发现备库差了一大段日志,那切换就会失败或者丢数据。所以日常巡检时把V$ARCHIVE_GAP和两个线程的 sequence 差作为必查项,比什么都重要。
7.2 同一套主库挂两套 DG 的注意事项
有人会遇到“两套 DG 库”的架构,也就是一个主库同时给两个备库传输日志,比如一套容灾备库、一套测试备库。这种情况下主库log_archive_config里的dg_config要写全三个库的 db_unique_name,传输目标用log_archive_dest_2和log_archive_dest_3分别指向两个备库:
*.log_archive_config='dg_config=(orcl,orclstby,orcltest)' *.log_archive_dest_2='service=orclstby lgwr async valid_for=(online_logfiles,primary_role) db_unique_name=orclstby' *.log_archive_dest_3='service=orcltest lgwr async valid_for=(online_logfiles,primary_role) db_unique_name=orcltest'两个备库的db_unique_name必须不同,否则 DG Broker 会认为它们是同一个库,注册配置时会冲突。备库的FAL_SERVER都指向主库,这个没问题;但需要注意,如果其中一个备库被提升为主库,另一个备库的FAL_SERVER就需要改成新的主库,否则会一直从旧主库要日志。
7.3 其他高频杂项错误
最后列几个我见过很多次的杂项问题。
补丁不一致是最隐蔽的。主库打了 11.2.0.4 的某月 PSU,备库还在更早的 PSU,日志传输可能正常,但切换时可能因为_optimizer_*或其他内部 bug 导致新主库行为异常。所以补丁级别尽量对齐。
字符集和时区问题我开篇提过,再强调一次:有些环境建备库时图省事,直接CREATE DATABASE默认字符集,后面才同步数据,这种很容易埋雷。备库字符集必须与主库一致。
ORACLE 11g R2的老版本还有一个容易踩的坑:FRA 空间不足会导致备库无法接收归档,从而产生 gap。备库的db_recovery_file_dest_size要给足,并且要监控V$RECOVERY_FILE_DEST的空间使用率。
我在实际搭建中最深的体会是:这套方案本身并不神秘,关键是把“SCN 衔接”和“双线程归档”这两点处理好。备份时把归档收集全,备库 PFILE 把 RAC 参数减干净,路径转换写对,剩下的就是等 MRP 进程慢慢追上。搭好之后连续观察两三天,每天看一次 gap 和线程序列差,确认无异常后,这台单实例备库才算真正能放心纳管。