1. Oracle CDC 简介
CDC(Change Data Capture)。很多人都认为,只要是涉及到数据库数据复制和增量数据抽取,都是需要购买收费软件的。实际上,我们通过Oracle提供的CDC和LogMiner等免费工具也能实现数据库数据复制和增量数据抽取,各种数据复制软件只是使得获取增量数据更加便捷,或者是可以支持更多的扩展功能(例如:异构数据库之间的同步,ETL过程的数据清洗、装换),但实际Oracle本身是支持CDC机制,只是很少有人关注,操作起来也有些复杂,而且据传言并不稳定,常常见到论坛上爆出一些莫名其妙的问题。
2. 增量数据采集概述
数据采集通常是指ETL过程中Extract-数据抽取部分。除了ETL外在不同应用系统之间通常也需要传递数据,在某些环境条件限制下不能将数据从一个系统直接移到另一个系统,只能借助文本来作为中间媒介传递数据,且文本的生成有时间窗口的限制,所以对数据采集即数据抽取的性能有一定的要求。对增加数据的采集的方法常用的有以下几种:
- 1.时间戳(Timestamps on rows)
- 2.版本号(Version Numbers on rows)
- 3.状态指示(Status indicators on rows)
- 4.时间戳、版本号、状态指示混合使用(Time/Version/Status on rows)
- 5.触发器 (Triggers on tables)
- 6.表差异(Table differencing)
- 7.数据库的日志扫描(Log scanners on databases)
对于增量数据采集情况在Oracle中推出了两种主要方案,一种是我们熟悉的物化视图(materialized view),另一种就是本文将要介绍的CDC组件(Change Data Capture 改变数据捕获)。
CDC 特性是在Oracle9i数据库中引入的。CDC能够帮助你识别从上次提取之后发生变化的数据。利用CDC,在对源表进行INSERT、UPDATE或 DELETE等操作的同时就可以提取数据,并且变化的数据被保存在数据库的变化表中。这样就可以捕获发生变化的数据,然后利用数据库视图以一种可控的方式提供给目标系统。
3. CDC的发布订阅模型
CDC体系结构基于发布者/订阅者模型。发布者捕捉变化数据并提供给订阅者。订阅者使用从发布者那里获得的变化数据。通常,CDC系统拥有一个发布者和多个订阅者。发布者首先需要识别捕获变化数据所需的源表。然后,它捕捉变化的数据并将其保存在特别创建的变化表中。它还使订阅者能够控制对变化数据的访问。订阅者需要清楚自己感兴趣的是哪些变化数据。一个订阅者可能不会对发布者发布的所有数据都感兴趣。 订阅者需要创建一个订阅者视图来访问经发布者授权可以访问的变化数据。
CDC有几个重要的基本概念需要先明确一下:
- 源表(Source Table),业务数据库的需要捕获数据的源表
- 变化表(Change Table) ,保存从源表捕获的变化数据(包括各种DML产生的数据)
- 变化集(Change Set),是保证事务一致性的数据集合。一个变化集对应多个变化表
- 订阅视图(Subscription View),提供给读取变化表数据的视图
- 订阅窗口(Subscription Window) ,定义了查看变化数据的时间范围.就象一个观察变化数据的滑动窗口。变化数据处理完成后,可以对清除订阅窗口。
4. Oracle CDC机制
4.1 同步复制
Synchronous Change Data Capture Configuration
原理很简单,原表、目标表必须是同一个库,采用触发器的机制(设置同步CDC后,并看不到触发器,但实际运行机理还是触发器的机制)将原表内容复制到另一个目标表。这个机制就不多说了,和自己给表建触发器没什么太大差别。
4.2 异步在线日志CDC
Asynchronous HotLog Configuration
这个过程已经没有触发器了,而是使用Redo Log,但是使用在线日志,并不是归档日志。并且原表、目标表仍然必须是同一个库。这种模式是相对简单的,同时这种模式是在Oracle 10以上才产生的,9i是没有这个机制的。
4.3异步分布式CDC
Asynchronous Distributed HotLog Configuration
实际这个模式是对异步在线日志CDC的一种优化,也比较容易理解,就是加入了DB-LINK机制,使原表、目标表不在同一个数据库。实际是和异步在线日志CDC没有什么本质区别。
4.4 异步在线日志复制CDC
Asynchronous Autolog Online Change Data Capture Configuration
异步在线日志复制CDC模式就要高级很多了,使用Standby Redo Log(热备数据库日志),实际就是使用Oracle的热备机制,将日志写入了热备数据库,目标表就可以建立在热备库上,这对主数据库性能影响就进一步降低。
4.5 归档日志CDC
Asynchronous AutoLog Archive Change Data Capture Configuration 归档日志CDC模式是最完美的模式,但是需要有机制可以获取归档日志(并行文件系统技术),然后在目标端分析归档日志进行变化数据处理,这种模式理论上来讲,几乎可以完全不影响原数据库的性能。
坦白来说,我对Oracle理解并不深,只是为了解决特定的几个问题多看了一点,在现实工作中遇到类似问题需要解决的,或对技术痴狂的同学可以研究一下,我贴上了4种模式具体的设置步骤,虽然是英文的,但是还是非常明确的。(我比较推荐使用第二种,因为设置比较简单,性能上也属于中规中矩,如果没有什么特别要求,可以采用异步在线日志CDC。
以下是对异步在线日志CDC环境的部署测试。
5. CDC相关的数据库对象 (Package)
n DBMS_CDC_PUBLISH, 用于定义发布操作
n DBMS_CDC_SUBSCRIBE,用于定义订阅操作
n EXECUTE_CATALOG_ROLE
n SELECT_CATALOG_ROLE
n CREATE TABLE and CREATE SESSION privileges
n EXECUTE on the DBMS_CDC_PUBLISH package
n ALL_SOURCE_TABLES 源表
n ALL_PUBLISHED_COLUMNS 发布的表列
n All_Subscribed_Columns 订阅的表列
n All_Subscriptions 所有订阅
n All_Subscribed_Tables 已经订阅的表
6. CDC的实施步骤
同步模式以trigger形式来捕捉,这种实行没有自身来使用trigger来捕捉来的灵活,且其对性能的影响比从日志捕捉变化数据的性能影响大,所以本文以异步捕捉中的异步Hotlog来讲解CDC的具体实施步骤.
6.1 准备数据和用户
SQL>show user
scott
SQL>create table t1 ( a_num number , b_varchar varchar2(10),c_char char(10));#测试表
SQL>conn / as sysdba
SQL>create user cdcpub identified by cdcpub; #发布用户(publisher)
SQL>create user subscriber1 identified by subscriber1;#订阅者(subscriber)
6.2 调整数据库参数(需根据实际情况修改)
compatible = 10.2.0
java_pool_size = 50000000
job_queue_processes = 2
parallel_max_servers = + 5
processes = + 7
sessions = + 2
streams_pool_size = + 21 MB
undo_retention = 3600
6.3 修改数据库日志模式
#数据库默认是在archivelog模式
SQL>show user
USER is “sys”
SQL>ALTER DATABASE FORCE LOGGING; #此步骤是可选但建议执行;
SQL>ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;#此步骤需执行;
SQL>ALTER TABLE scott.t1
ADD SUPPLEMENTAL LOG GROUP log_group_t1 (a_num,b_varchar,c_char) ALWAYS;
#若要捕捉t1表中所有列,可用下列语句代替上述alter table语句:
#ALTER TABLE scott.t1 ADD SUPPLEMENTAL LOG DATA (ALL) #COLUMNS;
6.4 授权
ALTER USER cdcpub QUOTA UNLIMITED ON SYSTEM
QUOTA UNLIMITED ON SYSAUX;
GRANT CREATE SESSION TO cdcpub;
GRANT CREATE TABLE TO cdcpub;
GRANT CREATE TABLESPACE TO cdcpub;
GRANT UNLIMITED TABLESPACE TO cdcpub;
GRANT SELECT_CATALOG_ROLE TO cdcpub;
GRANT EXECUTE_CATALOG_ROLE TO cdcpub;
GRANT CREATE SEQUENCE TO cdcpub;
GRANT DBA TO cdcpub;
GRANT EXECUTE on DBMS_CDC_PUBLISH TO cdcpub;
EXECUTE DBMS_STREAMS_AUTH.GRANT_ADMIN_PRIVILEGE(GRANTEE => 'cdcpub');
6.5 准备源表(Source Table)
SQL>show user
USER is “SYS”
SQL>
BEGIN
DBMS_CAPTURE_ADM.PREPARE_TABLE_INSTANTIATION(TABLE_NAME => 'scott.t1');
END;
6.6 创建变更集(Change Set)
SQL>show user
USER is “cdcpub”
SQL>
BEGIN
DBMS_CDC_PUBLISH.CREATE_CHANGE_SET(
change_set_name => 'cdc_test_cs',
description => 'Change set for scott.t info',
change_source_name => 'HOTLOG_SOURCE',
stop_on_ddl => 'y'
);
END;
6.7 创建变更表(Change Table)
SQL>show user
USER is “cdcpub”
SQL>
BEGIN
DBMS_CDC_PUBLISH.CREATE_CHANGE_TABLE(
owner => 'cdcpub',
change_table_name => 't1_ct',
change_set_name => 'cdc_test_cs',
source_schema => 'scott',
source_table => 't1',
column_type_list =>'a_num number,b_varchar varchar2(10),c_char char(10)',
capture_values => 'both',
rs_id => 'y',
row_id => 'n',
user_id => 'n',
timestamp => 'n',
object_id => 'n',
source_colmap => 'n',
target_colmap => 'y',
options_string => '');
END;
6.8 激活变更集(Change Set)
SQL>show user
USER is “cdcpub”
SQL>
BEGIN
DBMS_CDC_PUBLISH.ALTER_CHANGE_SET(
change_set_name => 'cdc_test_cs',
enable_capture => 'y');
END;
6.9 授权给订阅者
SQL>show user
USER is “cdcpub”
SQL> GRANT SELECT ON cdcpub.t1_ct TO subscriber1;
SQL>show user
USER is “SYS”
SQL>GRANT CREATE TABLE TO subscriber1;
SQL>GRANT CREATE SESSION TO subscriber1;
SQL>GRANT CREATE VIEW TO subscriber1;
SQL>GRANT UNLIMITED TABLESPACE TO subscriber1;
6.10 订阅变更数据
SQL>show user
USER is “subscriber1”
SQL>
BEGIN
DBMS_CDC_SUBSCRIBE.CREATE_SUBSCRIPTION(
change_set_name => 'cdc_test_cs',
description => 'Change data for t1',
subscription_name => 't1_sub');
END;
SQL>show user
USER is “subscriber1”
SQL>
BEGIN
DBMS_CDC_SUBSCRIBE.SUBSCRIBE(
subscription_name => 't1_sub',
source_schema => 'scott',
source_table => 't1',
column_list => 'a_num,b_varchar,c_char',
subscriber_view => 't1_view');
END;
SQL>show user
USER is “subscriber1”
SQL>
BEGIN
DBMS_CDC_SUBSCRIBE.ACTIVATE_SUBSCRIPTION(
subscription_name => 't1_sub');
END;
SQL>show user
USER is “subscriber1”
SQL>
BEGIN
DBMS_CDC_SUBSCRIBE.EXTEND_WINDOW(
subscription_name => 't1_sub');
END;
SQL>show user
USER is “subscriber1”
SQL>select * from t1_view; #因scott.t1表中无数据变更所以当前视图无数据
no rows selected
SQL>conn scott/tiger
SQL> insert into t1 values(2,'cdc_test1','cdc');
SQL>commit;
SQL>conn subscriber1/subscriber1
SQL>
BEGIN
DBMS_CDC_SUBSCRIBE.EXTEND_WINDOW(
subscription_name => 't1_sub');
END;
SQL>select OPERATION$,a_num,b_varchar,c_char from t1_view
OP A_NUM B_VARCHAR C_CHAR
-- ---------- ---------- ----------
I 2 cdc_test1 cdc
- 清除变更集数据
如果当前变更数据不在需要使用,可以清除为后续生成的数据腾出空间;
BEGIN
DBMS_CDC_SUBSCRIBE.PURGE_WINDOW(
subscription_name => 'SALES_SUB');
END;
BEGIN
DBMS_CDC_SUBSCRIBE.DROP_SUBSCRIPTION(
subscription_name => 't1_sub');
END;
|