本文由 dbaplus 社群授权转载。
一、背景
随着 Oracle 11g 进入扩展支持阶段,Oracle 19C 作为 12C 家族中最终稳定版,已被多数公司熟知及应用于生产。本人所在公司也在尝试对 19C 进行部署、测试、升级、迁移,于是借此机会将热克隆这个特性做了一番测试。
二、使用热克隆的前提
1、需要 12C R2 及以上版本
在 12C R1 中,要克隆 PDB,源 PDB 必须在克隆操作期间处于静止状态,因此它需要源 PDB 停机,通俗的讲这是种“冷克隆”。
从 12C R2 及以后的版本中开始支持“热克隆”,即 Oracle 数据库支持使用联机克隆的功能。当源 PDB 以读写方式打开的状态下,完全不需要中断源 PDB 中的操作,无须应用程序停机,就可以进行克隆操作。
2、必须使用 local undo
当使用 share undo 的情况下,需要将 share undo 转成 local undo 后才可以使用热克隆。可以在 upgrade 模式下用 alter database local undo on 进行转换。
三、工作原理
从下面三张图可以看出不管是本地克隆、远程克隆,还是 non-cdb 克隆,都是类似 rman 方式进行备份恢复。热克隆会有以下 3 个阶段:
第一阶段:当热克隆开始时(t0),对源 PDB 的数据文件按块进行读取,直到源 PDB 最后一个块被读取并将其复制到目标 PDB 时(t1),此时 t0-t1 时间段内可能对已经复制的一些块进行了更改。那么,在此阶段,目标 PDB 可能与源 PDB 在物理上不一致。
第二阶段:将 t0-t1 之间对源 PDB 所做的更改传至目标 PDB,进行重做应用。在此阶段,目标 PDB 将成为 t1 时源 PDB 的物理副本,但这里即包括了已提交的事务,也包括未提交的事务,因此可能在事务上不一致。
第三阶段:截止至 t1 时,源 PDB 中包含所有已提交的事务,所有未提交的事务将进行回滚,目标 PDB 将是截至 t1 时源 PDB 的事务一致的副本。由此可见,实现热克隆的关键是本地撤销,因此热克隆必须使用 local undo。
图 1 本地 PDB 克隆
图 2 远程 PDB 克隆
图 3 远程 non-cdb 克隆
四、常见应用场景
1、本地克隆
1)通过 seed 模板克隆
此方式主要应用于使用 seed 模板创建一个全新的 PDB。
① 查看 pdb 的状态
SYS@ora19c>show pdbs;
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ---------------- -------------- ----------
2 PDB$SEED READ ONLY NO
复制代码
② 查看 seed 模板的 datafile
SYS@ora19c>select con_id,name from v$datafile where con_id=2;
CON_ID NAME
---------- ------------------------------------------------------------
2 /u01/app/oracle/oradata/ORA19C/pdbseed/system01.dbf
2 /u01/app/oracle/oradata/ORA19C/pdbseed/sysaux01.dbf
2 /u01/app/oracle/oradata/ORA19C/pdbseed/undotbs01.dbf
复制代码
③ 利用 seed 模板进行新 PDB 的克隆,无需对源库执行任何操作,指定数据文件转换目录映射
SYS@ora19c>CREATE PLUGGABLE DATABASE pdb1 ADMIN USER pdb_mgr1 IDENTIFIED BY oracle roles=(dba) file_name_convert=('/u01/app/oracle/oradata/ORA19C/pdbseed','/u01/app/oracle/oradata/ORA19C/pdb1');
Pluggable database created.
复制代码
④ 打开新的 PDB 进行验证
SYS@ora19c>show pdbs;
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 PDB1 MOUNTED
SYS@ora19c>alter pluggable database pdb1 open;
Pluggable database altered.
SYS@ora19c>show pdbs;
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 PDB1 READ WRITE NO
SYS@ora19c>select con_id,name from v$datafile where con_id=3;
CON_ID NAME
---------- -----------------------------------------------------------------
3 /u01/app/oracle/oradata/ORA19C/pdb1/system01.dbf
3 /u01/app/oracle/oradata/ORA19C/pdb1/sysaux01.dbf
3 /u01/app/oracle/oradata/ORA19C/pdb1/undotbs01.dbf
复制代码
2)克隆一个已存在的 PDB
此方式常用于将已存在的 PDB 快速的在本地创建镜像,拥有与源 PDB 完全相同的数据、结构、用户、权限等。
① 将刚创建的 PDB1 创建一个 u1 用户并授权,验证克隆是否会克隆用户及权限
SYS@ora19c>alter session set container=pdb1;
Session altered.
SYS@ora19c>create user u1 identified by oracle;
User created.
SYS@ora19c>grant connect,resource to u1;
Grant succeeded.
复制代码
② 通过已存在的 PDB1 克隆出 PDB2,源库可以在 read write 模式下直接进行操作
SYS@ora19c>show pdbs;
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 PDB1 READ WRITE NO
SYS@ora19c>create pluggable database pdb2 from pdb1 file_name_convert=('pdb1','pdb2');
Pluggable database created.
SYS@ora19c>show pdbs;
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 PDB1 READ WRITE NO
4 PDB2 MOUNTED
复制代码
③ 打开新创建的 PDB 进行验证
SYS@ora19c>alter pluggable database pdb2 open;
Pluggable database altered.
SYS@ora19c>select con_id,name from v$datafile where con_id=4;
CON_ID NAME
---------- -----------------------------------------------------------------
4 /u01/app/oracle/oradata/ORA19C/pdb2/system01.dbf
4 /u01/app/oracle/oradata/ORA19C/pdb2/sysaux01.dbf
4 /u01/app/oracle/oradata/ORA19C/pdb2/undotbs01.dbf
复制代码
④ 验证克隆的新库是否存在源库的用户及权限
SYS@ora19c>conn u1/oracle@192.168.8.101/pdb2
Connected.
U1@192.168.8.101/pdb2>select * from session_privs;
PRIVILEGE
----------------------------------------
SET CONTAINER
CREATE INDEXTYPE
CREATE OPERATOR
CREATE TYPE
CREATE TRIGGER
CREATE PROCEDURE
CREATE SEQUENCE
CREATE CLUSTER
CREATE TABLE
CREATE SESSION
U1@192.168.8.101/pdb2>select * from session_roles;
ROLE
--------------------------------------------------------
CONNECT
RESOURCE
SODA_APP
复制代码
2、远程克隆
1)克隆远程已存在的 PDB
此方式常用于将已存在的 PDB 快速的在异机之间创建镜像,拥有与源 PDB 完全相同的数据、结构、用户、权限等。
①源库 pdb_mgr1 用户授 create pluggable database 权限
SYS@ora19c>alter session set container=pdb1;
Session altered.
SYS@ora19c>grant create pluggable database to pdb_mgr1;
Grant succeeded.
复制代码
② 目标 CDB 中创建 db link
SYS@ora19c>create public database link lk_pdb1 connect to pdb_mgr1 identified by oracle using '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.8.101)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=pdb1)))';
Database link created.
复制代码
③ 执行远程克隆操作,源库无须进行其它操作,可以在 read write 下操作
SYS@ora19c>CREATE PLUGGABLE DATABASE pdb1_r FROM pdb1@lk_pdb1 file_name_convert=('pdb1','pdb1_r');
Pluggable database created.
复制代码
④ 打开新创建的 PDB 进行验证
SYS@ora19c>alter pluggable database pdb1_r open;
Pluggable database altered.
SYS@ora19c>show pdbs;
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 PDB1_R READ WRITE NO
SYS@ora19c>select con_id,name from v$datafile where con_id=3;
CON_ID NAME
---------- --------------------------------------------------------------
3 /u01/app/oracle/oradata/ORA19C/pdb1_r/system01.dbf
3 /u01/app/oracle/oradata/ORA19C/pdb1_r/sysaux01.dbf
3 /u01/app/oracle/oradata/ORA19C/pdb1_r/undotbs01.dbf
复制代码
2)远程克隆 Non-CDB
此方式常用于 Non-CDB 异机迁移 CDB 生成新的 PDB。
① 查看源库的状态
SYS@noncdb>select name,cdb,con_id from v$database;
NAME CDB CON_ID
--------------------------- --------- ----------
NONCDB NO 0
复制代码
② 源库 pdb_mgr1 用户授 create pluggable database 权限
SYS@noncdb>grant create pluggable database to system;
Grant succeeded.
复制代码
③ 目标 CDB 中创建 db link
SYS@ora19c>create public database link lk_noncdb connect to system identified by oracle using '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.8.101)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=noncdb)))';
Database link created.
SYS@ora19c>select name,cdb,con_id from v$database@lk_noncdb;
NAME CDB CON_ID
--------------------------- --------- ----------
NONCDB NO 0
复制代码
④ 执行 noncdb 的远程克隆
SYS@ora19c>CREATE PLUGGABLE DATABASE noncdb_pdb FROM noncdb@lk_noncdb file_name_convert=('/u01/app/oracle/oradata/NONCDB','/u01/app/oracle/oradata/ORA19C/noncdb_pdb');
Pluggable database created.
复制代码
⑤ 打开新的 PDB 进行验证
SYS@ora19c>show pdbs;
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 PDB1_R READ WRITE NO
5 NONCDB_PDB MOUNTED
SYS@ora19c>alter pluggable database NONCDB_PDB open;
Warning: PDB altered with errors.
复制代码
⑥ open 失败,执行 nocdb to pdb 的脚本
SYS@ora19c>alter session set container=NONCDB_PDB;
Session altered.
SYS@ora19c>@?/rdbms/admin/noncdb_to_pdb.sql
复制代码
⑦ 打开新创建的 PDB 进行验证
SYS@ora19c>alter pluggable database NONCDB_PDB open;
Pluggable database altered.
SYS@ora19c>show pdbs;
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 PDB1_R READ WRITE NO
5 NONCDB_PDB READ WRITE NO
SYS@ora19c>select con_id,name from v$datafile where con_id=5;
CON_ID NAME
---------- ---------------------------------------------------------------------
5 /u01/app/oracle/oradata/ORA19C/noncdb_pdb/system01.dbf
5 /u01/app/oracle/oradata/ORA19C/noncdb_pdb/sysaux01.dbf
5 /u01/app/oracle/oradata/ORA19C/noncdb_pdb/undotbs01.dbf
5 /u01/app/oracle/oradata/ORA19C/noncdb_pdb/users01.dbf
复制代码
五、特殊应用场景
1、子集克隆
从 12.1.0.2 开始,引入了 User Tablespaces,简单的说就是可以按表空间(用户创建的)来克隆 PDB。比如,当前 PDB1 中,用户新建了两个表空间 ts1,ts2,克隆只需要 ts1 表空间中的数据,那么我们可以用 USER_TABLESPACES 子句只克隆 PDB1 中的 ts1 表空间,这样大大的缩短了时间和不必要的空间开销。对于拆分数据也很有用,可以把一个库按照表空间拆分。
语法:
USER_TABLESPACES=ALL 默认,所有表空间都克隆;
USER_TABLESPACES=NONE 所有用户创建的表空间都不克隆;
USER_TABLESPACES=(‘ts1’) 指定只克隆ts1;
USER_TABLESPACES=ALL EXCEPT(‘ts1’) 除了ts1之外,其他表空间都克隆。
1)源库创建表空间 ts1,ts2
SYS@ora19c>create tablespace ts1 datafile '/u01/app/oracle/oradata/ORA19C/pdb1/ts1.dbf' size 10m;
Tablespace created.
SYS@ora19c>create tablespace ts2 datafile '/u01/app/oracle/oradata/ORA19C/pdb1/ts2.dbf' size 10m;
Tablespace created.
复制代码
2)进行子集克隆,只克隆 ts1 表空间
SYS@ora19c>CREATE PLUGGABLE DATABASE pdb1_z FROM pdb1 file_name_convert=('pdb1','pdb1_z') user_tablespaces=('ts1');
Pluggable database created.
复制代码
3)打开新创建的 PDB 进行验证
SYS@ora19c>alter pluggable database pdb1_z open;
Pluggable database altered.
SYS@ora19c>show pdbs;
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 PDB1 READ WRITE NO
4 PDB2 READ WRITE NO
6 PDB1_Z READ WRITE NO
SYS@ora19c>select con_id,name from v$datafile where con_id=6;
CON_ID NAME
---------- ------------------------------------------------------------
6 /u01/app/oracle/oradata/ORA19C/pdb1_z/system01.dbf
6 /u01/app/oracle/oradata/ORA19C/pdb1_z/sysaux01.dbf
6 /u01/app/oracle/oradata/ORA19C/pdb1_z/undotbs01.dbf
6 /u01/app/oracle/oradata/ORA19C/pdb1_z/ts1.dbf
复制代码
仅元数据的子集克隆,使用 no data,创建语法:
create pluggable database pdb_nodata from pdb1 file_name_convert=('pdb1','pdb1_nodata') no data;
复制代码
2、利用可刷新 PDB 的功能进行数据迁移
可刷新 PDB 功能是建立在热克隆的基础之上的。
当生产 PDB 数据量非常大,需要在很短的窗口时间进行数据迁移,当有了可刷新 PDB 和热克隆的功能后,一切将变得简单。无需考虑克隆需要花多长时间,因为源数据库无需停机。当目标 PDB 变得陈旧时,我们可以对其刷新,应用自上次刷新以来积累的所有增量。即使源数据库非常庞大,增量重做通常也将小得多。最后只在需要做割接时将源 PDB 置为 read only 后进行一次增量刷新。
刷新 PDB 须注意以下几点:
源库必须开启归档日志和local undo;
可以手动刷新或者自动定时刷新,但刷新时目标端必须是mounted状态;
在不刷新期间,目标端可以以只读模式打开;
如果需以读写模式打开目标端,则必须将refresh mode设置为none,设置none之后就无法再回退回其它刷新模式;
刷新PDB必须使用dblink,dblink可以指向同一个CDB,也可以指向不同CDB。
1)在目标 PDB 创建 db link
SYS@ora19c>create public database link lk_pdb1 connect to pdb_mgr1 identified by oracle using '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.8.101)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=pdb1)))';
Database link created.
复制代码
2)通过 db link 创建 refresh PDB
SYS@ora19c>CREATE PLUGGABLE DATABASE pdb1_ref FROM pdb1@lk_pdb1 file_name_convert=('pdb1','pdb1_ref') REFRESH MODE EVERY 60 MINUTES;
Pluggable database created.
SYS@ora19c>show pdbs;
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 PDB1_R READ WRITE NO
4 PDB1_REF MOUNTED
5 NONCDB_PDB READ WRITE NO
复制代码
3)当 PDB 处于 REFRESH 模式时只能有 mounted 和 read only 两种状态
SYS@ora19c>alter pluggable database pdb1_ref open;
alter pluggable database pdb1_ref open
*
ERROR at line 1:
ORA-65341: cannot open pluggable database in read/write mode
SYS@ora19c>alter pluggable database pdb1_ref open read only;
Pluggable database altered.
SYS@ora19c>select pdb_id,pdb_name,refresh_mode from cdb_pdbs;
PDB_ID PDB_NAME REFRES
2 PDB$SEED NONE
4 PDB1_REF AUTO
5 NONCDB_PDB NONE
3 PDB1_R NONE
复制代码
4)PDB 只能在 mounted 状态下使用 REFRESH 功能
SYS@ora19c>alter pluggable database refresh;
alter pluggable database refresh
*
ERROR at line 1:
ORA-65025: Pluggable database PDB1_REF is not closed on all instances.
Alert log:
PDB1_REF(4):PDB1_REF(4):ERROR:PDB needs to be closed for auto refresh
PDB1_REF(4):Completed: alter pluggable database refresh
复制代码
5)源 PDB 创建测试数据
U1@192.168.8.101/pdb1>create table t1 as select * from dba_objects;
Table created.
U1@192.168.8.101/pdb1>select count(*) from t1;
COUNT(*)
----------
72359
复制代码
6)模拟应用侧停应用,将源端 PDB 置为 read only
SYS@ora19c>alter pluggable database pdb1 close immediate;
Pluggable database altered.
SYS@ora19c>alter pluggable database pdb1 open read only;
Pluggable database altered.
复制代码
7)目标端手动刷新,应用最近的增量,观察目志是否正常
SYS@ora19c>alter pluggable database pdb1_ref refresh;
Pluggable database altered.
Alert log:
2020-02-19T13:23:44.457060+08:00
alter pluggable database pdb1_ref refresh
2020-02-19T13:23:45.940479+08:00
Applying media recovery for pdb-4099 from SCN 2793352 to SCN 2793357
Remote log information: count-1
thr-1, seq-12, logfile-/u01/app/oracle/product/db_1/dbs/archparlog_1_12_4aa635f6_1029786031.arc, los-2752894, nxs-18446744073709551615
PDB1_REF(4):Media Recovery Start
2020-02-19T13:23:45.942469+08:00
PDB1_REF(4):Serial Media Recovery started
PDB1_REF(4):max_pdb is 9
2020-02-19T13:23:45.996021+08:00
PDB1_REF(4):Media Recovery Log /u01/app/oracle/product/db_1/dbs/archparlog_1_12_4aa635f6_1029786031.arc
2020-02-19T13:23:46.257650+08:00
PDB1_REF(4):Incomplete Recovery applied until change 2793357 time 02/19/2020 13:23:09
2020-02-19T13:23:46.264473+08:00
PDB1_REF(4):Media Recovery Complete (ora19c)
Completed: alter pluggable database pdb1_ref refresh
复制代码
8)目标端 PDB 关闭刷新模式
SYS@ora19c>ALTER PLUGGABLE DATABASE pdb1_ref REFRESH MODE NONE;
Pluggable database altered
复制代码
9)拉起目标端 PDB
SYS@ora19c>ALTER PLUGGABLE DATABASE pdb1_ref open read write;
Pluggable database altered.
SYS@ora19c>show pdbs;
CON_ID CON_NAME OPEN MODE RESTRICTED
2 PDB$SEED READ ONLY NO
3 PDB1_R MOUNTED
4 PDB1_REF READ WRITE NO
5 NONCDB_PDB MOUNTED
复制代码
10)应用连接新 PDB,校验业务
SYS@ora19c>conn u1/oracle@192.168.8.102/pdb1_ref
Connected.
U1@192.168.8.102/pdb1_ref>select count(*) from t1;
COUNT(*)
----------
72359
复制代码
六、热克隆中常见的错误
错误一:
ORA-65040: operation not allowed from within a pluggable database
解决方法: alter session set container=cdb$root;
错误二:
ORA-17628: Oracle error 1031 returned by remote Oracle server
ORA-01031: insufficient privileges
解决方法: 到源库里对用户授create pluggable database权限即可。
错误三:
ORA-19504: failed to create file '/u01/app/oracle/oradata/ORA19C/pdb1'
ORA-27038: created file already exists
解决方法: 文件映射路径问题,将“文件夹—文件夹”或“文件—文件”进行一一对应。
错误四:
ORA-65005: missing or invalid file name pattern for file-/u01/app/oracle/oradata/ORA19C/pdb1/system01.dbf
解决方法: 路径错误或注意路径中的大小写。
错误五:
ORA-01578: ORACLE data block corrupted (file # 72, block # 33609)
ORA-01110: data file 72: '/u01/app/oracle/oradata/ORA19C/pdb1_ref/system01.dbf'
ORA-26040: Data block was loaded using the NOLOGGING option
解决方法: 创建可刷新PDB时,源端未开启归档模式。
七、小结
热克隆的方式目前都已经比较成熟,并且可以灵活使用,适合多种应用场景。既可以应用于快速创建生产环境的完整副本或子集副本,也可以应用于较短停机时间的迁移。业务中断时间短,甚至无需业务中断,操作简单,不易出错,但某些场景下对环境要求较高。
作者介绍:
王毅斌, 新炬网络数据库专家。精通 Oracle、MySQL 等数据库运维技术,拥有 Oracle OCM、MySQL OCP 等认证,具有丰富的系统架构设计、数据迁移等经验,擅长 Oracle SQL 优化,参与多个电信行业核心系统的优化。
原文链接:
https://mp.weixin.qq.com/s?__biz=MzI4NTA1MDEwNg==&mid=2650791392&idx=1&sn=b44a752c58c8818de6577b5c9ea1fd67&chksm=f3f96875c48ee163af6813d4d509ee8bfc313fbdf000c58efda3766fb241a6e66be4f71c8b05&scene=27#wechat_redirect
评论