前言#
这套环境使用 RMAN Active Duplicate,将两节点 RAC 主库 cmsjs 复制为单实例物理备库 cmsjsyddg,再通过 ASYNC 传输 redo,以 READ ONLY WITH APPLY 模式提供备库查询。
主库使用 ASM,备库使用文件系统。主库有两个 redo thread,备库虽然只有一个实例,仍要接收并应用两个 thread 的 redo。备库内存也小于任一主库节点,复制数据库时必须调整继承的参数。
文中的主机、路径、补丁号和运行结果来自本次部署记录。修订后的部署流程尚未完整实库复测;归档清理脚本 v1.1 已完成一次现场预览,结果见第 9.2 节,实际删除分支仍需验证。本文未覆盖数据库软件安装、Broker、自动故障转移及主备切换演练。
1. 环境与部署边界#
1.1 主备配置#
| 项目 | RAC 主库 | 单实例备库 |
|---|---|---|
| DB_NAME | cmsjs | cmsjs |
| DB_UNIQUE_NAME | cmsjs | cmsjsyddg |
| 主机名 | sjdb1、sjdb2 | cmsjsdg2 |
| 实例名 | cmsjs1、cmsjs2 | cmsjsyddg |
| redo thread | 1、2 | 接收主库的 thread 1、2 |
| Oracle 版本 | 19.28.0.0.0 | 19.28.0.0.0 |
| 数据库存储 | ASM,+DATA | 文件系统 OMF |
| ORACLE_HOME | /u01/app/oracle/product/19.3.0/dbhome_1 | /u01/app/oracle/product/19.3.0/db_1 |
| 物理内存 | 每节点约 754 GB | 约 126 GB |
| 保护模式 | MAXIMUM PERFORMANCE | 随配置核验 |
主备 Oracle Home 的补丁记录一致:
37962946;OCW RELEASE UPDATE 19.28.0.0.0
37960098;Database Release Update : 19.28.0.0.250715ORACLE_HOME 路径中的 19.3.0 是目录名,实际版本以数据库查询和补丁清单为准。
| 网络用途 | 主机名 | IP | 监听端口 |
|---|---|---|---|
| RAC 节点 1 | sjdb1 | 10.87.180.10 | 按实际节点监听配置 |
| RAC 节点 2 | sjdb2 | 10.87.180.11 | 按实际节点监听配置 |
| 节点 1 VIP | sjdb1-vip | 10.87.180.12 | 按实际节点监听配置 |
| 节点 2 VIP | sjdb2-vip | 10.87.180.13 | 按实际节点监听配置 |
| SCAN | rac-scan | 10.87.180.14 | 1521 |
| 备库 | cmsjsdg2 | 10.87.201.28 | 1521 |
备库 /u01 总容量约 6 TB。数据文件目录为 /u01/oradata/cmsjsyddg,快速恢复区(FRA)为 /u01/fra/cmsjsyddg,FRA 配额设为 1000G。目录位于同一文件系统时会竞争空间,FRA 配额也不会替数据库预留磁盘。
1.2 redo 如何到达单实例备库#
CMSJS RAC primary
sjdb1 / cmsjs1 / thread 1 ──┐
├── ASYNC redo ──> cmsjsdg2 / cmsjsyddg
sjdb2 / cmsjs2 / thread 2 ──┘ ├─ thread 1 的 SRL
├─ thread 2 的 SRL
└─ MRP0 应用 redo
↓
READ ONLY WITH APPLY物理备库与主库使用相同的 DB_NAME,用不同的 DB_UNIQUE_NAME 区分数据库。CLUSTER_DATABASE=FALSE 表示备库以单实例运行,不会把主库的两个 redo thread 合并成一个。
RFS 进程接收 redo 并写入备库重做日志(Standby Redo Log,SRL);恢复进程 MRP 协调 Redo Apply。实时应用可以在日志尚未归档时读取 SRL。本文的 ADG 配置让备库在只读打开的同时持续应用 redo。
1.3 执行前确认#
开始部署前,Oracle Home 应已安装并完成补丁。复用前还需记录操作系统版本、平台兼容性、CDB/非 CDB 类型、数据库容量和 redo 生成量,现有现场记录未列出这些信息。
- 主库已运行在
ARCHIVELOG模式。Active Duplicate 期间保留所需归档,并安排主库 I/O、CPU 和网络可以承受的执行窗口。 - 核对主备 Oracle Home 的
opatch lspatches。主库查询DBA_REGISTRY_SQLPATCH确认 SQL 补丁状态;备库可查询后再核对数据库记录。 - 如主库为 CDB,在根容器执行文中的数据库级 SQL,并在备库初始化参数中设置
enable_pluggable_database=TRUE。PDB 打开状态和业务服务另行验收。 - 如使用 TDE,先准备备库 keystore 和所需密钥。密码文件不能替代 TDE 密钥。
- 检查现有归档目的地和 Broker 管理状态。本文使用手工参数配置,并以未占用的
LOG_ARCHIVE_DEST_2为例;已有配置需合并,不能直接覆盖。 - 使用
READ ONLY WITH APPLY前确认相应 Active Data Guard 许可。未使用该选项的部署可停留在MOUNTED并运行 Redo Apply。Oracle 19c 物理备库管理
文中的 SQL 默认由指定数据库上的 oracle 用户以 SYSDBA 执行;目录授权和文件属主调整单独标明为 root 操作。
2. 主库检查与日志准备#
2.1 记录数据库和 RAC 状态#
在主库任一实例执行:
set lines 300 pages 100
select name, db_unique_name, dbid, cdb, database_role, open_mode,
log_mode, force_logging, flashback_on, protection_mode,
switchover_status
from v$database;
select inst_id, instance_name, host_name, thread#, status, version
from gv$instance
order by inst_id;
show parameter compatible
show parameter spfile
show parameter remote_login_passwordfile
show parameter dg_broker_start
show parameter db_recovery_file_dest
show parameter log_archive_dest本次部署前记录如下:
NAME CMSJS
DB_UNIQUE_NAME cmsjs
DATABASE_ROLE PRIMARY
OPEN_MODE READ WRITE
LOG_MODE ARCHIVELOG
FORCE_LOGGING NO
FLASHBACK_ON YES
PROTECTION_MODE MAXIMUM PERFORMANCE
INST_ID INSTANCE_NAME HOST_NAME THREAD# STATUS
1 cmsjs1 sjdb1 1 OPEN
2 cmsjs2 sjdb2 2 OPENDuplicate 脚本包含 SPFILE 子句,执行前需确认主库使用 SPFILE。使用其他初始化方式时,不能原样套用该脚本。
2.2 开启 FORCE LOGGING#
主库最初为 FORCE_LOGGING=NO。复制前启用强制日志,避免后续常规 NOLOGGING 操作留下物理备库无法通过 redo 重现的数据。
alter database force logging;
select force_logging from v$database;本次返回 YES。该设置影响后续操作,不会补生成历史上未记录的 redo。Oracle 19c 创建物理备库
2.3 为两个 thread 分别配置 SRL#
先核对在线重做日志(Online Redo Log,ORL):
select thread#, group#, round(bytes / 1024 / 1024) mb, members, status
from v$log
order by thread#, group#;
select group#, type, member from v$logfile order by group#, member;本次每个 thread 有 3 组 ORL,每组 4096 MB、2 个 member。每个 thread 的 SRL 至少比 ORL 多 1 组,单组容量不小于对应来源的 ORL;本环境统一使用 4 GB。Oracle 19c redo 传输配置
| Thread | 现有 ORL group | ORL 单组大小 | 新建 SRL group | SRL 单组大小 |
|---|---|---|---|---|
| 1 | 5、6、7 | 4096 MB | 11、12、13、14 | 4 GB |
| 2 | 8、9、10 | 4096 MB | 15、16、17、18 | 4 GB |
确认组号未被占用后,在主库创建 SRL。主库的 SRL 为后续角色转换做准备;Duplicate 也会使用已有定义在备库重建 SRL。
alter database add standby logfile thread 1 group 11 ('+DATA','+DATA') size 4G;
alter database add standby logfile thread 1 group 12 ('+DATA','+DATA') size 4G;
alter database add standby logfile thread 1 group 13 ('+DATA','+DATA') size 4G;
alter database add standby logfile thread 1 group 14 ('+DATA','+DATA') size 4G;
alter database add standby logfile thread 2 group 15 ('+DATA','+DATA') size 4G;
alter database add standby logfile thread 2 group 16 ('+DATA','+DATA') size 4G;
alter database add standby logfile thread 2 group 17 ('+DATA','+DATA') size 4G;
alter database add standby logfile thread 2 group 18 ('+DATA','+DATA') size 4G;
select thread#, group#, round(bytes / 1024 / 1024) mb, status
from v$standby_log
order by thread#, group#;本次新建的 8 组 SRL 均为 UNASSIGNED。两个 member 都放在 +DATA 是现场配置,不构成两个独立磁盘组之间的故障隔离,底层冗余仍取决于 ASM 和存储设计。
2.4 设置 Data Guard 成员#
在主库执行:
alter system set log_archive_config='DG_CONFIG=(cmsjs,cmsjsyddg)'
scope=both sid='*';
alter system set standby_file_management='AUTO' scope=both sid='*';DG_CONFIG 声明配置中的数据库成员。STANDBY_FILE_MANAGEMENT=AUTO 用于物理备库的数据文件自动管理;在当前主库设置它,是为以后成为备库做准备。
此时先不启用发往 cmsjsyddg 的远端归档目的地,待备库监听、网络认证和 Duplicate 完成后再配置。
3. 准备备库目录、监听和网络认证#
3.1 设置环境并创建目录#
在备库 oracle 用户会话中设置:
export ORACLE_SID=cmsjsyddg
export ORACLE_HOME=/u01/app/oracle/product/19.3.0/db_1
export PATH="$ORACLE_HOME/bin:$PATH"在备库使用 root 创建目录并设置属主和权限:
install -d -o oracle -g oinstall -m 750 \
/u01/oradata/cmsjsyddg \
/u01/fra/cmsjsyddg \
/u01/app/oracle/admin/cmsjsyddg/adumpOMF 负责生成文件名,目录通过以下参数指定:
| 参数 | 值 | 用途 |
|---|---|---|
DB_CREATE_FILE_DEST | /u01/oradata/cmsjsyddg | 数据文件创建目录 |
DB_CREATE_ONLINE_LOG_DEST_1 | /u01/oradata/cmsjsyddg | 控制文件与 redo member 的一个目录 |
DB_CREATE_ONLINE_LOG_DEST_2 | /u01/fra/cmsjsyddg | 控制文件与 redo member 的另一个目录 |
DB_RECOVERY_FILE_DEST | /u01/fra/cmsjsyddg | FRA |
DB_RECOVERY_FILE_DEST_SIZE | 1000G | FRA 配额 |
本方案使用 OMF 重新生成目标文件名,因此不配置 DB_FILE_NAME_CONVERT 和 LOG_FILE_NAME_CONVERT。复制主库 SPFILE 时仍需确认没有继承旧的转换规则或额外的 DB_CREATE_ONLINE_LOG_DEST_n。两个目录若共用 /u01 文件系统,其故障隔离能力有限。Oracle 19c RMAN Duplicate 文件命名
3.2 配置静态监听#
RMAN 会在 Duplicate 过程中重启辅助实例。静态监听使辅助实例在 NOMOUNT 阶段仍能通过 Oracle Net 连接。
在备库 Oracle Home 的 network/admin/listener.ora 中加入以下配置。如果已使用 TNS_ADMIN,应编辑它指向的文件;已有监听配置按实际情况合并。
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = cmsjsdg2)(PORT = 1521))
)
)
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = cmsjsyddg)
(ORACLE_HOME = /u01/app/oracle/product/19.3.0/db_1)
(SID_NAME = cmsjsyddg)
)
)由备库 oracle 用户启动并检查监听;已有监听运行时使用 reload 加载配置。
lsnrctl start
lsnrctl status
lsnrctl services本次静态服务显示:
Service "cmsjsyddg" has 1 instance(s).
Instance "cmsjsyddg", status UNKNOWNUNKNOWN 表示监听无法通过动态注册获知实例状态,不等同于实例故障,也不能证明实例已经启动。第 4.4 节通过 SYSDBA 连接验证实例状态。
3.3 配置双向 TNS#
备库文件为 /u01/app/oracle/product/19.3.0/db_1/network/admin/tnsnames.ora:
CMSJS =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 10.87.180.14)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = cmsjs)
)
)
CMSJSYDDG =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = cmsjsdg2)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = cmsjsyddg)
)
)CMSJS 使用本次记录的 SCAN IP。复用时以实际 SCAN 配置为准,SERVICE_NAME 也要从主库监听服务列表核实,不能仅由 DB_NAME 推断。备库应能访问 SCAN 重定向到的 RAC 节点 VIP 和监听端口。
在两个 RAC 节点的 /u01/app/oracle/product/19.3.0/dbhome_1/network/admin/tnsnames.ora 中加入相同的 CMSJSYDDG 条目。三台主机均需能将 cmsjsdg2 解析为 10.87.201.28。
在备库执行:
tnsping CMSJS
tnsping CMSJSYDDG在两个 RAC 节点分别执行:
tnsping CMSJSYDDGtnsping 只用于检查连接描述符和监听可达性。数据库服务、密码文件和 SYSDBA 认证还需实际登录验证。
3.4 复制密码文件#
本次主库密码文件位于:
+DATA/CMSJS/PASSWORD/pwdcmsjs.256.1243102711复用时先用数据库资源配置核实实际密码文件位置。由主库 grid 用户导出:
asmcmd pwcopy \
+DATA/CMSJS/PASSWORD/pwdcmsjs.256.1243102711 \
/tmp/orapwcmsjs由主库 root 调整属主和权限:
chown oracle:oinstall /tmp/orapwcmsjs
chmod 600 /tmp/orapwcmsjs再由主库 oracle 用户复制到备库:
scp /tmp/orapwcmsjs oracle@cmsjsdg2:/tmp/确认备库目标位置没有需要保留的旧密码文件后,由 oracle 用户安装:
mv /tmp/orapwcmsjs "$ORACLE_HOME/dbs/orapwcmsjsyddg"
chmod 600 "$ORACLE_HOME/dbs/orapwcmsjsyddg"确认后删除主库 /tmp/orapwcmsjs 中的临时副本。复制主库密码文件是为了在初始辅助实例上建立远程认证;Active Duplicate 创建物理备库时还会处理密码文件。Oracle 19c DUPLICATE 参考
4. 调整内存并启动辅助实例#
4.1 按备库资源设置内存#
主库每节点的 SGA_TARGET 约 353.5 GB、PGA_AGGREGATE_TARGET 约 117.8 GB、PROCESSES=8000。备库资源不足,不能直接继承这些值。
| 参数 | 本次备库值 |
|---|---|
SGA_TARGET / SGA_MAX_SIZE | 64G / 64G |
PGA_AGGREGATE_TARGET / PGA_AGGREGATE_LIMIT | 16G / 32G |
PROCESSES / SESSIONS | 3000 / 4522 |
USE_LARGE_PAGES | FALSE |
这些值来自本次配置,不能作为按物理内存比例分配的通用标准。PGA target 不是硬上限,复用时还要给操作系统、恢复进程和查询负载留出空间。本次未启用 HugePages;如需启用,应结合操作系统配置另行调整。
4.2 创建 PFILE#
在备库创建 $ORACLE_HOME/dbs/initcmsjsyddg.ora:
*.db_name='cmsjs'
*.db_unique_name='cmsjsyddg'
*.compatible='19.0.0'
*.cluster_database=FALSE
*.remote_login_passwordfile='EXCLUSIVE'
*.memory_target=0
*.memory_max_target=0
*.sga_target=64G
*.sga_max_size=64G
*.pga_aggregate_target=16G
*.pga_aggregate_limit=32G
*.processes=3000
*.sessions=4522
*.use_large_pages='FALSE'
*.audit_file_dest='/u01/app/oracle/admin/cmsjsyddg/adump'
*.diagnostic_dest='/u01/app/oracle'
*.db_create_file_dest='/u01/oradata/cmsjsyddg'
*.db_create_online_log_dest_1='/u01/oradata/cmsjsyddg'
*.db_create_online_log_dest_2='/u01/fra/cmsjsyddg'
*.db_recovery_file_dest='/u01/fra/cmsjsyddg'
*.db_recovery_file_dest_size=1000G
*.standby_file_management='AUTO'
*.log_archive_config='DG_CONFIG=(cmsjs,cmsjsyddg)'
*.fal_server='CMSJS'COMPATIBLE 应与主库实际值核对。MEMORY_TARGET=0 和 MEMORY_MAX_TARGET=0 明确使用本文的 SGA/PGA 管理方式;主库若为 CDB,还需按第 1.3 节补充参数。
4.3 使用 PFILE 启动到 NOMOUNT#
用 PFILE 启动辅助实例,再由 RMAN 的 SPFILE 子句复制并修改主库参数,无需提前执行 CREATE SPFILE FROM PFILE。
sqlplus / as sysdba在 SQL*Plus 中将 STARTUP 写成一行:
startup nomount pfile='/u01/app/oracle/product/19.3.0/db_1/dbs/initcmsjsyddg.ora';
show parameter spfile
select instance_name, status from v$instance;此时 spfile 的值应为空,实例应为 cmsjsyddg / STARTED。这说明辅助实例已启动,数据库尚未挂载。
4.4 验证 SYSDBA 网络连接#
在备库连接主库,按提示输入 SYS 密码:
sqlplus 'sys@CMSJS as sysdba'select name, db_unique_name, database_role from v$database;应连接到 CMSJS / cmsjs / PRIMARY。
随后在备库本机及两个 RAC 节点分别测试辅助实例连接:
sqlplus 'sys@CMSJSYDDG as sysdba'select instance_name, status from v$instance;应连接到 cmsjsyddg / STARTED。在 NOMOUNT 阶段使用 V$INSTANCE 验证,不查询尚不可用的数据库挂载信息。
5. 执行 RMAN Active Duplicate#
5.1 先检查将继承的主库参数#
DUPLICATE ... SPFILE 会以主库 SPFILE 为基础生成备库参数文件。辅助实例启动用的 PFILE 不会覆盖复制后的 SPFILE,因此内存、目录和单实例配置必须在 SET 中再次指定。
主库先检查以下参数以及它们在 V$SPPARAMETER 中的 SID 作用域:
select sid, name, value
from v$spparameter
where isspecified = 'TRUE'
and (name in (
'db_file_name_convert', 'log_file_name_convert',
'control_files', 'remote_listener', 'local_listener',
'memory_target', 'memory_max_target',
'instance_number', 'thread', 'undo_tablespace')
or name like 'log_archive_dest%'
or name like 'db_create_online_log_dest%')
order by name, sid;脚本使用本次环境的 UNDOTBS1。执行前确认该 undo 表空间存在,并检查 RAC 的实例专属参数、旧路径与额外归档目的地。新 SID cmsjsyddg 不会直接匹配 cmsjs1.*、cmsjs2.* 条目,应检查公共参数和新实例的实际生效值;也不要因备库为单实例而删除源 RAC 的其他 undo 数据文件。
Oracle 19c 的 RMAN SPFILE 子句支持 RESET,用于移除不再需要的参数。执行下方三个 RESET 前,要确认源 SPFILE 中存在其对应作用域的条目;未设置的参数不能机械照抄 RESET,否则可能遇到 ORA-32010。发现额外参数差异后,再针对明确的条目调整,避免批量清空 RAC 或隐藏参数。Oracle 19c DUPLICATE 参数规则、ORA-32010
5.2 连接并复制#
在备库 oracle 用户会话中启动 RMAN:
rman分别连接并按提示输入密码:
CONNECT TARGET sys@CMSJS;
CONNECT AUXILIARY sys@CMSJSYDDG;确认 RMAN 输出同时包含正确的 target 和 auxiliary 连接信息,再执行脚本。保留运行日志,但不要将 SYS 密码写进命令行或脚本。
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;
ALLOCATE AUXILIARY CHANNEL a1 DEVICE TYPE DISK;
ALLOCATE AUXILIARY CHANNEL a2 DEVICE TYPE DISK;
ALLOCATE AUXILIARY CHANNEL a3 DEVICE TYPE DISK;
ALLOCATE AUXILIARY CHANNEL a4 DEVICE TYPE DISK;
DUPLICATE TARGET DATABASE
FOR STANDBY
FROM ACTIVE DATABASE
USING COMPRESSED BACKUPSET
DORECOVER
SPFILE
SET db_unique_name='cmsjsyddg'
SET cluster_database='FALSE'
SET cluster_database_instances='1'
SET remote_login_passwordfile='EXCLUSIVE'
SET memory_target='0'
SET memory_max_target='0'
SET sga_target='64G'
SET sga_max_size='64G'
SET pga_aggregate_target='16G'
SET pga_aggregate_limit='32G'
SET processes='3000'
SET sessions='4522'
SET use_large_pages='FALSE'
SET audit_file_dest='/u01/app/oracle/admin/cmsjsyddg/adump'
SET diagnostic_dest='/u01/app/oracle'
SET db_create_file_dest='/u01/oradata/cmsjsyddg'
SET db_create_online_log_dest_1='/u01/oradata/cmsjsyddg'
SET db_create_online_log_dest_2='/u01/fra/cmsjsyddg'
SET db_recovery_file_dest='/u01/fra/cmsjsyddg'
SET db_recovery_file_dest_size='1000G'
SET standby_file_management='AUTO'
SET log_archive_config='DG_CONFIG=(cmsjs,cmsjsyddg)'
SET log_archive_dest_1='LOCATION=USE_DB_RECOVERY_FILE_DEST VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=cmsjsyddg'
SET log_archive_dest_state_1='ENABLE'
SET log_archive_dest_2='SERVICE=CMSJS ASYNC NOAFFIRM VALID_FOR=(ONLINE_LOGFILE,PRIMARY_ROLE) DB_UNIQUE_NAME=cmsjs REOPEN=15'
SET log_archive_dest_state_2='DEFER'
SET fal_server='CMSJS'
SET undo_tablespace='UNDOTBS1'
RESET remote_listener
RESET local_listener
RESET control_files
NOFILENAMECHECK;
}本次使用 4 个 target channel 和 4 个 auxiliary channel。压缩备份集可减少传输数据量,同时增加 CPU 开销;通道数应结合主库负载、网络和备库写入能力调整。先用 SHOW COMPRESSION ALGORITHM 检查 RMAN 压缩算法配置,算法的许可要求不能仅凭 USING COMPRESSED BACKUPSET 推断。Oracle 19c 备份压缩
NOFILENAMECHECK 会跳过源、目标文件名冲突检查。本次主库使用 ASM,备库使用另一台主机的文件系统;复用该选项前必须确认目标不会访问或覆盖主库文件,尤其要检查共享存储和目录挂载。
5.3 检查复制结果和文件路径#
本次运行日志以这一行结束:
Finished Duplicate Db at 2026-09-05 12:52:37这表示本次 Duplicate 完成,持续日志应用还需后续配置。在备库执行:
select name, db_unique_name, database_role, open_mode, log_mode,
force_logging, switchover_status
from v$database;
show parameter spfile
show parameter cluster_database
show parameter db_create_file_dest
show parameter db_recovery_file_dest
show parameter fal_server
show parameter remote_listener
select name from v$controlfile;
select file#, name from v$datafile order by file#;
select group#, type, member from v$logfile order by group#, member;
select thread#, group#, round(bytes / 1024 / 1024) mb, status
from v$standby_log order by thread#, group#;本次 Duplicate 后为 PHYSICAL STANDBY / MOUNTED,CLUSTER_DATABASE=FALSE,FAL_SERVER=CMSJS,REMOTE_LISTENER 为空。文件路径记录如下,OMF 自动生成的末尾文件名以实际查询为准:
主库数据文件:+DATA/CMSJS/DATAFILE/...
备库数据文件:/u01/oradata/cmsjsyddg/CMSJSYDDG/datafile/...
控制文件副本 1:/u01/oradata/cmsjsyddg/CMSJSYDDG/controlfile/...
控制文件副本 2:/u01/fra/cmsjsyddg/CMSJSYDDG/controlfile/...本次在线 redo 和 SRL 的 member 分布在 /u01/oradata/... 与 /u01/fra/...。SRL 为 thread 1 的 11~14 组和 thread 2 的 15~18 组,每组 4096 MB。RMAN 按主库已有定义在备库重建这些 SRL,并非复制正在使用的 SRL 内容。实际组数、thread、容量和 member 路径均需查询确认;缺少 SRL 时先补齐,再启动持续应用。Oracle 19c DUPLICATE 的备库日志处理
6. 配置持续传输与日志应用#
6.1 检查备库归档参数#
复制完成后,核对下列参数是否与 Duplicate 中的备库配置一致:
alter system set log_archive_dest_1=
'LOCATION=USE_DB_RECOVERY_FILE_DEST VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=cmsjsyddg'
scope=both;
alter system set log_archive_dest_state_1=ENABLE scope=both;
alter system set log_archive_dest_2=
'SERVICE=CMSJS ASYNC NOAFFIRM VALID_FOR=(ONLINE_LOGFILE,PRIMARY_ROLE) DB_UNIQUE_NAME=cmsjs REOPEN=15'
scope=both;
alter system set log_archive_dest_state_2=ENABLE scope=both;
alter system set fal_server='CMSJS' scope=both;DEST_1 将本地归档写入 FRA。DEST_2 仅在该数据库成为主库时发送在线 redo,所以它在物理备库角色下不会向原主库反向发送当前收到的 redo。FAL_SERVER 指向可请求缺失归档的数据库服务。
反向目的地是角色转换的准备参数,是否具备切换条件仍要经过专门检查和演练。
6.2 启动 MRP#
在备库执行:
alter database recover managed standby database disconnect from session;本配置具备 SRL,上述命令用于启动实时应用,无需添加 USING CURRENT LOGFILE 子句。DORECOVER 不会替代这一步持续恢复。Oracle 19c Redo Apply
6.3 启用主库向备库发送 redo#
主库保留已验证的本地归档策略。只有本地 FRA 已配置、容量满足需求,且本次确实计划使用 FRA 归档时,才应用以下现场设置:
alter system set log_archive_dest_1=
'LOCATION=USE_DB_RECOVERY_FILE_DEST VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=cmsjs'
scope=both sid='*';确认 DEST_2 未用于其他目的地后,在主库执行:
alter system set log_archive_dest_2=
'SERVICE=CMSJSYDDG ASYNC NOAFFIRM VALID_FOR=(ONLINE_LOGFILE,PRIMARY_ROLE) DB_UNIQUE_NAME=cmsjsyddg REOPEN=15'
scope=both sid='*';
alter system set log_archive_dest_state_2=ENABLE scope=both sid='*';
alter system set fal_server='CMSJSYDDG' scope=both sid='*';SID='*' 写入 RAC 的公共设置。若已有实例专属值,还要核对两个实例实际生效的参数:
select inst_id, name, value
from gv$parameter
where name in ('log_archive_config', 'log_archive_dest_2',
'log_archive_dest_state_2', 'fal_server')
order by name, inst_id;
select protection_mode, protection_level from v$database;本次采用 ASYNC NOAFFIRM,主库原有保护模式为 MAXIMUM PERFORMANCE。ASYNC 不等待备库接收确认后才完成主库提交,因此不能据此承诺故障时零数据丢失;配置传输属性后也应查询实际保护模式。Oracle 19c 保护模式
7. 打开 Active Data Guard#
先确认备库已开始接收 redo,恢复进程存在且没有阻塞恢复的错误。需同时提供只读查询并已确认相应许可时,在备库依次执行:
alter database recover managed standby database cancel;
alter database open read only;
alter database recover managed standby database disconnect from session;
select name, db_unique_name, database_role, open_mode from v$database;本次结果:
NAME CMSJS
DB_UNIQUE_NAME cmsjsyddg
DATABASE_ROLE PHYSICAL STANDBY
OPEN_MODE READ ONLY WITH APPLYREAD ONLY WITH APPLY 表明数据库已只读打开且运行日志应用。还需按第 8 节检查两个 thread 的最新 redo 是否已传输和应用。
8. 验证两个 thread 的传输与应用#
8.1 从两个主库实例检查远端目的地#
在主库执行:
set lines 300 pages 100
col destination for a25
col error for a80
col database_mode for a20
col recovery_mode for a40
select inst_id, dest_id, status, database_mode, recovery_mode,
destination, error
from gv$archive_dest_status
where dest_id = 2
order by inst_id;本次打开 ADG 后的记录为:
INST_ID STATUS DATABASE_MODE RECOVERY_MODE
1 VALID OPEN_READ-ONLY MANAGED REAL TIME APPLY WITH QUERY
2 VALID OPEN_READ-ONLY MANAGED REAL TIME APPLY WITH QUERY两个实例的 ERROR 均为空。OPEN_READ-ONLY 和 WITH QUERY 对应第 7 节打开 ADG 后的状态,在只挂载备库时不应要求这两个结果。
8.2 产生可追踪的日志进展#
在 sjdb1 本地连接 cmsjs1,再在 sjdb2 本地连接 cmsjs2,分别执行:
select instance_name, thread# from v$instance;
alter system switch logfile;分别使用各实例的本地会话,确认两个 thread 都有日志推进。ALTER SYSTEM ARCHIVE LOG CURRENT 未指定 thread 时可作用于所有启用的 thread,不能用它来表示只切换当前节点的 thread。Oracle 19c ALTER SYSTEM
在备库观察 SRL:
select thread#, group#, sequence#, status, archived
from v$standby_log
order by thread#, group#;本次记录过以下状态:
THREAD# GROUP# SEQUENCE# STATUS
1 11 160 ACTIVE
2 15 50 ACTIVE这些组号和 sequence 是现场快照,不是复用时必须出现的固定值。检查重点是两个 thread 都能接收 redo,并在主库产生日志后持续推进。
8.3 检查 RFS 和 MRP#
Oracle 19c 推荐使用 V$DATAGUARD_PROCESS 查看 Data Guard 进程:
select name, role, action, thread#, sequence#
from v$dataguard_process
where name in ('RFS', 'MRP0')
order by name, thread#;也可使用以下兼容查询,与现场输出对照:
select process, status, thread#, sequence#
from v$managed_standby
where process in ('RFS', 'MRP0')
order by process, thread#;V$MANAGED_STANDBY 已被弃用,但在 19c 仍可用于读取已有巡检结果。MRP 的 APPLYING_LOG 表示正在应用;WAIT_FOR_LOG 表示等待日志,需要与时间戳、归档缺口和传输状态一起解释。单实例备库不要求每个 thread 各有一个 MRP0。Oracle 19c V$DATAGUARD_PROCESS
8.4 检查延迟和指标是否更新#
在备库执行:
set lines 250 pages 100
col name for a20
col value for a25
col time_computed for a25
col datum_time for a25
select name, value, time_computed, datum_time
from v$dataguard_stats
where name in ('transport lag', 'apply lag');本次记录的延迟值为:
transport lag +00 00:00:00
apply lag +00 00:00:00这表示该次指标采样未显示传输或应用积压,不能解释为网络传输没有耗时。TIME_COMPUTED 是指标计算时间,DATUM_TIME 是计算所依据的主库数据到达备库的时间。应间隔查询并结合主库日志进展观察;若 DATUM_TIME 一直不变,即使值为 0,也不能据此判定同步正常。Oracle 19c V$DATAGUARD_STATS
8.5 区分归档序号差与恢复缺口#
下列查询只比较当前 resetlogs 分支中,RFS 记录的最大接收序号与 APPLIED=YES 的最大序号:
select thread#,
max(sequence#) last_received,
max(case when applied = 'YES' then sequence# end) last_applied,
max(sequence#) -
max(case when applied = 'YES' then sequence# end) archived_seq_delta
from v$archived_log
where registrar = 'RFS'
and resetlogs_change# = (select resetlogs_change# from v$database)
group by thread#
order by thread#;实时应用可能正在读取尚未归档的 SRL,因此这个差值不能直接换算成应用延迟。APPLIED=IN-MEMORY 也不等于数据文件已完成更新;以最大序号相减还会漏掉中间缺失的序号,或在没有已应用记录时返回空值。Oracle 19c V$ARCHIVED_LOG
另查当前阻塞恢复的归档缺口:
select thread#, low_sequence#, high_sequence# from v$archive_gap;发现缺口时,处理后重复查询,直到当前阻塞缺口消除。查询为空时,仍需结合两个 thread 的进展、进程状态和持续更新的延迟指标判断同步状态。Oracle 19c V$ARCHIVE_GAP
8.6 记录验收基线#
| 检查位置 | 检查项 | 本次记录或验收要求 |
|---|---|---|
| 主库 | 数据库角色与打开模式 | PRIMARY / READ WRITE |
| 主库 | RAC 实例与 thread | cmsjs1 / 1、cmsjs2 / 2 |
| 主库 | 保护模式 | MAXIMUM PERFORMANCE |
| 主库 | 两实例 DEST_2 | VALID,ERROR 为空 |
| 备库 | 角色与打开模式 | PHYSICAL STANDBY / READ ONLY WITH APPLY |
| 备库 | 集群参数 | CLUSTER_DATABASE=FALSE |
| 备库 | SRL | 每个 thread 4 组,每组 4096 MB |
| 备库 | redo 进展 | 两个 thread 都能接收并持续推进 |
| 备库 | 应用进程 | MRP 存在,无持续阻塞恢复的错误 |
| 备库 | 延迟 | 本次值为 0;复验还需确认 DATUM_TIME 更新 |
| 备库 | 归档缺口 | 复验确认无当前阻塞恢复的缺口 |
现场记录给出了最终状态快照,但缺少多次 DATUM_TIME 采样和完整缺口查询结果。交付验收时需补充并保存这些结果,以确认日志传输持续正常。
9. 备库归档清理与自动化#
9.1 定义清理范围#
本次清理条件为:归档由 RFS 接收、APPLIED='YES'、归档完成时间早于当前时间 7 天。七天按 COMPLETION_TIME 计算,不按 redo 开始时间计算;不要把它直接改写成含义不同的 RMAN UNTIL TIME。
下方脚本为 v1.1。除上述条件外,脚本还要求记录为可用、未删除;同一路径若存在不满足条件的活动记录,则跳过该文件。APPLIED='IN-MEMORY' 不进入删除清单。Oracle 19c V$ARCHIVED_LOG
脚本按精确文件名生成 DELETE ARCHIVELOG,不用 LIKE。即使传入完整文件路径,LIKE 中的 _、% 仍可能扩大匹配范围。SQL 查询失败、输出异常或数据库身份不符时,脚本直接退出。Oracle 19c recordSpec
执行前在备库 RMAN 会话中核对现有策略:
SHOW ARCHIVELOG DELETION POLICY;
SHOW RETENTION POLICY;七天只是这个脚本的筛选门槛,不是 FRA 至少保留七天归档的保证。FRA 仍可能回收符合条件的文件,恢复窗口也不等于每个文件的保留天数。备份、Flashback 和级联备库有额外需要时,应先确定整体策略。脚本不使用 FORCE 绕过 RMAN 的删除策略。Oracle 19c RMAN 配置
9.2 安装脚本并先预览#
在备库以 oracle 用户创建目录,将下面内容保存为 /home/oracle/scripts/clean_arch_cmsjsyddg.sh,使用 LF 换行:
mkdir -p /home/oracle/scripts /home/oracle/log#!/bin/bash
# 默认只预览;核对候选清单后,使用 --delete 执行删除。
set -Eeuo pipefail
umask 077
SCRIPT_VERSION=1.1
MODE=${1:---preview}
case "$MODE" in
--preview|--delete) ;;
*) printf 'Usage: %s [--preview|--delete]\n' "$0" >&2; exit 2 ;;
esac
export ORACLE_SID=cmsjsyddg
export ORACLE_HOME=/u01/app/oracle/product/19.3.0/db_1
export PATH="$ORACLE_HOME/bin:/usr/bin:/bin"
export NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'
unset TWO_TASK ORACLE_PDB_SID
LOG_DIR=/home/oracle/log
mkdir -p "$LOG_DIR"
LOG_FILE="$LOG_DIR/clean_arch_${ORACLE_SID}_$(date +%Y%m%d).log"
exec >>"$LOG_FILE" 2>&1
# 防止同一脚本重叠运行;此锁不会阻止数据库角色切换。
exec 9>"$LOG_DIR/.clean_arch_${ORACLE_SID}.lock"
if ! flock -n 9; then
printf '%s Another cleanup is running.\n' "$(date '+%F %T')"
exit 75
fi
TMP_DIR=$(mktemp -d "$LOG_DIR/.clean_arch_${ORACLE_SID}.XXXXXX")
cleanup() {
rc=$?
trap - EXIT
rm -f -- "$TMP_DIR/role.log" "$TMP_DIR/candidates.rman" "$TMP_DIR/rman.log"
rmdir -- "$TMP_DIR"
printf '%s Cleanup ended; exit=%s\n' "$(date '+%F %T')" "$rc"
exit "$rc"
}
trap cleanup EXIT
printf '\n%s Cleanup started; version=%s; mode=%s\n' "$(date '+%F %T')" "$SCRIPT_VERSION" "$MODE"
check_identity() {
if ! sqlplus -L -s / as sysdba >"$TMP_DIR/role.log" 2>&1 <<'SQL'
whenever oserror exit 2
whenever sqlerror exit 1
set heading off feedback off pagesize 0 verify off echo off
select case
when database_role = 'PHYSICAL STANDBY'
and lower(db_unique_name) = 'cmsjsyddg'
then 'IDENTITY_OK'
else 'IDENTITY_MISMATCH'
end
from v$database;
exit success
SQL
then
cat "$TMP_DIR/role.log"
return 1
fi
# 只接受预期输出,SQL*Plus 自身的 SP2 错误也不会被当成成功。
if [[ "$(sed '/^[[:space:]]*$/d; s/^[[:space:]]*//; s/[[:space:]]*$//' "$TMP_DIR/role.log")" != 'IDENTITY_OK' ]]; then
cat "$TMP_DIR/role.log"
printf 'Database identity or role check failed.\n'
return 1
fi
}
check_identity
# 只生成完整文件名,不使用 LIKE;下划线和百分号不会扩大匹配范围。
# 同名活动记录若不满足条件,则跳过该文件;说明留在 Shell 层。
if ! sqlplus -L -s / as sysdba >"$TMP_DIR/candidates.rman" 2>&1 <<'SQL'
whenever oserror exit 2
whenever sqlerror exit 1
set heading off feedback off pagesize 0 verify off echo off
set linesize 32767 trimout on trimspool on tab off define off
select distinct 'delete noprompt archivelog ''' || a.name || ''';'
from v$archived_log a
where a.registrar = 'RFS'
and a.applied = 'YES'
and a.archived = 'YES'
and a.deleted = 'NO'
and a.status = 'A'
and a.name is not null
and a.completion_time < sysdate - 7
and not exists (
select 1
from v$archived_log b
where b.name = a.name
and b.deleted = 'NO'
and b.status = 'A'
and (nvl(b.registrar, '?') <> 'RFS'
or nvl(b.applied, '?') <> 'YES'
or nvl(b.archived, '?') <> 'YES'
or b.completion_time is null
or b.completion_time >= sysdate - 7)
)
order by 1;
exit success
SQL
then
cat "$TMP_DIR/candidates.rman"
exit 1
fi
# 拒绝诊断文本、换行文件名和含单引号的文件名,避免生成异常 RMAN 命令。
if grep -Ev "^(delete noprompt archivelog '[^']+';|[[:space:]]*)$" "$TMP_DIR/candidates.rman"; then
printf 'Unexpected candidate output; no RMAN deletion was started.\n'
exit 1
fi
ARCH_COUNT=$(grep -c '^delete noprompt archivelog ' "$TMP_DIR/candidates.rman" || true)
printf 'Eligible file names: %s\n' "$ARCH_COUNT"
cat "$TMP_DIR/candidates.rman"
# 只轮转脚本日志,不操作归档目录。
find "$LOG_DIR" -maxdepth 1 -type f \
-name "clean_arch_${ORACLE_SID}_*.log" -mtime +90 -delete
if [[ "$MODE" == '--preview' || "$ARCH_COUNT" -eq 0 ]]; then
printf 'Preview completed, or no eligible file was found.\n'
exit 0
fi
# 缩小检查与删除之间的窗口;不能替代切换期间暂停调度。
check_identity
if rman target / cmdfile="$TMP_DIR/candidates.rman" >"$TMP_DIR/rman.log" 2>&1; then
RMAN_RC=0
else
RMAN_RC=$?
fi
cat "$TMP_DIR/rman.log"
if [[ "$RMAN_RC" -ne 0 ]]; then
exit "$RMAN_RC"
fi
# RMAN 可能跳过受删除策略保护的文件;发现诊断码时要求检查日志。
if grep -Eq '(RMAN-|ORA-)[0-9]{5}' "$TMP_DIR/rman.log"; then
printf 'Oracle/RMAN diagnostic messages were found; inspect the log.\n'
exit 3
fi
printf 'RMAN command file completed. Check its output for actual deleted files.\n'该脚本使用 Bash、flock 和 mktemp。flock 只防止脚本自身重叠运行,不能阻止数据库角色转换。切换、故障转移、重建或控制文件维护期间,应先暂停调度,等正在运行的作业退出;两次角色检查仍不能消除检查与删除之间的时间窗口。
脚本不自动执行全库 CROSSCHECK ARCHIVELOG ALL 和 DELETE EXPIRED。EXPIRED 表示 RMAN 检查时文件缺失或不可访问,不表示超过七天;相关元数据维护应独立检查并记录结果。Oracle 19c DELETE
授权、检查语法并预览:
chmod 750 /home/oracle/scripts/clean_arch_cmsjsyddg.sh
bash -n /home/oracle/scripts/clean_arch_cmsjsyddg.sh
/home/oracle/scripts/clean_arch_cmsjsyddg.sh --preview
cat /home/oracle/log/clean_arch_cmsjsyddg_$(date +%Y%m%d).log2026-09-05 13:50:56,在 cmsjsdg2 上由 oracle 用户执行 v1.1 的 --preview,日志显示 Eligible file names: 0、Cleanup ended; exit=0,Shell 返回码也为 0。这次现场运行通过了身份检查和候选查询,没有符合条件的归档,未调用 RMAN 删除。它验证了预览和空候选处理,尚未验证存在候选文件时的实际删除。
预览不删除数据库归档,但会记录候选清单并清理超过 90 天的本脚本执行日志。确认文件名、应用状态、时间范围及 RMAN 策略符合要求后,手工执行一次正式清理:
/home/oracle/scripts/clean_arch_cmsjsyddg.sh --delete检查退出码和日志中的实际删除结果,再复查第 8 节的同步状态与第 10.4 节的 FRA 使用量。候选文件数不一定等于删除数,RMAN 可能因策略保护跳过部分文件;脚本发现诊断码时会以非零值退出,便于人工确认。
9.3 配置定时任务#
完成手工验证后,以备库 oracle 用户编辑 crontab:
crontab -e每天服务器本地时间 03:30 执行正式清理:
30 3 * * * /home/oracle/scripts/clean_arch_cmsjsyddg.sh --delete用 crontab -l 检查调度。脚本将运行信息写入 /home/oracle/log,日志保留 90 天;将非零退出和日志中的失败信息接入现有监控。本文没有配置告警通知服务。
