Oracle CDC 變更資料捕獲技術

llnnmc發表於2018-09-17

一、Oracle CDC技術概要

對於增量資料採集,Oracle推出了兩種主要方案,一種是我們熟悉的物化檢視(materialized view),另一種就是CDC元件(Change Data Capture 變更資料捕獲)。利用CDC,在對源表進行INSERT、UPDATE或DELETE等操作的同時就可以提取資料,並且變化的資料被儲存在資料庫的變化表中。這樣就可以捕獲發生變化的資料,然後利用資料庫檢視以一種可控的方式提供給目標系統。

CDC體系結構基於釋出者/訂閱者模型。釋出者捕捉變化資料並提供給訂閱者。訂閱者使用從釋出者那裡獲得的變化資料。通常,CDC系統擁有一個釋出者和多個訂閱者。釋出者首先需要識別捕獲變化資料所需的源表。然後,它捕捉變化的資料並將其儲存在特別建立的變化表中。它還使訂閱者能夠控制對變化資料的訪問。訂閱者需要清楚自己感興趣的是哪些變化資料。一個訂閱者可能不會對釋出者釋出的所有資料都感興趣。訂閱者需要建立一個訂閱者檢視來訪問經發布者授權可以訪問的變化資料。

CDC有幾個重要的基本術語:
源表(Source Table),業務資料庫的需要捕獲資料的源表。
變化表(Change Table),儲存從源表捕獲的變化資料(包括各種DML產生的資料)。
變化集(Change Set),是保證事務一致性的資料集合,一個變化集對應多個變化表。
訂閱檢視(Subscription View),提供給讀取變化表資料的檢視。
訂閱視窗(Subscription Window),定義了檢視變化資料的時間範圍,就象一個觀察變化資料的滑動視窗,變化資料處理完成後,可以清除訂閱視窗。

CDC分同步和非同步模式:

同步模式,實時的捕獲變化資料並儲存到變化表中,釋出者與訂閱都位於同一資料庫中,同步模式實際使用trigger的形式來捕捉變化資料。

 

 

非同步模式,以Oracle流複製技術為基礎,從redo log中讀取日誌記錄來捕捉變化資料。非同步模式分為三種:

1)Asynchronous HotLog Configuration(非同步線上日誌CDC)

 

該過程不再使用觸發器,而是使用線上日誌,不是歸檔日誌。原表與目標表仍然必須是同一個庫。該模式相對簡單,是在Oracle 10g以上產生的,9i沒有該機制。

2)Asynchronous Distributed HotLog Configuration(非同步分散式線上日誌CDC)

 

該模式是對非同步線上日誌CDC的一種最佳化,也比較容易理解,就是加入了DB-LINK機制,使原表、目標表不在同一個庫,實際和非同步線上日誌CDC沒有什麼本質區別。

3)Asynchronous AutoLog Mode(透過非同步自動日誌複製的CDC)

這個又分兩種:

3.1)Asynchronous Autolog Online Change Data Capture Configuration(非同步線上日誌複製CDC)

 

非同步線上日誌複製CDC模式使用Standby熱備資料庫日誌,將日誌寫入了熱備資料庫,目標表就可以建立在熱備庫上,這對主資料庫效能影響就進一步降低。

3.2)Asynchronous AutoLog Archive Change Data Capture Configuration(非同步歸檔日誌複製CDC)

 

 

該模式幾乎可以完全不影響原資料庫的效能。需要做異地同步歸檔,然後在目標端分析歸檔日誌進行變化資料處理。

關於Oracle CDC的更多介紹可參考Oracle官方資料:

同步模式以trigger形式來捕捉,不如自主建立trigger靈活,且對效能的影響比從日誌捕捉變化資料的影響大,所以這裡以非同步Hotlog來進行部署。

二、CDC環境搭建

1、確認資料庫對CDC(變更資料捕獲)的支援
col parameter for a20
col value for a10
select * from v$option where parameter = 'Change Data Capture';

PARAMETER            VALUE
-------------------- ----------
Change Data Capture  TRUE

2、確認資料庫執行在歸檔模式
archive log list;

3、修改資料庫為強制日誌
alter database force logging;

4、新增資料庫補充日誌
alter database add supplemental log data;

5、確認資料庫修改後的狀態
col log_mode for a15
col force_logging for a15
col supp_log_min for a15
select log_mode, supplemental_log_data_min supp_log_min, force_logging from v$database;

LOG_MODE        SUPP_LOG_MIN    FORCE_LOGGING
--------------- --------------- ---------------
ARCHIVELOG      YES             YES

6、準備釋出資料和使用者

-- 建立業務使用者表,這裡業務使用者以Oracle自帶的SCOTT使用者為例
conn scott/tiger
create table t1(a number, b varchar2(20));

-- 建立釋出者並授權
conn / as sysdba
create user cdc_pubr identified by cdc_pubr default tablespace users;

alter user cdc_pubr quota unlimited on system quota unlimited on sysaux;
grant connect, resource, dba to cdc_pubr;
grant create session to cdc_pubr;
grant create table to cdc_pubr;
grant create tablespace to cdc_pubr;
grant unlimited tablespace to cdc_pubr;
grant select_catalog_role to cdc_pubr;
grant execute_catalog_role to cdc_pubr;
grant create sequence to cdc_pubr;
grant select_catalog_role to cdc_pubr;
grant execute_catalog_role to cdc_pubr;
grant select on change_sets to cdc_pubr;
grant execute on sys.dbms_cdc_publish to cdc_pubr;
begin
    dbms_streams_auth.grant_admin_privilege(grantee => 'cdc_pubr');
end;
/

-- 新增CDC表的補充日誌
alter table scott.t1 add supplemental log group log_group_t1(a number, b varchar2(20)) always;
-- 如要捕捉表的所有列,則可用以下語句替代
alter table scott.t1 add supplemental log data(all) columns;

7、源表例項化
conn / as sysdba
begin
    dbms_capture_adm.prepare_table_instantiation(table_name => 'scott.t1');
end;
/

8、建立變更集
conn cdc_pubr/cdc_pubr;
begin
  dbms_cdc_publish.create_change_set(change_set_name    => 'cdc_t1',
                                     description        => 'change set for scott.t1',
                                     change_source_name => 'hotlog_source',
                                     stop_on_ddl        => 'y');
end;
/

9、建立變更表
conn cdc_pubr/cdc_pubr;
begin
  dbms_cdc_publish.create_change_table(owner             => 'cdc_pubr',
                                       change_table_name => 'c_t1',
                                       change_set_name   => 'cdc_t1',
                                       source_schema     => 'scott',
                                       source_table      => 't1',
                                       column_type_list  => 'a number, b varchar2(20)',
                                       capture_values    => 'both',
                                       rs_id             => 'y',
                                       row_id            => 'y',
                                       user_id           => 'y',
                                       timestamp         => 'y',
                                       object_id         => 'n',
                                       source_colmap     => 'n',
                                       target_colmap     => 'y',
                                       options_string    => '');
end;
/

10、啟用變更集
conn cdc_pubr/cdc_pubr;
begin
  dbms_cdc_publish.alter_change_set(change_set_name => 'cdc_t1',
                                    enable_capture  => 'y');
end;
/

dbms_cdc_publish過程的詳細解釋可參考官方資料:
https://docs.oracle.com/cd/E11882_01/appdev.112/e40758/d_cdcpub.htm#ARPLS023

11、建立訂閱者並授權
conn / as sysdba
create user cdc_subr1 identified by cdc_subr1 default tablespace users;

grant create table to cdc_subr1;
grant create session to cdc_subr1;
grant create view to cdc_subr1;
grant unlimited tablespace to cdc_subr1;

conn cdc_pubr/cdc_pubr;
grant select on cdc_pubr.c_t1 to cdc_subr1;

12、建立訂閱集
conn cdc_subr1/cdc_subr1
begin
  dbms_cdc_subscribe.create_subscription(change_set_name   => 'cdc_t1',
                                         description       => 'change data for scott.t1',
                                         subscription_name => 'sub_t1');
end;
/

13、訂閱源表及相關欄位
conn cdc_subr1/cdc_subr1
begin
  dbms_cdc_subscribe.subscribe(subscription_name => 'sub_t1',
                               source_schema     => 'scott',
                               source_table      => 't1',
                               column_list       => 'a, b',
                               subscriber_view   => 'v_t1');
end;
/

14、啟用訂閱
conn cdc_subr1/cdc_subr1
begin
  dbms_cdc_subscribe.activate_subscription(subscription_name => 'sub_t1');
end;
/

15、擴充套件訂閱視窗,設定訂閱視窗的高位邊界,以便能看到資料的變更
conn cdc_subr1/cdc_subr1
begin
  dbms_cdc_subscribe.extend_window(subscription_name => 'sub_t1');
end;
/

dbms_cdc_subscribe過程的詳細解釋可參考官方資料:
https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_cdcsub.htm#CHEFHFJA

三、檢視訂閱內容

conn cdc_subr1/cdc_subr1
select * from v_t1;

因源表scott.t1尚無資料變更,因此該檢視無資料。

源表插入資料
conn scott/tiger
insert into t1 values(101, 'liuln');
commit;

重新整理訂閱資料,注意每次查閱前需要這個重新整理動作
conn cdc_subr1/cdc_subr1
begin
  dbms_cdc_subscribe.extend_window(subscription_name => 'sub_t1');
end;
/

檢視訂閱檢視
col commit_timestamp$ for a20
col timestamp$ for a20
col row_id$ for a20
col username$ for a10
select operation$, to_date(commit_timestamp$, 'yyyy-mm-dd hh24:mi:ss') commit_timestamp$, to_date(timestamp$, 'yyyy-mm-dd hh24:mi:ss') timestamp$, row_id$, rsid$, username$, a, b from v_t1;

OPERATION$ COMMIT_TIMESTAMP$    TIMESTAMP$           ROW_ID$                   RSID$ USERNAME$           A B
---------- -------------------- -------------------- -------------------- ---------- ---------- ---------- --------------------
I          2018-09-17 17:07:47  2018-09-17 17:07:44  AAAWxgAAEAAAAWGAAA            1 SCOTT             101 liuln

再插入一條資料
conn scott/tiger
insert into t1 values(102, 'yaowei');
commit;

觀察結果,變更資料是累積的
OP COMMIT_TIMESTAMP$    TIMESTAMP$           ROW_ID$                   RSID$ USERNAME$           A B
-- -------------------- -------------------- -------------------- ---------- ---------- ---------- --------------------
I  2018-09-17 17:07:47  2018-09-17 17:07:44  AAAWxgAAEAAAAWGAAA            1 SCOTT             101 liuln
I  2018-09-17 17:37:18  2018-09-17 17:37:15  AAAWxgAAEAAAAWGAAB            2 SCOTT             102 yaowei

更新資料
conn scott/tiger
update t1 set b = 'liuqy' where a = '102';
commit;

觀察結果,分行顯示了更新前後的舊值和新值
OP COMMIT_TIMESTAMP$    TIMESTAMP$           ROW_ID$                   RSID$ USERNAME$           A B
-- -------------------- -------------------- -------------------- ---------- ---------- ---------- --------------------
I  2018-09-17 17:07:47  2018-09-17 17:07:44  AAAWxgAAEAAAAWGAAA            1 SCOTT             101 liuln
I  2018-09-17 17:37:18  2018-09-17 17:37:15  AAAWxgAAEAAAAWGAAB            2 SCOTT             102 yaowei
UO 2018-09-17 17:46:01  2018-09-17 17:46:01  AAAWxgAAEAAAAWGAAB            3 SCOTT             102 yaowei
UN 2018-09-17 17:46:01  2018-09-17 17:46:01  AAAWxgAAEAAAAWGAAB            3 SCOTT             102 liuqy

刪除資料
conn scott/tiger
delete from t1 where a = '101';
commit;

觀察結果
OP COMMIT_TIMESTAMP$    TIMESTAMP$           ROW_ID$                   RSID$ USERNAME$           A B
-- -------------------- -------------------- -------------------- ---------- ---------- ---------- --------------------
I  2018-09-17 17:07:47  2018-09-17 17:07:44  AAAWxgAAEAAAAWGAAA            1 SCOTT             101 liuln
I  2018-09-17 17:37:18  2018-09-17 17:37:15  AAAWxgAAEAAAAWGAAB            2 SCOTT             102 yaowei
UO 2018-09-17 17:46:01  2018-09-17 17:46:01  AAAWxgAAEAAAAWGAAB            3 SCOTT             102 yaowei
UN 2018-09-17 17:46:01  2018-09-17 17:46:01  AAAWxgAAEAAAAWGAAB            3 SCOTT             102 liuqy
D  2018-09-17 17:52:03  2018-09-17 17:52:03  AAAWxgAAEAAAAWGAAA            4 SCOTT             101 liuln

操作中發現,重新整理訂閱資料的動作每次需要執行兩遍才能獲取到變更資料。

四、訂閱資料清理

變更資料提取後如不再需要,可以清除,以騰出空間。
begin
  dbms_cdc_subscribe.purge_window(subscription_name => 'sub_t1');
end;
/

五、取消訂閱

如果訂閱不再需要,可以刪除。
begin
  dbms_cdc_subscribe.drop_subscription(subscription_name => 'sub_t1');
end;
/


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28974745/viewspace-2214346/,如需轉載,請註明出處,否則將追究法律責任。

相關文章