1. 介绍
Transportable Tablespace (TTS)传输表空间,把表空间数据从一个库传输到另外一个库,而XTTS是在TTS基础上进一步增强,支持跨平台和增量备份。
2. XTTS使用的限制条件--参考【Doc ID 1454872.1】
1) 源库软件版本必须是11.2.0.3或更高 2) 源库的 COMPATIBLE 参数必须设置为 10.2.0 或更高。 3) 源库的 COMPATIBLE 参数值不能大于目标库的 COMPATIBLE 参数值。 4) 源库必须处于 ARCHIVELOG 模式。 5) 目标库必须是是11.2.0.4或更高版本 6) rman的默认备份类型必须是DISK。 7) 源库的 RMAN 配置里 DEVICE TYPE DISK 不能设置为 COMPRESSED,否则会抛出ORA-19994错误。 8) 目标库的 COMPATIBLE 参数必须设置为 11.2.0.4 或更高。 9) 要迁移的表空间的数据文件必须都是 online 或者不包含 offline 的数据文件。 10) 源库的oracle版本必须低于或等于目标库 11) 这些步骤都需要使用 OSDBA 组中的 oracle 用户来执行。需要使用 OS 验证的方式来连接源库和目标库。 12) 如果使用dbms_file_transfer进行初始化,则目标端数据库必须是11.2.0.4 13) 这个方法不支持在备库和snapshot备库 14) 这个方法不支持多租户数据库。Enhancement bug 22570430 描述了这个限制。
15)源端的操作系统不能是Windows
16)源端和目标端时区,字符集保持一致
17)目标端db_files比源库大
3. 实例流程步骤
3.1 初始化设置
(1)服务器搭建安装数据库软件和创建实例 (2)rman-xttconvert软件包准备及配置参数($TMPDIR: 保存临时文件目录) (3)检查自包含情况,传输对象是否在系统表空间等 (4)目标库创建用户,角色,profile,临时表,外部表等xtts迁移受限的对象
(5)平台检查
3.2 准备阶段(源库数据仍然在线)
(1)源库rman copy方式全库导出到NAS存储或是NFS存储文件系统 (2)在目标系统恢复数据文件至目标端的 endian 格式
3.3 前滚阶段(源库数据仍然在线)
(1)在源库创建增量备份 (2)把增量备份转换成目标系统的 endian 格式并且把增量备份应用至目标数据文件 (3)(源库)为下次增量备份确定 next_scn (4)重复3.3的步骤直到准备好操作传输表空间
3.4 传输阶段(源库数据表空间置为read only模式)
(1)源库停业务应用,确认数据库无job和事务运行和日志都应用到备库后将源库表空间置为 READ ONLY模式 (2)最后一次执行前滚阶段步骤 (3)源库通过数据泵方式导出元数据(注意:表空间元数据并不包含视图,过程,同义词等对象) (4)目标库导入元数据,并将表空间改成读写模式
3.5 收尾阶段
(1)校验数据 (2)统计信息收集或导入 (3)无效对象重新检查编译 (4)临时表对象导入
4. 实施过程详情
4.1 环境信息
4.2 初始化阶段
1)目标端部署数据库(包括同步源端tns等文件)
2)检查源端数据库对象信息(业务账号对象的表空间依赖性,业务账号及临时表信息)
-- 调用dbms_tts.transport_set_check() exec sys.dbms_tts.transport_set_check(ts_list => 'tablespace_name', incl_constraints => TRUE); -- 查看检查结果 select * from sys.transport_set_violations;
3)挂载目录用于存储源端数据(此处使用NFS)-- 参考MOS(Doc ID 359515.1)文件中参数挂载文件系统
在目标端分配足够存储空间创建文件系统后通过NFS的方式挂载到源端数据库服务器
--源端NAS存储挂在参数 mount -o llock,rw,bg,vers=3,proto=tcp,noac,forcedirectio,hard,nointr,timeo=600,rsize=32768,wsize=32768,suid 127.0.0.1:/dbdump /datadump --目标端 mount -t nfs -o rw,bg,hard,nointr,rsize=32768,wsize=32768,tcp,noac,vers=4,timeo=600,actimeo=0 127.0.0.1:/dbdump /datadump
4)安装XTTS软件
这里选择安装到临时数据目录(即上面NFS的文件系统)
su - oracle unzip -qo /oracle/soft/rman_xttconvert_v3.zip -d /datadump/xtts_dir/ --源库备份文件目录(在 xtt.properties 文件中由 backupformat 参数定义) mkdir -p /datadump/xtts_dir/sourcedir -- 目标系统数据文件目录(在 xtt.properties 文件中由 storageondest 参数定义) mkdir -p /datadump/xtts_dir/destdir -- 修改目录权限 chmod 777 xtts_dir chmod 777 /datadump/xtts_dir/destdir chmod 777 /datadump/xtts_dir/sourcedir -- 编辑配置文件 xtt.properties tablespaces=DEV_DATA,DEV_IDX,DEV_TMP # 需要传输的业务表空间名称列表 platformid=4 # 源端数据库platform id (select PLATFORM_ID from V$DATABASE;) dfcopydir=/datadump/xtts_dir/sourcedir # 源端数据库全备份文件目录 backupformat=/datadump/xtts_dir/sourcedir # 源端增量备份存储目录 stageondest=/datadump/xtts_dir/destdir # 目标端存储源端备份文件的目录 storageondest=+DATA # 目标端最终数据文件目录 backupondest=/datadump/xtts_dir/destdir # 目标端增量备份格式转换后的输出目录 parallel=8 # RMAN的并行数量 rollparallel=2 # 前滚并行度
desttmpdir=/datadump/xtts_dir # 目标端tmpdir目录,建议执行xtts目录,xttdriver.pl产生新文件目录
5)准备用户,角色,profile语句
-- 创建dblink create database link XTTS_DBLINK connect to xtts identified by 'xtts' using '(DESCRIPTION =(ADDRESS_LIST =(ADDRESS =(PROTOCOL = TCP)(HOST = localhsot)(PORT = 1521)))(CONNECT_DATA =(SERVICE_NAME = orcl)))'; -- 目标库创建角色 select 'create role '||role ||';' from dba_roles@XTTS_DBLINK minus select 'create role '||role ||';' from dba_roles; -- 目标库创建用户 select 'create user "'||a.username ||'" identified by values '''||b.password|| ''' default tablespace USERS '|| 'temporary tablespace '|| a.TEMPORARY_TABLESPACE||';' from dba_users@XTTS_DBLINK a,sys.user$@XTTS_DBLINK b, dba_users c,sys.user$ d where a.username=b.name and a.username=d.name(+) and a.username = c.username(+) and c.username is null order by a.username;
4.3 准备阶段
注意:建议禁止同步开始后增加数据文件
4.3.1 方案选择
1)dbms_file_transfer会根据源端的目录结构传送到目标端时配置成相同的目录结构,但是容易触发bug,整个准备阶段的同步过程中容易间断,需要后期使用rman单独数据文件的方式传送失败的数据文件。
2)rman方式目前为止比较稳定,但是它会将所有的数据文件后缀改名为xtf,并且每一个批次的数据文件只能传送到一个目录下。比较适用于asm的情况
4.3.2 源端0级全备
# 源库rman [backup as copy]方式进行0级备份到 xtt.properties 文件中由 dfcopydir 参数定义 export TMPDIR=/datadump/xtts_dir export XTTDEBUG=1 echo $TMPDIR nohup $ORACLE_HOME/perl/bin/perl xttdriver.pl -p -d >full_back.log & chmod -R 777 /datadump/xtts_dir/sourcedir
# 产生xttplan.txt(表空间当前SCN记录), rmanconvert.cmd(记录文件转换的数据文件名称)
4.3.3 目标端还原数据文件
#
su - oracle export TMPDIR=/datadump/xtts_dir export XTTDEBUG=1 echo $TMPDIR nohup $ORACLE_HOME/perl/bin/perl xttdriver.pl -c -d >convert.log &
4.4 前滚阶段
在这个阶段,增量备份会在源库创建,发送到目标系统,转换成目标系统的 endian 格式,应用到目标库数据文件拷贝上并进行前滚。这个阶段可能需要运行很多次。每次增量备份都会比上次的增量备份花费更少的时间,并且把目标系统的数据文件拷贝和源库更贴近。在这个阶段,源库上的数据仍然可以被正常访问。
4.4.1 源库rman 增备
su - oracle export TMPDIR=/datadump/xtts_dir export XTTDEBUG=1 echo $TMPDIR nohup $ORACLE_HOME/perl/bin/perl xttdriver.pl -i -d >incr_1.log & cd /datadump/xtts_dir chmod 777 tsbkupmap.txt chmod 777 incrbackups.txt chmod 777 xttplan.txt mv /datadump/xtts_dir/backup/* /datadump/xtts_dir/dfcopydir chmod 777 /datadump/xtts_dir/dfcopydir
源库对xtt.properties参数文件中指定的表空间进行增量备份,同时会生成 tsbkupmap.txt、 incrbackups.txt、 xttplan.txt三个文件。备份的数据是从做xttdriver.pl -s 时在xttplan.txt文件中记录的SCN开始的。备份完成后需要将这3个文件连同增量备份集一起传输到目标端。
4.4.2 应用增备到目标端数据文件
su - oracle export TMPDIR=/datadump/xtts_dir export XTTDEBUG=1 echo $TMPDIR nohup $ORACLE_HOME/perl/bin/perl xttdriver.pl -r -d >restore_incr1.log &
4.4.3 推进源端增量备份的next_scn
su - oracle export TMPDIR=/datadump/xtts_dir export XTTDEBUG=1 echo $TMPDIR $ORACLE_HOME/perl/bin/perl xttdriver.pl -s -d
该命令产生最新 xttplan.txt 文件(修改FROM_SCN),用于确定下一次增量备份的起点(下次增量备份开始 SCN)。建议在【目标端】每次做完recover动作后, 【源端】就执行一次该命令,以免遗忘。
4.4.4 重复执行前滚阶段步骤,尽量缩少增量备份数据,从而减少停机时间
4.5 传输阶段
注意事项:
1. 元数据导入前,需要在目标端创建业务用户和角色,用户默认表空间需要在导入完成后指定
2. 元数据导入时只导入和指定表空间相关联的对象,存放在系统表空间的对象需要二次导入
3. 导入前需要检查目标端db_files参数是否大于等于源库的值
4. 临时表空间中对象不会随元数据导入而导入,需要提前创建
5. 元数据导入时无法开启并行,耗时比重高
4.5.1 停应用业务
4.5.2 停止源库job
alter system set job_queue_processes=0 scope=both; alter system set aq_tm_processes=0 scope=both; -- 停止JOB回话 select /*+ rule */ * from dba_jobs_running; ====根据情况是否kill当前运行的job select sid, SERIAL#,USERNAME from v$session where sid=507; alter system kill session '507,5,@inst_id' immediate;
4.5.3 源库将表空间置为只读模式
--设置表空间为只读模式 SELECT 'alter tablespace ' || t.tablespace_name || ' read only;' FROM dba_tablespaces t ,dba_data_files f WHERE t.tablespace_name = f.tablespace_name AND t.tablespace_name NOT IN ('SYSTEM' ,'SYSAUX' ,'USERS') AND t.contents = 'PERMANENT' GROUP BY t.tablespace_name ORDER BY COUNT(f.file_id); alter tablespace DEV_DATA read only; alter tablespace DEV_IDX read only; alter tablespace DEV_TMP read only; 对数据文件的OFFLINE操作,为了避免归档文件不存在的情况了,建议执行一次RECOVER操作。 -- 获取recover datafile脚本 SELECT FILE#,ONLINE_STATUS,CHANGE#,ERROR,'recover datafile '|| file# sql_cmd FROM V$RECOVER_FILE; --检查确认 set linesize 168 pagesize 99 col tablespace_name for a24 select tablespace_name,status from dba_tablespaces; SELECT FILE#,ONLINE_STATUS,CHANGE#,ERROR FROM V$RECOVER_FILE;
4.5.4 源库最后一次增备
-- 源库rman 增备
su - oracle
export TMPDIR=/datadump/xtts_dir
export XTTDEBUG=1
echo $TMPDIR
nohup $ORACLE_HOME/perl/bin/perl xttdriver.pl -i >incr_1.log &
cd /datadump/xtts_dir
chmod 777 tsbkupmap.txt
chmod 777 incrbackups.txt
chmod 777 xttplan.txt
mv /datadump/xtts_dir/backup/* /datadump/xtts_dir/dfcopydir
chmod 777 /datadump/xtts_dir/dfcopydir
源库对xtt.properties参数文件中指定的表空间进行增量备份,同时会生成 tsbkupmap.txt、 incrbackups.txt、 xttplan.txt三个文件。备份的数据是从做xttdriver.pl -s 时在xttplan.txt文件中记录的SCN开始的。备份完成后需要将这3个文件连同增量备份集一起传输到目标端。
4.5.5 应用增备文件到目标库
-- 应用增备到目标端数据文件
su - oracle
export TMPDIR=/datadump/xtts_dir
export XTTDEBUG=1
echo $TMPDIR
nohup $ORACLE_HOME/perl/bin/perl xttdriver.pl -r -d >restore_incr1.log &
4.5.6 源库导出元数据
# 1. OS创建目录并修改权限 mkdir -p /datadump/xtts_dir/dmp chown oracle:oinstall /datadump/xtts_dir/dmp chmod 777 /datadump/xtts_dir/dmp # 2. DB创建目录并授权 sqlplus / as sysdba col directory_name for a50 col directory_path for a50 set linesize 300 select directory_name,directory_path from dba_directories; create directory XTTS_DIR as '/datadump/xtts_dir/dmp'; grant read,write on directory XTTS_DIR to sys; # 3. 导出表空间metadata expdp "/ as sysdba" directory=XTTS_DIR dumpfile=xtts_tbs_metadata.dmp transport_tablespaces=DEV_IDX,DEV_IDX,DEV_TMP logfile=xtts_tbs_metadata.log CLUSTER=N exclude=STATISTICS # 4. 导出临时表结构 TMP_TABS=$(echo "set heading off feedback off time off timing off pages 0 lines 200 SELECT trim(owner||'.'||table_name) objs FROM dba_tables WHERE temporary = 'Y' AND owner NOT IN (SELECT owner FROM dba_logstdby_skip);" | sqlplus -S "/ as sysdba"|xargs -n 1000 echo|tr -s ' ' ',') cat > tmptabs.par <<EOF USERID="/ as sysdba" TABLES=(${TMP_TABS}) FILE=temp_tables.dmp LOG=exp_temp_tables.log EOF exp parfile=tmptabs.par rows=y # 5. 检查外部表对象(可选) mkdir -p /tmp/soc/ chown oracle:oinstall /tmp/soc/ create directory SOCDUMP as '/tmp/soc/'; grant read,write on directory SOCDUMP to SOC; expdp expdp "/ as sysdba" dumpfile=LOG.dmp directory=XTTS_DIR tables=soc.log # 6. 物化视图结构(可选) cd /datadump/xtts_dir/dmp TMP_MVS=$(echo "set heading off feedback off time off timing off pages 0 lines 200 SELECT trim(owner||'.'||MVIEW_NAME) objs FROM dba_mviews WHERE owner NOT IN (SELECT owner FROM dba_logstdby_skip);" | sqlplus -S "/ as sysdba"|xargs -n 1000 echo|tr -s ' ' ',') cat > tmpmvs.par <<EOF USERID="/ as sysdba" TABLES=(${TMP_MVS}) FILE=exp_mvs.dmp LOG=exp_mvs.log EOF exp parfile=tmpmvs.par rows=y -- 检查确认文件内容 imp "/ as sysdba" file=exp_mvs.dmp show=y full=y # 7. 目标库导入元数据 chmod 777 /datadump/xtts_dir/dmp sqlplus / as sysdba col directory_name for a50 col directory_path for a50 set linesize 300 select directory_name,directory_path from dba_directories; create directory XTTS_DIR as '/datadump/xtts_dir/dmp'; grant read,write on directory XTTS_DIR to sys; -- 导入表空间metadata(必须先创建用户和角色,及授权) $ORACLE_HOME/perl/bin/perl xttdriver.pl -e --获取全部数据文件列表,获取文件transport_datafiles内容信息 cp xttplugin.txt dmp/impdp_tbs.par nohup impdp parfile=impdp_tbs.par >tbs.out 2>&1 & vi impdp_tbs.par USERID="/ as sysdba" directory=XTTS_DIR dumpfile=xtts_tbs_metadata.dmp logfile=impdp_xtts_tbs_metadata.log CLUSTER=N transport_datafiles='+DATA/orcl/datafile/dev_9.dbf','+DATA/orcl/datafile/dev_idx_11.dbf' exclude=statistics -- 导入用户metadata nohup impdp "/ as sysdba" directory=XTTS_DIR dumpfile=xtts_us_metadata.dmp logfile=imp_xtts_us_metadata.log schemas=dev,soc CLUSTER=N parallel=8 exclude=index,table,constraint >ou.out 2>&1 & # 8. 导入临时表对象 # 9. 外部表 mddir -p /tmp/soc/ chown oracle:oinstall /tmp/soc/ touch /tmp/soc/soc.log create directory SOCDUMP as '/tmp/soc/'; grant read,write on directory SOCDUMP to SOC; impdp "/ as sysdba" dumpfile=LOG.dmp directory=XTTS_DIR tables=soc.log # 10. 目标端将表空间置为读写模式 alter tablespace DEV_DATA read write; alter tablespace DEV_IDX read write; alter tablespace DEV_TMP read write; # 11. 通过rman校验数据传输是否异常 rman target /
validate tablespace DEV_DATA,DEV_IDX,DEV_TMP check logical;
4.6 检查源库和目标库数据一致性
4.6.1 通过DB_LINK检查对象信息
--对比无效对象 select r.owner, r.object_type, r.remote_cnt Source_Cnt, l.local_cnt Target_Cnt from ( select owner, object_type, count(owner) remote_cnt from dba_objects@XTTS_DBLINK where owner not in (select name from system.logstdby$skip_support where action=0) group by owner, object_type ) r , ( select owner, object_type, count(owner) local_cnt from dba_objects where owner not in (select name from system.logstdby$skip_support where action=0) group by owner, object_type ) l where l.owner (+) = r.owner and l.object_type (+) = r.object_type and nvl(l.local_cnt,-1) != r.remote_cnt order by 1, 3 desc; --对比sequence大小 select * from( select a.SEQUENCE_OWNER,a.sequence_name,a.last_number prod_number, b.last_number dr_number,(b.last_number - a.last_number) gap_than_zero from dba_sequences@XTTS_DBLINK a,dba_sequences b where a.sequence_owner not in ('SYS','SYSTEM','XDB','WMSYS','TSMSYS','SYSMAN','PRECISE1', 'ORDSYS','OUTLN','OLAPSYS','ORDPLUGINS','MDSYS','EXFSYS', 'DMSYS','DSG','DBSNMP','PRECISE2','SI_INFORMTN_SCHEMA','SPA','TSMSYS','PUBLIC','GOLDENGATE', 'ORDDATA','PRECISE4','PRECISE3','CTXSYS','SCOTT','PERFSTAT') and a.sequence_owner=b.sequence_owner (+) and a.sequence_name=b.sequence_name(+) order by 5,1,2 desc) where gap_than_zero < 0 ; --检查无效index select owner, index_name, status from dba_indexes where status='UNUSABLE' order by 1,2; select i.owner, i.index_name, p.partition_name, p.status from dba_ind_partitions p,dba_indexes i where p.index_name=i.index_name and p.status='UNUSABLE' order by 1,2,3; select i.owner,i.index_name,s.subpartition_name,s.status from dba_ind_subpartitions s,dba_indexes i where s.index_name=i.index_name and s.status='UNUSABLE' order by 1,2,3;
4.6.2 检查并编译无效对象无效对象
@?/rdbms/admin/utlrp.sql select count(*) from dba_objects where status='INVALID'; select owner,count(*) from dba_objects where status='INVALID' group by owner;
4.6.3 收集统计信息
exec dbms_stats.gather_database_stats(estimate_percent=>100,degree=>30,cascade=>true,granularity=>'AUTO');