生产上遇到一个迁移场景,大概1T数据量左右,由于没用XTTS做过迁移,所以准备尝试一下,本次迁移采用XTTS(增强传输表空间) V3版本的DBMS_FILE_TRANSFER方式。
一、源库及目标库情况
从目标库及源库情况来看,选用XTTS并不是个好选择。XTTS主要还是用在跨平台、跨版本且数据量大的场景下,当前的场景:服务器间网络传输速率高用DataPump的netlink方式最简单,用DG停机时间可以做到最短。
源库 | 目标库 | |
---|---|---|
IP地址 | 10.0.11.XXX | 10.0.14.XXX |
系统版本 | CentOS 5.7 | CentOS Linux release 7.6.1810 (Core) |
数据库版本 | 11.2.0.3.0 | 11.2.0.4.181016 (28204707) |
字符集 | AL32UTF8 | AL32UTF8 |
实例名 | XKORG | XKORG |
CPU | 16 | 16 |
内存(GB) | 32 | 32 |
数据量GB | 1000 |
要迁移的表空间:USERS、ORCLTBS
二、文档及脚本
mos 1389592.1
使用rman_xttconvert_v3.zip脚本
文档及脚本放到网盘中,公众号回复XTTS获取网盘地址
三、迁移流程
3.1 前置条件检查
XTTS使用限制较多,V3版本按照本节逐项检查
3.1.1 目标库操作系统不能为Window
源库:CentOS 5.7 目标库:CentOS Linux 7.6.1810
3.1.2 源库必须在10.2.0.3 版本或以上
代码语言:javascript复制sqlplus -v
源库版本:Release 11.2.0.3.0 Production
3.1.3 源库的compatible 兼容性参数在 10.2.0 或以上
代码语言:javascript复制show parameter compatible
检查结果:11.2.0.0.0
3.1.4 源库的compatible 参数必须不能比目标库大(向下兼容)
代码语言:javascript复制show parameter compatible
源库:11.2.0.0.0 目标库:11.2.0.4.0
3.1.5 源库必须处于归档模式
代码语言:javascript复制archive log list
检查结果:已在归档模式下
3.1.6 目标库必须是11.2.0.4或以上
代码语言:javascript复制sqlplus -v
检查结果:11.2.0.4.0
3.1.7 rman备份策略应该是备份到disk
检查结果:
3.1.8 rman备份不能启用压缩
代码语言:javascript复制show all
检查结果:
代码语言:javascript复制CONFIGURE DEVICE TYPE DISK PARALLELISM 1 BACKUP TYPE TO BACKUPSET; # default
3.1.9 要被传输的表空间必须是online不能包含离线的数据文件
代码语言:javascript复制select file_name,online_status from dba_data_files t where t.online_status not in ('ONLINE','SYSTEM');
代码语言:javascript复制select tablespace_name,status from dba_tablespaces t where t.status<> 'ONLINE';
检查结果:均为online状态
3.1.10 源库和目标库字符集需要保持一致(包括国家字符集)
代码语言:javascript复制select * from nls_database_parameters t where t.parameter in ('NLS_CHARACTERSET','NLS_NCHAR_CHARACTERSET');
检查结果:源库、目标库均为:
3.1.11 目标库db_files参数必须大于源库
代码语言:javascript复制show parameter db_files
源库:200 目标库:200 目标库不符合要求,修改
代码语言:javascript复制alter system set db_files=500 scope=spfile;
3.1.12 确定SYS及SYSTEM下是否存在业务对象
见3.2.2
3.1.13 SYS、SYSTEM 用户是否有对象存在于业务表空间
见3.2.2
3.1.14 检查是否存在外部表
代码语言:javascript复制SELECT DISTINCT owner FROM DBA_EXTERNAL_TABLES;
select owner, TABLE_NAME, DEFAULT_DIRECTORY_OWNER, DEFAULT_DIRECTORY_NAME from DBA_EXTERNAL_TABLES;
检查结果:
3.1.15 检查表加密列信息加密表空间
代码语言:javascript复制SELECT owner, table_name, COUNT(*) FROM DBA_ENCRYPTED_COLUMNS GROUP BY owner, table_name;
SELECT tablespace_name, ENCRYPTED FROM dba_tablespaces WHERE ENCRYPTED = 'YES';
检查结果:
3.1.16 检测数据库时区、TIMEZONE,保证源库目标库一致
代码语言:javascript复制select dbtimezone from dual;
select name,value$ from props$ where name ='DST_PRIMARY_TT_VERSION';
检查结果:源库、目标库均为
3.1.17 源库开启块跟踪,并修改bct隐藏参数
代码语言:javascript复制alter database enable block change tracking using file '/u02/data/XKORG/trace.log';
select status, filename from v$block_change_tracking;
alter system set "_bct_bitmaps_per_file"=100;
启动BCT后,XTTS使用tracking file里的信息,只需要读取改变的数据块信息,而不用再对全部数据文件进行扫描,从而提高了XTTS增量备份的性能。
3.1.18 目标库UNDO表空间配置
搞大点
代码语言:javascript复制select * from v$dbfile;
alter database datafile 3 resize 32766m;
3.1.19 目标库TEMP表空间配置
代码语言:javascript复制alter tablespace TEMP add tempfile '/oradata/datafile/XKORG/temp02.dbf' size 20G autoextend on;
3.1.20 目标库USER表空间配置··
需要传输的表空间中包含USER,需要将目标库USER替换为users_back
代码语言:javascript复制create tablespace users_back datafile '/oradata/datafile/XKORG/users_back.dbf' size 10m;
alter database default tablespace users_back;
drop tablespace users;
3.1.21 源库创建用户表
创建一个单独的用户表,这个表里面存放的是要迁移的用户,在checkobject(迁移完检查源库目标库对象是否一致)脚本与导入临时表的脚本中都会用到这个表create_migrate_useranme.sql
代码语言:javascript复制@/home/oracle/xtts_scripts/create_migrate_username.sql
代码语言:javascript复制--脚本内容
CREATE TABLE SYSTEM.migrate_username
AS
SELECT username
FROM dba_users
WHERE username NOT IN ('ANONYMOUS',
'APEX_030200',
'APEX_PUBLIC_USER',
'APPQOSSYS',
'CTXSYS',
'DBSNMP',
'DIP',
'EXFSYS',
'FLOWS_FILES',
'MDDATA',
'MDSYS',
'MGMT_VIEW',
'OLAPSYS',
'ORACLE_OCM',
'ORDDATA',
'ORDPLUGINS',
'ORDSYS',
'OUTLN',
'OWBSYS',
'OWBSYS_AUDIT',
'SCOTT',
'SI_INFORMTN_SCHEMA',
'SPATIAL_CSW_ADMIN_USR',
'SPATIAL_WFS_ADMIN_USR',
'SYS',
'SYSMAN',
'SYSTEM',
'WMSYS',
'XDB',
'XS$NULL',
'GGADM',
'SPA');
3.1.22 主机hosts文件配置
将源库/ete/hosts文件内容复制到目标环境中
以上条件全部满足,则具备迁移的前置条件
3.2 初始化设置阶段
3.2.1 目标库安装数据库软件并创建数据库,软件版本不小于源库
检查结果:已按要求安装软件并创建数据库,实例名同源库
3.2.2 检查表空间是否自包含
代码语言:javascript复制execute dbms_tts.transport_set_check('USERS,ORCLTBS',true);
select * from transport_set_violations;
我在迁移时候出现非自包含情况,检查发现有分区表及索引存储在SYSTEM表空间中,需要将这部分数据首先移动到业务表空间,详见:【迁移】Oracle分区表及索引迁移表空间(https://www.modb.pro/db/42030) 迁移完成后,检查结果如下:
3.2.3 创建以下对象
- 源端创建复制数据库对象的目录(源库被传输的数据文件存放位置)
create directory source_dir as '/u02/data/XKORG/';
- 目标端创建存放数据库对象的目录(目标库最终数据文件存放位置)
create directory dest_dir as '/oradata/datafile/XKORG/';
3.2.4 目标库创建DBLINK
代码语言:javascript复制create public database link to_old connect to system identified by oracle using '(DESCRIPTION =
(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST = 10.0.11.XXX)(PORT = 1521)))
(CONNECT_DATA = (SERVICE_NAME = XKORG))
)';
验证是否创建成功
代码语言:javascript复制select * from dual@to_old;
3.2.5 源库目录创建
代码语言:javascript复制mkdir /home/oracle/xtts
chown -R oracle:dba /home/oracle/xtts/
上传官方脚本 rman_xttconvert_v3.zip 文件到xtts目录下,并授权
代码语言:javascript复制cd /home/oracle/xtts/
unzip rman_xttconvert_v3.zip
3.2.6 编辑xtt.properties配置文件
修改如下参数
代码语言:javascript复制tablespaces= USERS,ORCLTBS --要迁移的表空间名称
platformid=13 --select platform_id from v$database;
srcdir = SOURCE_DIR --dft时使用,源库存放数据文件的路径
dstdir = DEST_DIR --dft时使用,目标库存放数据文件的路径
srclink=to_old --目标库创建的DBLINK
backupformat=/home/oracle/xtts/bakincr --源端用于存放增量备份的路径
stageondest=/home/oracle/xtts/bak --目标端存放数据文件副本目录,和存放增量备份目录
backupondest=/home/oracle/xtts/bak --目标端增量备份的最终存放目录
parallel= 8
rollparallel= 8 --增量备份的并行度
getfileparallel= 8 --获取文件的并行度
说明:在v$transportable_platform视图中标记了platformid对应的platformname及字节序
源端创建目录
代码语言:javascript复制mkdir -p /home/oracle/xtts/bakincr
mkdir -p /home/oracle/xtts/bak
chown oracle:dba /home/oracle/xtts/bakincr
chown oracle:dba /home/oracle/xtts/bak
目标端创建目录
代码语言:javascript复制mkdir -p /home/oracle/xtts/bak
3.2.7 源端和目标端设置TMPDIR
Oracle用户环境变量
代码语言:javascript复制$export TMPDIR=/home/oracle/xtts
3.2.8 源端将/home/oracle/xtts 下所有文件传给目标端
代码语言:javascript复制scp -P 10011 /home/oracle/xtts/* 10.0.14.XXX:/home/oracle/xtts/
3.3 准备阶段
在这个阶段,表空间数据文件会从源库传输到目标库,并且会做一个自动的字节格式的转换。这个步骤只需要做一次。在此阶段,源端数据库可以正常进行访问。
下图为官方脚本功能说明:
3.3.1 源库执行以下命令
代码语言:javascript复制[oracle@source]$ nohup $ORACLE_HOME/perl/bin/perl xttdriver.pl -S &
这个命令会执行以下动作:
- 确认表空间是 online,read write 模式,不包含 offline 数据文件
- 创建两个文件:xttnewdatafiles.txt,getfile.sql
3.3.2 将第一步产生的两个文件传到目标端
代码语言:javascript复制scp -P 10011 xttnewdatafiles.txt getfile.sql 10.0.14.XXX:/home/oracle/xtts/
3.3.3 目标端执行以下命令
代码语言:javascript复制[oracle@dest]$ nohup $ORACLE_HOME/perl/bin/perl xttdriver.pl -G &
当这一步完成,数据文件将会被传输到目标端最终位置,并且被目标库使用,可见数据文件出现在目标库数据文件存放目录下,相当于将一份全备应用到了目标库。
3.4 前滚阶段
在这个阶段中,源库会创建一个增量备份,传输到备库。并且会转换为目标库字节格式,并应用于目标库。这个阶段可以运行多次,每一个成功的增量备份所花的时间应该比之前的要少,并且使目标库的数据与源库更接近。
3.4.1 源库创建表空间的增量备份集
代码语言:javascript复制nohup perl xttdriver.pl -i &
这个命令会对传输的表空间产生一个增量备份集。备份集位于 backupformat 目录下。并且会产生两个文件:tsbkupmap.txt,incrbackups.txt
3.4.2 传输增量备份集到目标端
代码语言:javascript复制scp -P 10011 'cat incrbackups.txt' 10.0.14.XXX:/home/oracle/xtts/bak/
3.4.3 转换增量备份集并应用到目标库
源端复制xttplan.txt,tsbkupmap.txt 到目标端
代码语言:javascript复制scp -P 10011 xttplan.txt tsbkupmap.txt 10.0.14.XXX:/home/oracle/xtts/
目标端执行以下命令,应用增量备份
代码语言:javascript复制nohup perl xttdriver.pl -r &
3.4.4 确定下次增量备份的scn
源库运行下面脚本, 确定一个新的scn, 记录在 xttplan.txt 文件中
代码语言:javascript复制nohup perl xttdriver.pl -s &
3.4.5 重复前滚阶段(可选)
如果你需要使目标库更接近源库,则需要重复进行1-4 步骤;如果目标库已经足够接近源库,那就直接进行传输阶段。
3.5 传输阶段
在传输阶段,源库需要被设置为read only 模式,目标库会被应用最后一次增量备份。在目标数据文件一致后,将执行一次普通的传输表空间的步骤,从源库导出元数据对象并导入目标库。在此阶段结束之前,源库只能通过 read only 方式访问数据。
3.5.1 目标库导入profile
将资源控制文件profile,通过network_link方式导入目标库
代码语言:javascript复制nohup impdp "/as sysdba" metrics=yes network_link=to_old include=profile full=y content=metadata_only > profile.log 2>&1 &
3.5.2 目标库导入role
将角色通过network_link方式导入目标库
代码语言:javascript复制nohup impdp "/as sysdba" metrics=yes network_link=to_old include=role full=y content=metadata_only > role.log 2>&1 &
3.5.3 确认是否有新用户添加
代码语言:javascript复制select username,created from dba_users where created in (select max(CREATED) from dba_users);
3.5.4 确认是否有新的数据文件添加
代码语言:javascript复制select file#,name,creation_time from v$datafile where creation_time in (select max(creation_time) from v$datafile);
3.5.5 通知客户停业务
从这里开始计算停机时间
3.5.6 源库清理回收站数据
代码语言:javascript复制purge dba_recyclebin;
3.5.7 导出统计信息及DBLINK
关于统计信息有两种处理方式:导出再倒入 或者 目标库重新收集。这里选择重新收集更合理一些,所以可以不导出统计信息,更节省时间。
代码语言:javascript复制nohup expdp "/as sysdba" directory=DUMPDIR dumpfile=stat_dblink.dmp logfile=stat_dblink.log include=statistics,DB_LINK full=y &
这里的directory=DUMPDIR指向一个NAS,该NAS挂载到了源库与目标库。
3.5.8 停服务与修改JOB参数(源库/目标库)
代码语言:javascript复制alter system set job_queue_processes=0;
show parameter job_queue_processes;
3.5.9 源库处理进程
确认无活动事务与死事务,包括分布式事务
代码语言:javascript复制ps -ef| grep LOCAL=NO| grep -v grep| awk '{print $2}'| xargs kill -9
select local_tran_id,state from dba_2pc_pending;
3.5.10 源库创建用户与测试表,插入数据
代码语言:javascript复制create user TEST identified by oracle default tablespace USERS;
grant connect,resource to TEST;
--create_test_table.sql 内容就是创建两个测试表,用于迁移完验证是否在目标库也能查询到
@/home/oracle/xtts_scripts/create_test_table.sql
3.5.11 多次切换归档
代码语言:javascript复制alter system switch logfile;
3.5.12 再次清空回收站
代码语言:javascript复制purge dba_recyclebin;
3.5.13 源库将表空间设置read only
代码语言:javascript复制alter tablespace USERS read only;
alter tablespace ORCLTBS read only;
3.5.14 源库创建最后一次增量备份集,传输、转换、应用到目标库
建议通知客户停业务之前再做一次增量备份应用,以减少数据差异,缩短停业务后的这次增量备时间
代码语言:javascript复制nohup perl xttdriver.pl -i &
scp 'cat incrbackups.txt' 10.0.14.XXX:/home/oracle/xtts/bak/
scp xttplan.txt tsbkupmap.txt 10.0.14.XXX:/home/oracle/xtts/
3.5.15 目标端最后一次应用
代码语言:javascript复制nohup perl xttdriver.pl -r &
3.5.16 创建用户
目标库执行脚本,通过之间创建的dblink,在目标端创建用户,脚本不是自己写的就不放出来了
代码语言:javascript复制@/home/oracle/xtts_scripts/create_user.sql
3.5.17 给create database link权限
给上一步创建的用户加权限 grant create database link to X
代码语言:javascript复制@/home/oracle/xtts_scripts/drm_grant_create_link.sql
3.5.18 开启数据库flashback功能
脚本内容就是开启闪回,创建restore point
代码语言:javascript复制@/home/oracle/xtts_scripts/drm_enable_flashback.sql
3.5.19 导入对象数据到目标库
目标端执行以下命令
代码语言:javascript复制nohup perl xttdriver.pl -e &
这个命令会产生一个DataPump 导入模板文件 xttplugin.txt 。该文件里是impdp的导入模板,编辑并执行导入 注意:
- 可以在impdp语句中加入exclude=TABLE_STATISTICS,INDEX_STATISTICS,排除统计信息,我们后面收集
- 语句中transport_datafiles可能比较多,建议放到par文件中执行
- 查看日志发现触发器警告,可先忽略后续编译处理
- 指定的dump目录第一次执行失败,查询为权限问题 给dump目录加777后解决
3.5.20 禁用FLASHBACK功能
这一步应该放到应用最终测试完成后再执行
代码语言:javascript复制@/home/oracle/xtts_scripts/drm_disable_flashback.sql
3.5.21 查询测试表是否有数据
代码语言:javascript复制@/home/oracle/xtts_scripts/query_test_table_data.sql
查询结果:
3.5.22 目标库设置表空间read write
代码语言:javascript复制select tablespace_name,file_name from dba_data_files;
alter tablespace USERS read write;
alter tablespace ORCLTBS read write;
select TABLESPACE_NAME,status,CONTENTS from dba_tablespaces;
3.5.23 检查物理和逻辑块损坏,并验证数据
该步骤执行时间较长
代码语言:javascript复制RMAN> validate tablespace USERS, ORCLTBS check logical;
3.5.24 导入数据库的元对象
代码语言:javascript复制nohup impdp "/ as sysdba" network_link=to_old SCHEMAS='XXX','XXX' content=metadata_only TABLE_EXISTS_ACTION=SKIP exclude=table,index parallel=8 metrics=y directory=DUMPDIR > imp_meta.log 2>&1 &
3.5.25 导入临时表
代码语言:javascript复制--源库查询无用户自定义临时表
select owner,table_name from dba_tables where TEMPORARY='Y';
如果有的话按下面语句导入
nohup impdp "/ as sysdba" metrics=yes network_link=to_old logfile=temp_table.log schemas='XXX','XXX' include=TABLE:"" in (select table_name from dba_tables where TEMPORARY='Y')"" > imp_tmp.log 2>&1 &"
3.5.26 回收create database link权限
代码语言:javascript复制@/home/oracle/xtts_scripts/drm_revoke_database_link.sql
3.5.27 修改用户默认表空间
还是通过dblink获取
代码语言:javascript复制@/home/oracle/xtts_scripts/alter_user_default_tablespace.sql
Select username,default_tablespace from dba_users;
3.5.28 给角色及对象授权
代码语言:javascript复制select 'grant '||GRANTED_ROLE||' to '||grantee||';' from dba_role_privs where grantee in(select username from dba_users where default_tablespace in ('USERS','ORCLTBS') and user_id >='84');
源库查询后,在目标库执行 对象权限、角色权限、DDL权限 后续执行checkobject.sql脚本时生成后在目标库执行即可
3.5.29 编译无效对象
代码语言:javascript复制DECLARE
threads pls_integer := 150;
BEGIN
utl_recomp.recomp_parallel(threads);
END;
/
3.5.30 对比对象
代码语言:javascript复制@/home/oracle/xtts_scripts/checkobject.sql
select object_type,count(*) as num from dba_objects where owner='MAOTAI' group by object_type order by num desc;
3.5.31 收集(或导入)统计信息及DBLINK
方式1:导入统计信息及dblink 如果在3.5.7小节导出了统计信息,那么这里可以选择导入,但是时间会很长
代码语言:javascript复制nohup impdp "/as sysdba" directory=DUMPDIR dumpfile=stat_dblink.dmp logfile=stat_dblink_i.log include=statistics,DB_LINK full=y &
方式2:手工统计
代码语言:javascript复制select 'EXEC DBMS_STATS.GATHER_TABLE_STATS('''||owner||''','''||table_name||''',estimate_percent=>10,method_opt=>''FOR ALL COLUMNS SIZE AUTO'',degree=>12,cascade=>TRUE);' from dba_tables where owner in('schema1','schema2') ;
源库执行生成语句,编辑一个static.sql文件在目标库执行,此处是按表统计也可选择按schema统计GATHER_SCHEMA_STATS;
代码语言:javascript复制@/home/oracle/xtts_scripts/static.sql
注意:这次迁移最占用时间的步骤来了,一开始estimate 设置为80,但是特别慢,后续改为10,也跑了3个小时才完成,后来咨询大拿,这里其实收集个0.01就可以了,也就是收集0.01%的统计信息。注意并行度16个cpu开到12。
代码语言:javascript复制select sql_id,program,status,state,LAST_CALL_ET from v$session where program like '%P0%' and sql_id is not null order by 3
通过上述语句查询开启的并行进程,LAST_CALL_ET为该进程执行的时间 执行过程中可到v$lock 视图查询是否有锁 TM TX 如果执行过慢,可查询dba_segments bytes字段查询大小
3.5.32 收集字典表统计信息
代码语言:javascript复制EXEC DBMS_STATS.GATHER_DICTIONARY_STATS;
EXEC DBMS_STATS.GATHER_FIXED_OBJECTS_STATS;
3.5.33 源库查询失效对象
迁移后与目标库对比
代码语言:javascript复制set line 1000 pages 500
col owner for a20
col object_name for a50
col object_type for a15
SELECT owner, object_name, object_type,status
FROM dba_objects
WHERE status = 'INVALID' and owner in('schema1','schema2');
select owner,object_name,object_type,status from dba_objects@to_old where object_name in(select object_name from dba_objects where status='INVALID' and owner!='PUBLIC');
3.5.34 目标库打开JOB
代码语言:javascript复制alter system set job_queue_processes=1000;
3.5.35 通知切换IP
3.5.36 启动应用测试
3.5.37 防火墙策略添加
四、应急处置
XTTS迁移方式对源库变动主要是设置要迁移表空间read only,如迁移发现异常,按照如下步骤恢复:
- 假设服务器IP已替换,则首先需要将10.0.13.31IP重新切换到原服务器;
- 设置USERS、ORCLTBS表空间 read write;
alter tablespace USERS read write;
alter tablespace ORCLTBS read write;
- 检查监听状态
- 通知应用启动测试
五、总结
1、实际迁移花费6个小时,消耗时间最多的是收集统计信息耗费3小时,其次是最后一次增量备占用1小时,再次是坏块检查; 2、收集统计信息部分,事后咨询专家后知道其实收集0.01%就可以; 3、设置源库表空间为read only后的增量备时间有点长,现在看应该在停业务前再应用一次增量,应该能再减少这部分时间; 4、检查物理和逻辑块损坏,并验证数据,虽然是极小概率的情况,我觉得还是不要省为好 5、脚本很强大,能省很多时间,有专家用自己写的脚本不用官方脚本