☰
Oracle 19c RAC远程克隆PDB:原理、实操与排坑指南
2026/10/21 17:51:35 网站建设 项目流程

做DBA这些年,被开发要数据、要环境、要“跟生产尽可能一样”的次数有点多。早几年的标准做法是expdp导dump,后来换rman duplicate,都在折腾,不是要额外空间就是步骤冗长。真正让我觉得又稳又快的,其实是Oracle 19c里一个听上去很朴素的功能:远程克隆PDB。它不依赖备份集,也不要求目标端准备大容量dump存储,一条CREATE PLUGGABLE DATABASE语句,就能把源端一个PDB在另一个CDB里复制出来,尤其两边都是RAC集群时,既省时间又能保持数据在克隆窗口内的一致性。这篇就围绕oracle19c RAC远程克隆PDB,把原理、前置条件、完整实操、RAC细节和排坑经验一条线捋下来,给要做测试库或开发库的朋友一个可抄作业的参照。

1. 项目场景与方案选择

1.1 什么场景适合远程克隆PDB

远程克隆PDB最典型的场景是:生产中有一个承载业务数据的PDB,开发、测试、预发环境需要一份接近生产的数据,但又不能直接连到生产库。很多团队直接做备份恢复,但备份恢复要先把备份文件传到目标机,再执行restore,过程不短。克隆PDB的优点在于它是在CDB层面直接生成一个新的PDB,数据文件和字典都由Oracle自己完成,不会污染源PDB。

在实际项目里,我遇到得最多的需求其实有这几种:第一,测试环境要一份接近生产的数据,主要用来做功能验证、性能基线;第二,新版本升级前的兼容性验证,比如19c的库要验证新版应用是否连得上;第三,临时给数据分析团队拉一份快照数据,用完即扔。远程克隆在这些场景里都非常合适。

需要注意的是,远程克隆不是银弹。如果源PDB有几十TB,克隆时间会很长,而且源PDB在读模式下持续服务业务,应用会收到read-only的错误。如果业务不能接受短窗只读,就得考虑更复杂的手段,比如可刷新PDB或者备库转换。所以先想清楚业务容忍度,再决定要不要克隆。

1.2 和传统方案横向对比

我自己用下来,几种常见方案的优劣势可以这样看:

方案数据一致性额外存储操作复杂度适合场景
远程克隆PDB高(受read only窗口约束)不需要dump文件低,一条DDL完成同版本或兼容版本的PDB级复制
expdp/impdp取决于导出的时间点需要中间dump空间中,要维护导出参数跨平台、跨小版本
RMAN duplicate可指定SCN,一致性高需要备份集或通道较高,需辅助实例整库或大规模迁移

这个对比不是我拍的脑袋,而是从运维手感上总结的。就我个人的体验而言,PDB远程克隆在两边数据库版本都比较新、网络没有太大瓶颈时,速度非常可观。一次性DDL敲下去,剩下就是等它跑完,不用像expdp那样盯着日志和进程,也不用像rman那样指定一长串参数。

1.3 技术原理一句话讲清楚

远程克隆的原理并不复杂:目标CDB通过数据库链接访问源CDB,读取源PDB的元数据信息,并基于源PDB的数据文件在目标端重建出新的数据文件集。对目标端来说,这是一个CREATE PLUGGABLE DATABASE操作,涉及控制文件、数据字典、临时文件等多个对象的新增。由于源PDB在克隆期间必须处于READ ONLY状态,所以数据块在读取时是稳定一致的。

理解了这一点,就能想明白为什么dblink用户要有特殊权限,为什么要检查路径和空间,以及为什么源PDB不能有运行中的写事务。后面所有步骤都是围绕这些约束展开的。

2. 前置检查与条件准备

2.1 版本与参数硬性要求

在做任何操作之前,应该先把版本和参数确认一遍。我习惯在源库和目标库都执行下面这条SQL,确认数据库版本和compatible参数:

SELECT name, version, open_mode, compatible FROM v$cdb;

远程克隆对版本的最低要求是Oracle 12c,实际19c上最成熟。source和target的compatible参数最好都是19.x,避免一些edge case。目标CDB必须开启归档模式,因为创建PDB会产生大量redo和归档日志。检查方式:

SELECT log_mode FROM v$database;

另一个容易被忽视的点是本地undo模式。从12.2开始推荐使用local undo,19c默认也是。如果源PDB使用的还是shared undo,远程克隆前要把整个CDB的undo改成local模式,否则克隆语句可能因为undo表空间不一致报错。我遇到过源端还是shared undo的情况,克隆过程直接提示无法在共享undo模式下执行,改成local undo并重启CDB后才恢复正常。验证local undo的命令:

SELECT property_name, property_value FROM database_properties WHERE property_name LIKE 'LOCAL_UNDO%';

2.2 RAC多节点与存储检查

RAC环境下,“PDB在所有节点都打开”和“PDB在某一个节点打开”是两码事。远程克隆前,要确认源PDB在所有实例上都是READ ONLY,或者至少在后续访问路径覆盖到的实例上都保持READ ONLY。用这条SQL能一眼看清:

SELECT inst_id, con_id, name, open_mode FROM gv$pdbs ORDER BY inst_id;

输出中如果某些实例的open_mode是READ WRITE,克隆就会失败或数据不一致。所以我的习惯是,干脆一步到位把PDB在所有实例上CLOSE后再统一OPEN READ ONLY。

存储方面,目标CDB的ASM磁盘组必须有足够空间容纳新PDB的数据文件。计算方式是:查询源PDB的数据文件总和,再看目标端磁盘组的FREE_MB:

SELECT SUM(bytes)/1024/1024 AS pdb_data_mb FROM cdb_data_files WHERE con_name = 'PRODPDB'; -- 目标端查看磁盘组容量 SELECT group_number, name, free_mb FROM v$asm_diskgroup;

RAC中不要只检查当前所在节点,还要确认磁盘组在所有节点都可见。ASM磁盘组在集群中本来就是全局共享的,但归档目录、闪回区这些参数实际上是CDB级的,也要确认目标端的路径配置没问题。

2.3 权限与账号规划

权限是初做克隆经常卡住的一环。dblink连接源端用的账号不能是SYS,并且需要在CDB根容器里拥有CREATE PLUGGABLE DATABASE权限。通常我建议在源端建一个专用的公共用户:

CREATE USER c##clone_admin IDENTIFIED BY "Long_Pass_2024" CONTAINER=ALL; GRANT CREATE PLUGGABLE DATABASE TO c##clone_admin CONTAINER=ALL; GRANT CONNECT TO c##clone_admin CONTAINER=ALL;

目标端执行克隆的账号,同样要有CREATE PLUGGABLE DATABASE权限。生产环境我一般避免直接使用SYS账号跑这种操作,而是创建管理用户,这样从审计和权限控制角度都更清晰。

网络服务名也要提前配好。远程克隆面向的目标,是通过SCAN监听器暴露出来的CDB服务。TNSNAMES里一般写成:

PROD19CDB = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = prod-scan.example.internal)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED)(SERVICE_NAME = PROD19CDB)) )

注意SERVICE_NAME必须指向CDB的根服务,而不是某个PDB的service。

3. 远程克隆完整实操

3.1 把源PDB切成READ ONLY窗口

整个克隆最关键的一步,就是给源PDB做一个短暂的只读窗口。以本文例子来说,源库CDB19P里的PDB叫PRODPDB,目标库CDB19T里要建一个TESTPDB。

先确认当前状态:

SELECT instance_name, status FROM gv$instance;

然后关闭PDB再以只读方式打开:

ALTER PLUGGABLE DATABASE PRODPDB CLOSE IMMEDIATE; ALTER PLUGGABLE DATABASE PRODPDB OPEN READ ONLY;

这里要特别提醒:CLOSE IMMEDIATE会等待正在执行的事务结束,如果源库压力很大,可能迟迟关不掉。建议提前和业务方确认窗口,或者在低峰期操作。PDB关闭后再打开时,原来登录的连接需要重连,这个也要提前通知相关人员。

只读打开后,立刻再确认一次:

SELECT inst_id, name, open_mode FROM gv$pdbs WHERE name = 'PRODPDB';

确保每个实例上都是READ ONLY,再继续往下走。

3.2 创建数据库链接并验证

在目标库CDB19T上执行:

CREATE DATABASE LINK PROD_LINK CONNECT TO c##clone_admin IDENTIFIED BY "Long_Pass_2024" USING 'PROD19CDB';

创建后一定要验证。我用下面几条命令来确认dblink是否真的能用、能看到哪些信息:

SELECT name, con_id, open_mode FROM v$pdbs@PROD_LINK; SELECT dbid, name, cdb FROM v$database@PROD_LINK;

如果第一条能返回源库的PDB列表,说明连接成功。如果报连接失败、监听无效之类的错误,先是查网段、监听、TNS配置,不要急着往下执行克隆。数据库链接失败的常见原因很多,通常我会先测试监听通不通,再用tnsping确认服务名解析,最后用sqlplus手工连一下那个service,逐步缩小范围。

3.3 执行CREATE PLUGGABLE DATABASE

确认无误后,在目标库CDB19T上运行克隆语句。最简单的写法是:

CREATE PLUGGABLE DATABASE TESTPDB FROM PRODPDB@PROD_LINK CREATE_FILE_DEST = '+DATA';

如果源库不是OMF管理,或者你想把数据文件放到指定路径,也可以用FILE_NAME_CONVERT:

CREATE PLUGGABLE DATABASE TESTPDB FROM PRODPDB@PROD_LINK FILE_NAME_CONVERT = ('+DATA/CDB19P/DATAFILE', '+DATA/CDB19T/DATAFILE');

补充一句:PATH_PREFIX和STORAGE参数一般按需使用。比如想限制新PDB的最大空间,就用STORAGE (MAXSIZE 20G),达到限制时Oracle会告警或报错,这个在测试环境里比较实用。

执行后,如果看到“Pluggable database TESTPDB created.”的输出,说明克隆本身已经成功。克隆耗时取决于数据量、网络带宽和存储性能。我在一个500GB级别的PDB上做过验证,跨机房远程克隆大概二十多分钟;如果是同机房或同一存储层面,几分钟就能出结果。

3.4 打开新PDB并接入服务

克隆完成后,新PDB默认是MOUNTED状态,需要手动打开:

ALTER PLUGGABLE DATABASE TESTPDB OPEN;

然后查看状态:

SELECT con_id, name, open_mode, restricted FROM v$pdbs WHERE name = 'TESTPDB';

打开后建议执行SAVE STATE,让PDB在RAC每个实例重启时都按当前模式自动打开:

ALTER PLUGGABLE DATABASE TESTPDB SAVE STATE;

接下来给PDB创建对外服务。在RAC环境中我一般用srvctl管理:

srvctl add service -db cdb19t -service testpdb_svc -pdb TESTPDB srvctl start service -db cdb19t -service testpdb_svc

这样应用就可以通过TESTPDB的service name连接了。注意如果目标CDB里已经有同名服务,要先删掉或改名。

最后别忘了回到源库,把源PDB恢复到读写模式:

ALTER PLUGGABLE DATABASE PRODPDB CLOSE; ALTER PLUGGABLE DATABASE PRODPDB OPEN READ WRITE;

3.5 克隆结果快速验证

克隆之后千万别只盯着open_mode。我习惯做两个快速验证:第一,切换到新PDB容器里看表空间和文件信息:

ALTER SESSION SET CONTAINER = TESTPDB; SELECT tablespace_name, status FROM dba_tablespaces; SELECT name, bytes/1024/1024 AS mb FROM v$datafile;

第二,抽样对比源端和目标端的核心表记录数。不用全量比对,挑两三张业务大表,分别加count(*)查一下数量级是否一致。虽然短时间内源数据可能有变化,但数量级对不上就一定有问题。这一步能拦住很多由于dblink状态不一致导致的隐性数据错误。

4. RAC环境下的四个关键细节

4.1 多实例状态一致性是最容易翻车的地方

RAC下最容易被绊倒的点就是实例级状态不一致。上面我用gv$pdbs检查了源PDB的实例状态,这里再讲细一点。Oracle 19c的PDB允许按实例独立打开,节点1上PDB可能是READ WRITE,节点2上可能是MOUNTED,节点3上也许READ ONLY。远程克隆要求源PDB保持READ ONLY,那到底是哪个“实例层面”的READ ONLY?

实际经验告诉我,克隆时Oracle对数据一致性的判断是全局的。如果一个节点还在READ WRITE,另一个节点READ ONLY,跑完克隆后新PDB大概率有隐患,轻则部分对象查不到,重则打开时报一堆一致性问题。所以,操作前必须用gv$pdbs把所有实例的状态都确认一遍,不要只盯着当前节点看。我见过不少同事栽在这个点上,想着“当前节点已经是只读了”,结果克隆出来一打开就报错。

4.2 数据文件与ASM路径规划

RAC加ASM是19c环境最常见的一个组合。ASM路径形如+DATA/CDB19T/DATAFILE/xxx.dbf。远程克隆时,目标端新建PDB的数据文件会落在目标CDB所属的磁盘组里。用CREATE_FILE_DEST指定磁盘组即可,Oracle会自动命名文件并维护痕迹。

如果要用FILE_NAME_CONVERT,要注意:源端路径必须是PDB数据文件在ASM里的真实目录,目标端路径也必须指向目标CDB的磁盘组。路径写错时,最常见的报错是文件无法创建、目录不存在这类提示。在实际项目里,错误路径一旦写进去,Oracle可能会创建一些空文件甚至在ASM目录里留下脏数据,所以操作前还是认真确认路径。

在ASM里查看路径的方式:

asmcmd ls +DATA/CDB19T/DATAFILE

RAC的两个节点看到的是同一套ASM磁盘组,所以路径是全局一致的。但要注意:如果目标CDB的数据文件在+DATA,而归档在+ARCH,克隆只是生成数据文件,并不会重新规划日志和归档,所以新PDB的日志文件仍沿用CDB的配置。

4.3 服务与负载均衡配置

RAC环境中,PDB往往需要跨节点提供服务。新建的PDB默认对所有实例可见,但service的负载均衡和故障切换需要通过Service做到。srvctl添加service后,可以把service绑定到多个节点,指定预期负载:

srvctl add service -db cdb19t -service testpdb_svc -pdb TESTPDB -preferred CDB19T1,CDB19T2

如果两个节点资源不太均衡,也可以只绑定某一个节点,或者设置failover优先级。配置完成后,应用连接串里用service name而不是实例名,这样当节点重启时,连接能自动漂移,DBA不用改任何东西。

4.4 和备份恢复的衔接

克隆出来的PDB是一个全新PDB,RMAN感知到的会和源CDB里已有的备份记录完全无关。所以记得在目标CDB上重新配置RMAN备份。我会习惯性地:

rman target / CONFIGURE RETENTION POLICY TO REDUNDANCY 2; BACKUP PLUGGABLE DATABASE TESTPDB;

如果目标CDB之前已经在跑全库备份策略,那只要保证新的PDB包含在备份命令里即可。RMAN会识别并自动将其纳入备份。这一点很容易被忽略,但测试环境往往就是因为没有及时备份,等真要恢复时就没了。

5. 常见问题与排查实录

5.1 源PDB状态不对导致克隆失败

最典型的报错是ORA-65102:source PDB is not opened in read only mode。排查方式很简单,回到源库执行:

SELECT inst_id, name, open_mode FROM gv$pdbs;

如果发现某个节点还是READ WRITE,就执行:

ALTER PLUGGABLE DATABASE PRODPDB CLOSE IMMEDIATE; ALTER PLUGGABLE DATABASE PRODPDB OPEN READ ONLY;

有时候已经执行了READ ONLY,但某个实例上状态是“READ ONLY WITH APPLY”或“MIGRATE”,那也最好恢复到单纯的READ ONLY,避免不必要的麻烦。

5.2 dblink连不通

dblink连不通的问题在远程克隆项目里出现频率很高。一般分三层排查:第一,源端监听是否正常,SCAN listener和node listener都确认一下;第二,TNSNAMES里service name是否正确,指向的是CDB root;第三,源端账号密码和权限是否足够。

我最常用的快速验证方法是:

tnsping PROD19CDB sqlplus c##clone_admin@PROD19CDB

如果能连上去,再回到数据库里跑一下:

SELECT COUNT(*) FROM v$pdbs@PROD_LINK;

如果这条都能返回,说明dblink完全可用。如果不行,那就照着“监听-服务名-账号权限”三个方向逐步排查。

5.3 空间不足或文件路径错误

克隆过程中报错提示磁盘空间不够,或者ASM无法创建数据文件,通常就是目标端磁盘组容量不够。我一般会提前用源端的实际用量去估算目标端需要的空间,公式很简单:源PDB各表空间数据文件总和,再乘上1.2的冗余系数。RAC加ASM情况下,还要考虑镜像冗余(normal冗余或external冗余),这一点可以从v$asm_diskgroup的type列看到。如果磁盘组不够,要么扩容,要么把新PDB放到另一个更大的磁盘组。

路径错误的表现则是直接报文件无法创建、目录不存在。我的建议是尽量用CREATE_FILE_DEST而不是FILE_NAME_CONVERT,从机制上让Oracle自动决定路径,能少踩很多坑。

5.4 字符集兼容性

字符集也是我实际踩过的坑。源PDB如果用的是ZHS16GBK,目标CDB用AL32UTF8,克隆一般没问题,因为AL32UTF8对ZHS16GBK的兼容性较好。反过来,如果源端是AL32UTF8,目标端是ZHS16GBK,很可能在克隆后查询出现乱码,极端情况直接报错。

所以我的前置检查清单里始终有一条:

SELECT property_value FROM database_properties WHERE property_name = 'NLS_CHARACTERSET';

在源和目标都执行一次,确认兼容再开始动PDB。

5.5 权限不足与公共用户处理

dblink连接时,如果提示ORA-01017,通常是密码或账号不对;如果提示ORA-01031,是权限不足。远程克隆要求连接用户拥有CREATE PLUGGABLE DATABASE权限。

还有一个容易忽略的点:Oracle要求dblink连接用户不能是SYS。很多人图省事直接使用SYS账号建立dblink,结果克隆时会遇到一堆奇怪错误。老老实实建一个c##用户,给需要的最小权限,是最省心的方案。

5.6 排查思路的通用套路

多次排查后,我给自己定了一套固定套路:先看状态,后看网络,再看权限,最后才查SQL。状态用gv$pdbs和v$pdbs看;网络用tnsping和sqlplus验证;权限用grant检查和连接测试;最后才回到克隆语句本身检查参数。按这个顺序走,基本能覆盖绝大多数问题。如果还不行,就去翻告警日志:

tail -200 $ORACLE_BASE/diag/rdbms/cdb19t/cdb19t1/trace/alert_cdb19t1.log

告警日志里通常有更底层的错误原因,比在SQL层面瞎猜要快得多。

6. 克隆后运维与扩展用法

6.1 参数与资源管理

新PDB打开后,不代表工作就做完了。我一般会对克隆出来的测试PDB做三件事:第一,检查SGA/PGA分配是否超出预期,19c可以按PDB级别设置SGA_TARGET,做法是ALTER SYSTEM SET sga_target=... CONTAINER=CURRENT;第二,给PDB设置资源管理计划,限制它在高峰期与生产环境抢资源;第三,确认temp表空间大小合理,测试环境跑复杂SQL时临时空间不够是很常见的坑。

这些设置不影响PDB数据本身,但对后续长期使用体验影响很大。测试环境如果一开始不限制资源,几套克隆PDB叠在一起,很快会把整个CDB主机资源吃满。

6.2 可刷新PDB做定期同步

如果需求是“每隔一段时间就要一份和源端一致的数据”,可以考虑在19c中使用Refreshable PDB。它的本质是在远程克隆之后,继续保留dblink连接,通过定期执行刷新操作,让测试PDB持续获得源PDB的增量数据。

我能想到的实现方式是:

CREATE PLUGGABLE DATABASE TESTPDB FROM PRODPDB@PROD_LINK ... REFRESH MODE EVERY 12 HOURS;

之后每次刷新都会自动从源端拉取变更,避免每次手工重新克隆。这种方式尤其适合BI测试、报表开发这种需要接近实时数据的场景。当然它也有局限:源PDB在刷新时通常需要保持READ ONLY,如果源库要长期读写,还是得用其他同步手段。

6.3 清理与生命周期管理

测试PDB用完后要清理,避免占着存储。清理动作很简单:

ALTER PLUGGABLE DATABASE TESTPDB CLOSE; DROP PLUGGABLE DATABASE TESTPDB INCLUDING DATAFILES;

如果只是临时验证,我建议在创建时用STORAGE限制大小,并且给PDB设置一个明确的生命周期标记,比如在名称里带上日期,方便后续批量清理。RAC环境下,DROP后同时要在srvctl里删除相关service,否则服务配置还会残留:

srvctl remove service -db cdb19t -service testpdb_svc

6.4 观察克隆进度的高效方法

克隆一个几百GB的PDB时,坐在那里等是一件很焦虑的事。我通常用动态视图看克隆会话在做什么:

SELECT sid, serial#, opname, target, sofar, totalwork, elapsed_seconds FROM v$session_longops WHERE opname LIKE '%PDB%' ORDER BY sid;

另外也可以看当前会话的等待事件,判断瓶颈在网络上还是在存储写入上。如果长时间卡在网络等待,基本可以确定是带宽不够;如果卡在db file sequential read,那就要看目标磁盘组的I/O能力。这两种情况处理方式完全不同。

最后,说一点个人的感受:远程克隆PDB这个功能做得好,好在它把“复制一个数据库”从复杂的运维操作降格成一条DDL。但越是看起来简单,越需要把前置检查和RAC细节理顺,否则出错时排查链路反而更长。核心技术本身的原理并不神秘,值钱的是一步步避开那些只有真正做过才能总结出的坑。我在实际工作中把这套流程固化成了一张检查清单,每次操作前过一遍,很多问题在发生前就被拦住了。

这段内容从场景选型、前置条件、实操过程到RAC细节和排错方法都覆盖了,基本可以当作战术手册来用。如果你手头正好有一套19c RAC要做测试库,按这个流程走一遍,会比无头苍蝇一样试错高效得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询