最近在帮一个客户做xtts升级迁移,持续了有段时间了,今天就说说xtts升级迁移的大致流程、迁移过程中遇到的问题以及问题的处理过程。
进入正题前,我们先来看看迁移工具tts吧,tts就是传输表空间,将表空间从源端传输到目标端,而xtts是tts的改良版,在tts的基础上实现了跨平台以及增量备份恢复。xtts迁移的基本步骤如下:

接下来我们再来看看几种常见的迁移方案:(图片来自互联网,侵删)
数据泵

GoldenGate

XTTS

然后我们看下以上几种方案的比较:

下面我将借着这次给客户做的xtts迁移案例,列出xtts迁移的具体流程,客户的环境:源端AIX 6.1 oracle 10.2.0.4 目标端exadata x8m oracle 19.8
源端信息收集
1、确认需要传输的用户
| select username,user_id,account_status,created from dba_users order by 2 asc; |
查出源端所有用户后,一般情况下需要和客户确认哪些用户需要传输,假设这里需要传输的用户为user_a,user_b,user_c,user_d。
2、确认需要传输的表空间以及表空间的大小
SET HEAD ON SET FEEDBACK ON BREAK ON REPORT COMPUTE SUM LABEL'Total Spaces' OF total_m ON REPORT COMPUTE SUM LABEL'Total Spaces' OF free_m ON REPORT COMPUTE SUM LABEL'Total Spaces' OF used_m ON REPORT col tablespace format a25 col ext_mgt format a8 col seg_mgt format a8 col status format a7 set feedback off select b.tablespace_name tablespace, b.total_m, b.free_m, b.used_m, b.used_pct from dba_tablespaces a, (select d.tablespace_name tablespace_name, round((d.sumbytes/1024/1024),2) total_m, round(decode(f.sumbytes,null,0,f.sumbytes)/1024/1024,2) free_m, round(((d.sumbytes-decode(f.sumbytes,null,0,f.sumbytes))/1024/1024),2)used_m, round((d.sumbytes-decode(f.sumbytes,null,0,f.sumbytes))*100/d.sumbytes,2)used_pct from (select tablespace_name, sum(bytes) sumbytes from dba_free_space group by tablespace_name) f, (select tablespace_name, sum(bytes) sumbytes from dba_data_files group by tablespace_name) d where f.tablespace_name(+) =d.tablespace_name order by d.tablespace_name) b where a.tablespace_name=b.tablespace_name and a.tablespace_name not in ('SYSTEM','SYSAUX','UNDOTBS1','UNDOTBS2') --根据实际情况调整 order by 5; |
这一步的目的是提前准备存储用于存放源端备份文件,以及确认目标端所需存储的大小,源端数据量大的情况下这里建议如果同平台则可以使用共享存储的方式,避免网络传输消耗大量时间,如果是异构平台,可以使用NAS挂载的方式。假设这里需要传输的表空间为tbs_a,tbs_b,tbs_c,tbs_d。
3、检查是否存在用户自定义无法迁移的对象
col owner for a10 col segment_name for a50 col segment_type for a20 set linesize 150 pagesize 10000 select owner,segment_name, segment_type from dba_segments where tablespace_name in ('SYSTEM', 'SYSAUX') and owner not in (select username from dba_users where user_id < 57); --根据实际情况调整 |
有些开发在使用数据库的时候可能不是特别规范,将对象的默认表空间指定为了system或者sysaux,而这两个表空间在xtts迁移过程中是不会传输的,所以如果上面sql查询有结果就需要对这些对象先处理(移动到需要传输的表空间中)。
4、源端用户权限收集
查看自己创建的角色: select * from user$ where type# = 0 and name not in ('PUBLIC', '_NEXT_USER'); SELECT DBMS_METADATA.GET_DDL('ROLE','XXX') FROM DUAL; 查看角色的授权: SELECT CASE WHEN D.ADMIN_OPTION = 'YES' THEN 'GRANT ' || d.privilege || ' TO ' || d.GRANTEE || ' WITH GRANT OPTION ;' ELSE 'GRANT ' || d.privilege || ' TO ' || d.GRANTEE || ';' END priv, 'DBA_SYS_PRIVS' FROM dba_sys_privs d WHERE D.GRANTEE in ('XXX');
SELECT CASE WHEN D.ADMIN_OPTION = 'YES' THEN 'GRANT ' || d.GRANTED_ROLE || ' TO ' || d.GRANTEE || ' WITH GRANT OPTION;' ELSE 'GRANT ' || d.GRANTED_ROLE || ' TO ' || d.GRANTEE || ';' END priv, 'DBA_ROLE_PRIVS' FROM DBA_ROLE_PRIVS d WHERE D.GRANTEE in ('XXX'); SELECT CASE WHEN d.grantable = 'YES' THEN 'GRANT ' || d.privilege || ' ON ' || d.owner || '.' || d.table_name || ' TO ' || d.GRANTEE || ' WITH GRANT OPTION ;' ELSE 'GRANT ' || d.privilege || ' ON ' || d.owner || '.' || d.table_name || ' TO ' || d.GRANTEE || ';' END priv, 'DBA_TAB_PRIVS' FROM DBA_TAB_PRIVS d WHERE D.GRANTEE in ('XXX'); 查看用户的权限: SELECT CASE WHEN D.ADMIN_OPTION = 'YES' THEN 'GRANT ' || d.privilege || ' TO ' || d.GRANTEE || ' WITH GRANT OPTION ;' ELSE 'GRANT ' || d.privilege || ' TO ' || d.GRANTEE || ';' END priv, 'DBA_SYS_PRIVS' FROM dba_sys_privs d WHERE D.GRANTEE in ('USER_A','USER_B','USER_C','USER_D') order by grantee;
SELECT CASE WHEN D.ADMIN_OPTION = 'YES' THEN 'GRANT ' || d.GRANTED_ROLE || ' TO ' || d.GRANTEE || ' WITH GRANT OPTION;' ELSE 'GRANT ' || d.GRANTED_ROLE || ' TO ' || d.GRANTEE || ';' END priv, 'DBA_ROLE_PRIVS' FROM DBA_ROLE_PRIVS d WHERE D.GRANTEE in ('USER_A','USER_B','USER_C','USER_D') order by grantee;
SELECT CASE WHEN d.grantable = 'YES' THEN 'GRANT ' || d.privilege || ' ON ' || d.owner || '.' || d.table_name || ' TO ' || d.GRANTEE || ' WITH GRANT OPTION ;' ELSE 'GRANT ' || d.privilege || ' ON ' || d.owner || '.' || d.table_name || ' TO ' || d.GRANTEE || ';' END priv, 'DBA_TAB_PRIVS' FROM DBA_TAB_PRIVS d WHERE D.GRANTEE in ('USER_A','USER_B','USER_C','USER_D') order by grantee; |
5、 临时表空间和undo表空间信息收集
select tablespace_name,sum(bytes)/1024/1024/1024 size_GB from dba_temp_files group by tablespace_name; select file_name,bytes/1024/1024 MB from dba_data_files where tablespace_name like '%UNDO%'; |
6、 判断表空间是否自包含
execute sys.dbms_tts.transport_set_check('TBS_A,TBS_B,TBS_C,TBS_D',true); col violations fora100 select * from sys.transport_set_violations; |
有自包含对象需要进行提前处理(将涉及到的对象移动到system表空间中),表分区跨越了多个表空间就不再自包含了,索引在其他表空间也会不自包含。
7、 源端收集tns、listener、sqlnet配置
8、 源端dblink信息收集
select * from dba_db_links; select dbms_metadata.get_ddl('DB_LINK','XXX','SYS') from dual; |
源端配置
9、 NAS挂载
关于nas挂载的client端以及server端有很多种情况,主要根据源端目标端的空间大小而定,比如源端和目标端都没有多余的空间用于中间磁盘的划分,那么这时候server端可能就是一个nas存储,源端和目标端都作为client端,分别通过nfs挂载即可。下图(图片来自官方文档)为各平台rac情况下详细的挂载参数:

注:AIX平台需要修改如下参数:
# nfso -p -onfs_use_reserved_ports=1; |
为了解决nfs目录导出报错,需要设置10298事件:
| alter system set events '10298 trace name context forever, level 32'; |
挂载目录最好使用二级目录例如:/mig/xtts,并且由于源端和目标端的oracle用户id可能不一致,所以在源端和目标端分别看/mig/xtts目录的时候,属主属组可能是不一致的,所以后续分别在源端和目标端操作的时候,每次都需要先修改/mig/xtts的属组和属主。
cd mig/xtts mkdir tmp mkdir data |
10、 源端全备前开启BCT
alter database enable block change tracking using file '/+DATA/ORACLE_SID/rman_trace.log'; --路径根据实际情况而定 select filename from v$block_change_tracking; |
注意如果源端为rac环境,那么rman_trace.log需要放在共享存储上。
11、 源端创建到目标端的dblink
这一步主要用于后面恢复完成之后的对象状态和数量的比对。
create database link to_target connect to system identified by password using 'xxx.xx.x.x:1521/oracle_sid'; --根据实际情况而定 |
目标端配置
12、 目标端dbca建库
字符集和源端库保持一致,sga、pga、process、db_files(建议1024)不小于源端环境,SID可根据实际情况而定。
13、 目标端配置tns、listener、sqlnet
14、 目标端创建临时表空间及profile
15、 目标端修改undo表空间大小
16、 目标端调整redo log
备份恢复阶段
17、 上传并配置xtts脚本
这里使用的是xtts 4.3
unzip rman_xttconvert_v4.3.zip; |
vi xtt.properties tablespaces=TBS_A,TBS_B,TBS_C,TBS_D platformid=6 --源端平台ID src_scratch_location=/mig/xtts/data --源端备份目录 dest_datafile_location=+DATA/oracle_sid/datafile --目标端最终数据文件存放目录 dest_scratch_location=/mig/xtts/data --目标端恢复目录 parallel=8 rollparallel=8 getfileparallel=8 |
xtt.properties作为xtts最核心的配置文件,我们来看看各个参数分别代表的含义:


18、 源端进行第一次数据库全备
export TMPDIR=/mig/xtts/tmp nohup perl xttdriver.pl --backup -d 3 > full_backup.log & |
注意全备前需要检查源端环境rman备份的并行参数,因为xtts的配置文件xtt.properties中的parallel参数只是用于控制转换数据文件(源端和目标端数据文件字节序的转换)的并行度,而源端rman备份的并行度是由源端环境中rman的配置决定的。
19、 目标端进行第一次全备恢复
cd mig/xtts/tmp/ chmod 777 * cd mig/xtts/data/ chmod 777 * cd mig/xtts/ export TMPDIR=/mig/xtts/tmp nohup $ORACLE_HOME/perl/bin/perl xttdriver.pl --restore -d 3 > full_restore.log & |
20、 源端进行增量备份(进行多次)
cd /mig/xtts/ export TMPDIR=/mig/xtts/tmp nohup perl xttdriver.pl --backup -d 3 > incr_backup1.log & |
21、 目标端进行增量恢复(进行多次)
cd mig/xtts/tmp/ chmod 777 * cd mig/xtts/data/ chmod 777 * cd mig/xtts/ export TMPDIR=/mig/xtts/tmp nohup $ORACLE_HOME/perl/bin/perl xttdriver.pl --restore -d 3 > incr_restore1.log & |
22、 源端导出元数据,全局临时表,public对象
create directory mig_dir as '/mig/xtts/data'; 导出元数据: vi expdp_xtts_other.par schemas=USER_A,USER_B,USER_C,USER_D directory=mig_dir dumpfile=xtts_other_%U.dmp logfile=expdp_xtts_other.log metrics=y exclude=TABLE,INDEX,CONSTRAINT,COMMENT,MATERIALIZED_VIEW,MATERIALIZED_VIEW_LOG,sequence parallel=2 expdp \'\/ as sysdba\' parfile=expdp_xtts_other.par 导出全局临时表: select owner,table_name from dba_tables where temporary='Y' and owner in('USER_A','USER_B','USER_C','USER_D'); --先查出有哪些全局临时表 vi exp_xtts_tmp.par file=xtts_tmp.dmp log=expdp_xtts_tmp.log metrics=y tables=('xxx.xxxxxx') exp \'\/ as sysdba\' parfile=expdp_xtts_tmp.par 源端导出public对象: vi expdp_xtts_public.par include=db_link:"IN(select DB_LINK from dba_db_links where owner='PUBLIC')",PUBLIC_SYNONYM full=y directory=mig_dir dumpfile=xtts_public.dmp logfile=expdp_xtts_public.log metrics=y expdp \'\/ as sysdba\' parfile= expdp_xtts_public.par |
23、 目标端导入元数据,全局临时表,public对象
create directory mig_dir_imp as '/mig/xtts/data'; 目标端导入元数据: vi impdp_xtts_other.par directory=mig_dir_imp dumpfile=xtts_other_%U.dmp full=y logfile=impdp_xtts_other.log EXCLUDE=TABLESPACE,PROCOBJ,RLS_CONTEXT,RLS_GROUP,RLS_POLICY,TABLESPACE_QUOTA metrics=y remap_tablespace= TBS_A:system, TBS_B:system, TBS_C:system, TBS_D:system impdp \'\/ as sysdba\' parfile=impdp_xtts_other.par 目标端导入全局临时表: imp \'\/ as sysdba\' file=xtts_tmp.dmp full=y log=imp_xtts_tmp.log 目标端导入public对象: impdp \'\/ as sysdba\' directory=mig_dir_imp dumpfile=xtts_public.dmp logfile=impdp_xtts_public.log metrics=y |
最终切换上线
24、 源端停止业务,禁用job,停监听,重启数据库
25、 源端将表空间置为read only
alter tablespace TBS_A read only; alter tablespace TBS_B read only; alter tablespace TBS_C read only; alter tablespace TBS_D read only; |
26、 源端进行最后一次增量备份
cd /mig/xtts/ export TMPDIR=/mig/xtts/tmp nohup perl xttdriver.pl --backup -d 3 > incr_backup_final.log & |
27、 源端导出传输表空间元数据
vi expdp_xtts_metadata.par directory=mig_dir dumpfile=xtts_metadata%U.dmp filesize=1048576000 logfile=expdp_xtts_metadata.log metrics=y transport_tablespaces=TBS_A,TBS_B,TBS_C,TBS_D expdp \'\/ as sysdba\' parfile=expdp_xtts_metadata.par |
28、 源端导出sequence
vi expdp_xtts_seq.par schemas=USER_A,USER_B,USER_C,USER_D directory=mig_dir dumpfile=xtts_seq_%U.dmp logfile=expdp_xtts_seq.log metrics=y include=sequence parallel=2 expdp \'\/ as sysdba\' parfile=expdp_xtts_seq.par |
29、 目标端进行最后一次增量恢复
cd mig/xtts/tmp/ chmod 777 * cd mig/xtts/data/ chmod 777 * cd mig/xtts/ export TMPDIR=/mig/xtts/tmp $ORACLE_HOME/perl/bin/perl xttdriver.pl --restore -d 3 > incr_restore_final.log & |
30、 目标端导入传输表空间元数据
vi impdp_xtts_metadata.par directory=mig_dir_imp dumpfile=xtts_metadata%U.dmp logfile=impdp_xtts_metadata.log metrics=y transport_datafiles= '+DATA/ORACLE_SID/DATAFILE/TBS_A.dbf', '+DATA/ORACLE_SID/DATAFILE/TBS_B.dbf', '+DATA/ORACLE_SID/DATAFILE/TBS_C.dbf', '+DATA/ORACLE_SID/DATAFILE/TBS_D.dbf' impdp \'\/ as sysdba\' parfile=impdp_xtts_metadata.par |
31、 目标端sequence导入
cd mig/xtts/data/ chmod 777 * cd mig/xtts/tmp/ chmod 777 * vi impdp_xtts_seq.par directory=mig_dir_imp dumpfile=xtts_seq_%U.dmp full=y logfile=impdp_xtts_seq.log metrics=y impdp \'\/ as sysdba\' parfile=impdp_xtts_seq.par |
32、 目标端执行授权脚本
33、 目标端表空间置为read write
alter tablespace TBS_A read write; alter tablespace TBS_B read write; alter tablespace TBS_C read write; alter tablespace TBS_D read write; |
34、 修改用户默认表空间
alter user USER_A default tablespace TBS_A ; alter user USER_B default tablespace TBS_B ; alter user USER_C default tablespace TBS_C ; alter user USER_D default tablespace TBS_D ; |
35、 编译无效对象
SQL>@?/rdbms/admin/utlrp.sql |
36、 比对源端和目标端对象状态和数量
select owner,object_type,count(*) from dba_objects where owner in ('USER_A','USER_B','USER_C','USER_D') and object_type!='INDEX' group by owner,object_type minus select owner,object_type,count(*)from dba_objects@to_target where owner in('USER_A','USER_B','USER_C','USER_D') and object_type!='INDEX' group by owner,object_type; |
37、 启动监听,启动业务,并进行业务验证
迁移过程中问题记录
据客户描述AIX到NAS存储和一体机到NAS存储之间都是万兆网,为了测试网络传输速度能达到多少,我在进行全备测试之前先进行了文件拷贝的速度测试,测试结果如下:
一体机--->NAS存储 cp/mv 14G 42s (多次测试都是40秒左右)
NAS存储--->一体机 cp/mv 14G 42s (多次测试都是40秒左右)
AIX--->NAS存储 cp/mv 14G 240s (多次测试都是240秒左右)
NAS存储--->AIX cp/mv 14G 240s (多次测试都是240秒左右)
tablespaces=TBS_XXX platformid=6 src_scratch_location=/mig/xtts/data dest_datafile_location=+DATA/oracle_sid/datafile dest_scratch_location=/mig/xtts/data parallel=4 rollparallel=4 getfileparallel=4 |
测试结果为632G的表空间全备需要将近3小时,网络传输速度大概在60M/s左右,按照这个速度8T的数据量全备的时间将近39小时,这显然是不能接受的。问题在于生产环境和NAS存储之间是万兆网,但为什么传输速度只有60M/s左右呢?
实际全备测试的传输速度和我一开始拷贝文件的速度基本是一致的,不应该啊,我明明开了4个并行,理论上一个进程速度是60M/s,那么四个进程至少也得有200多M/s啊。
下面是全备测试过程中的相关截图:

测试过程中持续观察发现en14网卡的流量一直在60--80M之间

也的确是万兆网络


上面两张图分别是aix和一体机到NAS存储的路由情况,可以看出也是一样的。
那到底是为什么呢?
接下来我查看了xtts全备时的日志,关键部分截图如下:

从日志里看出了问题,我前面明明配置了4个并行,为什么这里rman在进行备份的时候,只开了一个channel呢?是什么原因导致并行没有生效呢?为了验证是因为并行没有生效才导致传输速度上不去,我在进行全备的过程中,又开了一个窗口,从AIX本地复制大文件到NAS存储,这样一来就等于模拟了并行,果不其然在拷贝开始之后网络流量马上就从原来的60M/s增长到150多M/s如下图:

到目前为止基本定位到了问题的原因:xtts备份的过程中配置文件中parallel=4的参数没有生效,导致rman全备的时候是单进程在工作,所以慢也是可以理解的,接下来继续查官方文档,终于找到了答案:

这篇文档中对parallel参数的描述很清楚,parallel参数只用于控制转换数据文件(源端和目标端数据文件字节序的转换)的并行度,而源端rman备份的并行度是由源端环境中rman的配置决定的,接下来在生产环境验证:
rman target show all; |

从上图看一看到生产环境中rman备份的并行度默认是1,到此真相大白了。
将rman备份的并行度参数修改为4:
| RMAN>configure device type disk parallelism 4; |


再次发起数据库全备,632G表空间由原来的3小时候备份完提升到70分钟备份完,虽然时间还不是特别快,但目前只开了4个并行,后续可以根据生产的压力相应的做调整。
开启4个并行的情况下,网卡流量由最初的60M/s提升到270M/s左右

最后观察xtts备份的日志:

rman备份的时候,的确是开启了4个并行,至此问题解决,但还有一个疑惑的点,最后我们再回到文件拷贝测试的那一部分,明明都是万兆网络,明明都是单进程在干活,为什么14G的文件,一体机到NAS存储的拷贝只需要42秒,而AIX到NAS存储的拷贝却要240秒呢?
答案是磁盘的能力不同,AIX的磁盘跟一体机的存储相比性能差太多了,那么单进程在读取拷贝不同性能的磁盘的时候,速度也是不一样的。




