Oracle流复制是结合日志挖掘、队列等技术,实现多数据库、异构、远程等环境下数据同步的一种实现方式。主要被用于灵活的复制和容灾解决方案。
Oracle流复制相比较其他数据库同步方式,如Dataguard、Advanced Replication,流复制拥有以下几点显著的优势:
1、灵活的复制策略:可以分别针对数据库、模式、表等不同级别设定复制策略,相比Dataguard必须整个数据库复制而言,可以节省相当的资源。
2、高可用性:在异构环境下(不同的操作系统),Dataguard无法使用,流复制可以充分利用现有的设备与技术。
3、对网络条件的轻度依赖:流复制的传播是经过logmnr挖掘并包装的逻辑变更记录(LCRs),相比Dataguard传送archived redo log、Advanced Replication的mview log与mview刷新的方式,流复制对网络的需求降低了很多。
4、实时性:由监控进程负责实时监控用户操作反应在log当中的记录并传递给目标数据库进行接收,然后转换为实际的操作同步目标数据库,并可根据实际情况调整同步的间隔。
5、对主数据库性能的低影响:相对于其他复制方式,流复制基于对log物理文件进行分析等动作完成,只占用极少部分资源,并且无论流复制执行成功与否,都不会影响到主库的正常使用。
流复制中,源库必须设置为归档模式,如果是双向复制,则源库和目标库都要置于归档模式。
以下给出一个在生产环境中的具体例子来说明流复制技术的运用方法。这里的需求是主服务器数据库的一个名为CMES的模式,包括其表、索引、存储过程代码等对象结构和数据的变更都要求能同步到本地节点的数据库中。
一、搭建流复制环境
1、本地节点的流复制环境搭建
conn / as sysdba
修改实例参数
alter system set global_names=true;
alter system set aq_tm_processes=1;
创建streams表空间
create tablespace streams datafile 'd:\oradata\mes\streams01.dbf' size 200m;
将logminer 的数据字典从system表空间转移到streams表空间
execute dbms_logmnr_d.set_tablespace('streams');
创建strmadmin用户并授权
create user strmadmin identified by strmadmin default tablespace streams quota unlimited on streams;
grant connect, resource, dba, aq_administrator_role to strmadmin;
begin
dbms_streams_auth.grant_admin_privilege(grantee => 'strmadmin',
grant_privileges => true);
end;
/
在tnsnames.ora中添加服务名,指向主服务器端
mes_0 =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = ora11g-1)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = mes)
)
)
创建指向主服务器端的数据库链接
create public database link dl_mes_0 connect to system identified by mesHz2 using 'mes_0';
测试通过数据库链接可以访问到对方主机
select host_name from v$instance@dl_mes_0;
HOST_NAME
----------------------------------------------------------------
ORA11G-1
创建与数据库链接访问同名的global_name
第一个本地节点可命名为dl_mes_1,第二个本地节点可命令为dl_mes_2,以此类推
alter database rename global_name to dl_mes_1;
创建流队列
conn strmadmin/strmadmin
exec dbms_streams_adm.set_up_queue();
创建应用进程
conn strmadmin/strmadmin
begin
dbms_streams_adm.add_schema_rules(schema_name => 'cmes',
streams_type => 'apply',
streams_name => 'apply_streams',
queue_name => 'strmadmin.streams_queue',
include_dml => true,
include_ddl => true,
source_database => 'dl_mes_0',
inclusion_rule => true);
end;
/
2、主服务器端的流复制环境搭建
conn / as sysdba
开启补充日志
alter database add supplemental log data;
修改实例参数
alter system set global_names=true;
alter system set aq_tm_processes=1;
alter system set open_links=10 scope=spfile;
alter system set open_links_per_instance=10 scope=spfile;
创建streams表空间
create tablespace streams datafile 'd:\oradata\mes\streams01.dbf' size 200m;
将logminer的数据字典从系统表空间转移到streams表空间
execute dbms_logmnr_d.set_tablespace('streams');
创建strmadmin用户并授权
create user strmadmin identified by strmadmin default tablespace streams quota unlimited on streams;
grant connect, resource, dba, aq_administrator_role to strmadmin;
begin
dbms_streams_auth.grant_admin_privilege(grantee => 'strmadmin',
grant_privileges => true);
end;
/
在tnsnames.ora中添加指向各个本地节点的网络服务名
第一个本地节点可命名为mes_1,第二个本地节点可命令为mes_2,以此类推,各节点计算机名对应为oraxe11g-1、oraxe11g-2等
mes_1 =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = oraxe11g-1)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = mes)
)
)
创建数据库链接
对应各个本地节点的网络服务名来创建,如dl_mes_1对应mes_1,dl_mes_2对应mes_2
create public database link dl_mes_1 connect to system identified by mesHz2 using 'mes_1';
测试通过数据库链接dl_mes_1、dl_mes_2等可以分别访问到各个节点
select host_name from v$instance@dl_mes_1;
HOST_NAME
----------------------------------------------------------------
ORAXE11G-1
创建与数据库链接访问同名的global_name
alter database rename global_name to dl_mes_0;
创建流队列
conn strmadmin/strmadmin
exec dbms_streams_adm.set_up_queue();
创建捕获进程
conn strmadmin/strmadmin
begin
dbms_streams_adm.add_schema_rules(schema_name => 'cmes',
streams_type => 'capture',
streams_name => 'capture_streams',
queue_name => 'strmadmin.streams_queue',
include_dml => true,
include_ddl => true,
inclusion_rule => true);
end;
/
创建传播进程
conn strmadmin/strmadmin
begin
dbms_streams_adm.add_schema_propagation_rules(schema_name => 'cmes',
streams_name => 'main_to_node1',
source_queue_name => 'strmadmin.streams_queue',
destination_queue_name => 'strmadmin.streams_queue@dl_mes_1',
include_dml => true,
include_ddl => true,
source_database => 'dl_mes_0',
inclusion_rule => true,
queue_to_queue => true);
end;
/
当需要创建多个传播进程向不同节点发布时,需要指定不同的stream_name和destination_queue_name,如以下创建指向第二个本地节点的传播进程
conn strmadmin/strmadmin
begin
dbms_streams_adm.add_schema_propagation_rules(schema_name => 'cmes',
streams_name => 'main_to_node2',
source_queue_name => 'strmadmin.streams_queue',
destination_queue_name => 'strmadmin.streams_queue@dl_mes_2',
include_dml => true,
include_ddl => true,
source_database => 'dl_mes_0',
inclusion_rule => true,
queue_to_queue => true);
end;
/
3、实例化本地节点
根据具体业务,利用数据泵进行导入。这里具体业务是需要创建几个自己的表空间和用户模式,并从主服务器上导入模式数据到本地。
conn / as sysdba
创建表空间
create tablespace cmes datafile 'd:\oradata\mes\cmes01.dbf' size 100m;
create tablespace rmes datafile 'd:\oradata\mes\rmes01.dbf' size 2g;
create tablespace indx datafile 'd:\oradata\mes\indx01.dbf' size 2g;
create tablespace hmes datafile 'd:\oradata\mes\hmes01.dbf' size 2g;
创建RMES、BOSCH、ABS用户并授权
create user rmes identified by rmes default tablespace rmes;
create user bosch identified by huizhong default tablespace rmes;
create user abs identified by huizhong default tablespace rmes;
grant connect,resource to rmes,bosch,abs;
导入主服务器端的CMES模式基础数据
$impdp strmadmin/strmadmin network_link=dl_mes_0 schemas=cmes
导入主服务器端的RMES、BOSCH、ABS模式元数据
$impdp strmadmin/strmadmin network_link=dl_mes_0 schemas=rmes,bosch,abs content=metadata_only
编译无效对象
@?/rdbms/admin/utlrp
4、启动流复制进程
本地节点启动应用进程
conn strmadmin/strmadmin
exec dbms_apply_adm.start_apply('apply_streams');
主服务器端启动捕获进程
conn strmadmin/strmadmin
exec dbms_capture_adm.start_capture('capture_streams');
检查主服务器端警告日志,确认日志捕获的启动
Fri Apr 14 16:47:04 2017
LOGMINER: Begin mining logfile for session 1 thread 1 sequence 40, E:\ARCHIVELOG\MES\ARC_78AE6A4D_1_941117583_40.LOG
Fri Apr 14 16:47:05 2017
LOGMINER: End mining logfile: E:\ARCHIVELOG\MES\ARC_78AE6A4D_1_941117583_40.LOG
Fri Apr 14 16:47:05 2017
LOGMINER: Begin mining logfile for session 1 thread 1 sequence 41, D:\ORADATA\MES\REDO02.LOG
Fri Apr 14 16:47:14 2017
LOGMINER: End mining logfile: D:\ORADATA\MES\REDO02.LOG
Fri Apr 14 16:47:14 2017
LOGMINER: Begin mining logfile for session 1 thread 1 sequence 42, D:\ORADATA\MES\REDO03.LOG
检查本地节点警告日志,确认日志应用的启动
Fri Apr 14 16:46:41 2017
Streams APPLY AP01 for APPLY_STREAMS started with pid=24, OS id=3144
Fri Apr 14 16:46:42 2017
Streams Apply Server for APPLY_STREAMS started AS02 with pid=31 OS id=1768
Fri Apr 14 16:46:42 2017
Streams Apply Server for APPLY_STREAMS started AS03 with pid=32 OS id=2484
Fri Apr 14 16:46:42 2017
Streams Apply Reader for APPLY_STREAMS started AS01 with pid=29 OS id=4040
Fri Apr 14 16:46:42 2017
Streams Apply Server for APPLY_STREAMS started AS04 with pid=35 OS id=756
Fri Apr 14 16:46:42 2017
Streams Apply Server for APPLY_STREAMS started AS05 with pid=36 OS id=740
5、流复制功能验证
测试主服务器端数据库CMES模式的更新,是否能够自动同步到本地节点,包括DML和DDL操作。如未能同步,则检查主服务器端和本地节点的警告日志信息,排查出错原因。
表数据更新
select * from cmes.c_emp_t;
update cmes.c_emp_t t set t.emp_password = '111111' where t.emp_no = 'TEST';
commit;
增加表
create table cmes.c_emp1_t as select * from cmes.c_emp_t;
select * from cmes.c_emp1_t;
修改表结构
alter table cmes.c_emp1_t add remark varchar2(20);
update cmes.c_emp1_t t set t.remark = 'test' where t.emp_no = 'TEST';
commit;
desc cmes.c_emp1_t;
增加索引
create index cmes.idx_emp1_remark on cmes.c_emp1_t(remark) tablespace indx;
select table_name, index_name, index_type, status, tablespace_name from dba_indexes where owner='CMES' and table_name='C_EMP1_T';
删除索引
drop index cmes.idx_emp1_remark;
select table_name, index_name, index_type, status, tablespace_name from dba_indexes where owner='CMES' and table_name='C_EMP1_T';
删除表
drop table cmes.c_emp1_t purge;
select * from cmes.c_emp1_t;
新增存储过程
create or replace procedure cmes.my_test(res out varchar2) as
begin
res := 'OK';
end;
/
更新存储过程
create or replace procedure cmes.my_test(res out varchar2) as
begin
res := 'NOK';
end;
/
删除存储过程
drop procedure cmes.my_test;
6、建立流复制心跳
为监视流复制的工作状态,在主服务器上创建心跳表
create table cmes.streams_hb(hb_name varchar2(20), hb_time varchar2(20)) tablespace cmes;
插入数据
insert into cmes.streams_hb values('dl_mes_0', to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss'));
commit;
创建调度作业,设置为每分钟更新一次心跳时间
conn strmadmin/strmadmin
begin
dbms_scheduler.create_job(job_name => 'strmadmin.job_streams_hb',
job_type => 'plsql_block',
job_action => 'update cmes.streams_hb set hb_time = to_char(sysdate, ''yyyy-mm-dd hh24:mi:ss'') where hb_name = ''dl_mes_0'';',
start_date => sysdate,
repeat_interval => 'freq = minutely; interval = 1',
enabled => true,
auto_drop => false);
end;
/
观察本地节点的心跳表数据是否按心跳时间同步更新
select * from cmes.streams_hb;
HB_NAME HB_TIME
-------------------- --------------------
dl_mes_0 2017-05-09 12:19:47
二、针对表级别的配置说明
如果流复制定义在表级别,则几个进程的创建可采用如下形式。
主服务器端创建表级别的传播进程
begin
dbms_streams_adm.add_table_propagation_rules(table_name => 'scott.emp',
streams_name => 'scott_emp_main_to_node1',
source_queue_name => 'strmadmin.streams_queue',
destination_queue_name => 'strmadmin.streams_queue@dl_mes_1',
include_dml => true,
include_ddl => true,
source_database => 'dl_mes_0',
inclusion_rule => true,
queue_to_queue => true);
end;
/
主服务器端创建表级别的捕获进程
begin
dbms_streams_adm.add_table_rules(table_name => 'scott.emp',
streams_type => 'capture',
streams_name => 'scott_emp_capture_streams',
queue_name => 'strmadmin.streams_queue',
include_dml => true,
include_ddl => true,
inclusion_rule => true);
end;
/
本地节点创建表级别的应用进程
begin
dbms_streams_adm.add_table_rules(table_name => 'scott.emp',
streams_type => 'apply',
streams_name => 'scott_emp_apply_streams',
queue_name => 'strmadmin.streams_queue',
include_dml => true,
include_ddl => true,
source_database => 'dl_mes_0',
inclusion_rule => true);
end;
/
本地节点的实例化
本地节点导入主服务器端的表
$impdp strmadmin/strmadmin network_link=dl_mes_0 schemas=scott include=table:"in('EMP')" table_exists_action=replace
三、流复制配置的删除
停止应用进程
conn strmadmin/strmadmin
exec dbms_apply_adm.stop_apply(apply_name => 'apply_streams');
删除应用进程
conn strmadmin/strmadmin
begin
dbms_apply_adm.drop_apply(apply_name => 'apply_streams',
drop_unused_rule_sets => true);
end;
/
如果删除应用进程时报错应用进程的错误队列必须为空,则需要先删除之前应用进程所有的错误信息,然后再执行删除进程的操作
conn strmadmin/strmadmin
select * from dba_apply_error;
exec dbms_apply_adm.delete_all_errors(apply_name=>'apply_streams');
停止捕获进程
conn strmadmin/strmadmin
begin
dbms_capture_adm.stop_capture(capture_name => 'capture_streams',
force => true);
end;
/
删除捕获进程
conn strmadmin/strmadmin
begin
dbms_capture_adm.drop_capture(capture_name => 'capture_streams',
drop_unused_rule_sets => true);
end;
/
停止传播进程
conn strmadmin/strmadmin
begin
dbms_propagation_adm.stop_propagation(propagation_name => 'main_to_node1',
force => true);
end;
/
删除传播进程
conn strmadmin/strmadmin
begin
dbms_propagation_adm.drop_propagation(propagation_name => 'main_to_node1',
drop_unused_rule_sets => true);
end;
/
删除主服务器端和本地节点的队列及队列表
conn strmadmin/strmadmin
begin
dbms_streams_adm.remove_queue(queue_name => 'STREAMS_QUEUE',
cascade => true,
drop_unused_queue_table => true);
end;
/
删除流配置
conn strmadmin/strmadmin
exec dbms_streams_adm.remove_streams_configuration;
删除流用户
conn / as sysdba
drop user strmadmin cascade;
四、流复制的状态查询
查看创建的流队列和队列表
select owner, name, queue_table, queue_type from dba_queues where owner = 'STRMADMIN';
OWNER NAME QUEUE_TABLE QUEUE_TYPE
---------- ------------------------------ ------------------------------ --------------------
STRMADMIN AQ$_STREAMS_QUEUE_TABLE_E STREAMS_QUEUE_TABLE EXCEPTION_QUEUE
STRMADMIN STREAMS_QUEUE STREAMS_QUEUE_TABLE NORMAL_QUEUE
查看流队列表信息
select owner, queue_table, object_type from dba_queue_tables where owner = 'STRMADMIN';
OWNER QUEUE_TABLE OBJECT_TYPE
---------- ------------------------------ --------------------------
STRMADMIN STREAMS_QUEUE_TABLE SYS.ANYDATA
查看传播进程信息
col destination_dblink for a30
select propagation_name, source_queue_name, destination_queue_name, destination_dblink, status from dba_propagation;
PROPAGATION_NAME SOURCE_QUEUE_NAME DESTINATION_QUEUE_NAME DESTINATION_DBLINK STATUS
------------------------------ ------------------------------ ------------------------------ ------------------------------ ----------
MAIN_TO_NODE2 STREAMS_QUEUE STREAMS_QUEUE DL_MES_2 ENABLED
MAIN_TO_NODE1 STREAMS_QUEUE STREAMS_QUEUE DL_MES_1 ENABLED
查看捕获进程信息
select capture_name, queue_name, start_scn, status, capture_type from dba_capture;
CAPTURE_NAME QUEUE_NAME START_SCN STATUS CAPTURE_TY
------------------------------ ------------------------------ ---------- ---------- ----------
CAPTURE_STREAMS STREAMS_QUEUE 6156463 ENABLED LOCAL
查看应用进程信息
select apply_name,queue_name,status from dba_apply;
APPLY_NAME QUEUE_NAME STATUS
------------------------------ ------------------------------ --------
APPLY_STREAMS STREAMS_QUEUE ENABLED
五、补充说明
1、可以基于Database级别或Table级别启用追加日志(Supplemental Log)
alter database add supplemental log data;
在建立根据Schema粒度进行复制的Oracle Stream环境中,如果确认Schema下所有Table都有合理的主键(Primary Key),则可不需要启用追加日志。
2、根据需要可修改传播进程的休眠时间,如改为0,表示实时传播
begin
dbms_aqadm.alter_propagation_schedule(queue_name => 'streams_queue',
destination => 'dl_mes_1',
destination_queue => 'streams_queue',
latency => 0);
end;
/
3、如果等了很长时间数据还没有复制过来,仔细检查capture/propagation/apply各进程的状态是否有异常。并可尝试修改以下隐含参数并重启
alter system set "_job_queue_interval"=1 scope=spfile;
4、如果本地节点长时间关闭或无法与主服务器端保持网络连接,可能导致主服务器端的传播进程状态变为disabled,此时即便恢复了连接,仍然不能保持正常的同步复制。这种情况可以尝试先停止主服务器端到本地节点的传播进程,然后重新启动传播进程,一般情况下问题都可以得到解决。
查询传播进程状态,发现到dl_mes_2的传播是disabled
select propagation_name, source_queue_name, destination_queue_name, destination_dblink, status from dba_propagation;
PROPAGATION_NAME SOURCE_QUEUE_NAME DESTINATION_QUEUE_NAME DESTINATION_DBLINK STATUS
------------------------------ ------------------------------ ------------------------------ ------------------------------ --------
MAIN_TO_NODE1 STREAMS_QUEUE STREAMS_QUEUE DL_MES_1 ENABLED
MAIN_TO_NODE2 STREAMS_QUEUE STREAMS_QUEUE DL_MES_2 DISABLED
停止该传播进程
begin
dbms_propagation_adm.stop_propagation(propagation_name => 'main_to_node2',
force => true);
end;
/
此时该进程状态变为aborted
select propagation_name, source_queue_name, destination_queue_name, destination_dblink, status from dba_propagation;
PROPAGATION_NAME SOURCE_QUEUE_NAME DESTINATION_QUEUE_NAME DESTINATION_DBLINK STATUS
------------------------------ ------------------------------ ------------------------------ ------------------------------ --------
MAIN_TO_NODE1 STREAMS_QUEUE STREAMS_QUEUE DL_MES_1 ENABLED
MAIN_TO_NODE2 STREAMS_QUEUE STREAMS_QUEUE DL_MES_2 ABORTED
重启传播进程
exec dbms_propagation_adm.start_propagation(propagation_name => 'main_to_node2');
查看状态已恢复正常
select propagation_name, source_queue_name, destination_queue_name, destination_dblink, status from dba_propagation;
PROPAGATION_NAME SOURCE_QUEUE_NAME DESTINATION_QUEUE_NAME DESTINATION_DBLINK STATUS
------------------------------ ------------------------------ ------------------------------ ------------------------------ --------
MAIN_TO_NODE1 STREAMS_QUEUE STREAMS_QUEUE DL_MES_1 ENABLED
MAIN_TO_NODE2 STREAMS_QUEUE STREAMS_QUEUE DL_MES_2 ENABLED
5、如果本地节点应用进程状态变为abort,可尝试以下操作
停止应用进程
exec dbms_apply_adm.stop_apply(apply_name => 'apply_streams');
查看应用进程的报错信息
select * from dba_apply_error;
在确认错误已排除后,删除错误信息
exec dbms_apply_adm.delete_all_errors(apply_name=>'apply_streams');
重启应用进程
exec dbms_apply_adm.start_apply('apply_streams');
再次检查应用进程状态是否已恢复为enabled
select apply_name,queue_name,status from dba_apply;
APPLY_NAME QUEUE_NAME STATUS
------------------------------ ------------------------------ ----------
APPLY_STREAMS STREAMS_QUEUE ENABLED
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28974745/viewspace-2137631/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/28974745/viewspace-2137631/