Oracle Golden Gate(簡稱OGG)是Oralce出品的資料即時抄寫工具,它讀取redo.log來進行抄寫避免影響正在運作的Oracle的效能,目前可同步抄寫到Oracle、MySQL和SQL Server。OGG本身是一支standalone程式,也提供一個Java Adapter方便開發者客製抄寫作業。怎麼安裝自有Consultant處理,但實作Java Adapter還真的有些難度。這主題目前是我寫過最難寫的。
OGG啟動後,可以切換到OGG Home目錄執行ggsci執行檔,會出帶出ggsci>的提示。下達info all命令後,可以work的狀況下,會顯示三類Extract(不是三個),Extract之於OGG類似於Process之於OS。其實extract就是process,可以用ps -ef | grep ogg觀察。這三類Extract分別是:
- Manager:OGG的主控程式extract,是必須的。
- ext1:不一定叫ext1。屬OGG for Oracle,是由User建立,負責讀取redo.log。若只單純同步其它DB,應只需這類Extract,通常一個Extract對映一個DB(Oracle的SID),可以指定抄寫等定的table。
- javaue:則是OGG的Java Adapter特定的extract,也是本篇Blog主題。
info all會帶出每個extract的status,分別是:RUNNING、STOP和ABENDED。ABENDED查好久,是異常中止的意思。也就在javaue底下寫Java adpater若寫得不好,狀態就是ABENDED。
未談OGG for Java之前,先略述OGG for Oracle的運行架構,在OGG Home目錄下有個重要的子目錄:dirprm,裡面放的.prm檔即是上述的extract的參數檔,需手動編輯,除了mgr.prm很簡單的只設定PORT number之外,而ext1.prm內容長得像這樣:
extract ext1 # 宣告extract name |
設定完後,在ggsci>下start ext1,它就會讀取jemmy.FOO和table.orcl有異動到redo.log寫到./dirdat/je。至於怎麼直接抄寫到不同的DB,要另外找找設定,這裡是要給OGG for Java讀取使用。
OGG for Java安裝後,在OGG Home目錄下會多出一個ggjava的子目錄,即是javaue extract運行的地方。一樣在/dirprm子目錄有個javaue.prm,其內容後面再討論。另外還需利用defgen.prm做code gen產出javaue.def,作為javaue與ext1之間的mapping,在Home目錄執行:./defgen PARAMFILE dirprm/defgen.prm。所參考defgen.prm的內容,和ext1.prm內容頗為類似
userid ogg, password oracle |
而javaue.prm則是設定OGG for Java Adapter運作的環境及參數:
Extract javaue SetEnv (JAVA_HOME = "/usr/java5_64") CUserExit Java5_UserExit.so CUSEREXIT PassThru IncludeUpdateBefores # CUserExit是OGG for Oracle核心程式 GetUpdateBefores Table jemmy.*; |
講了上述不甚完全的配置後,現在才要進入如何開發的階段。OGG for Java的客製化限制還真的很OOXX的多。
- 第一個,不是做成Jar檔放進去,而是在/dirprm子目錄下放classes的內容,如OGG-Home/dirprm/com/mycompany/…。所以先前有個困惑是不應該放在ggjava目錄下嗎?目前無解。
- 第二個更OX了,log4j.properties以ggjava下的設定為主,而ggjava也import Spring的jar,版本是2.5.6,所以也有它的config檔,因不想複雜化,不用Spring。
- 寫好的OGG for Java程式放到dirprm目錄下後,如果有引額外的jar怎麼處理,這需要從dirprm下的javaue.properties做配置了。ggjava本身就有提供一個透過Velocity產出redo.log資料的sample,開發過程式可以和這sample並行對照驗證。以下是節錄的部份:
#gg.handlerlist=sample_test # sample_test是ggjava提供的用Velocity讀取redo.log的處理程式 # OGG Adapter |
javaue.properties的配置觀念與log4j類似。
- gg.handlerlist:後面接的是處理程式代名,可以多個,用逗號分隔。和log4j指定appender方法一樣。
- gg.handlerlist.程式代名.type:是指這程式代名實際對應的類別,需要在/dirprm/com/mycompany下找到OggHandler這個類別。該類別實作容後再敍。
- gg.classpath:import額外的jar檔,用逗號分隔。
- gg.handlerlist.程式代名.自訂屬性:ggjava好像進步到可以該程式代名需要的屬性。
- 如何開發OGG for Java:由上述的javaue.properties得知,啟動的入口在com.mycompany.OggHandler這支,它需要繼承OGG for Java提供抽象類別AbstractHandler,原程式碼如下:
package com.mycompany; import java.util.ArrayList; import org.slf4j.Logger; import com.goldengate.atg.datasource.AbstractHandler; public class OggHandler extends AbstractHandler { // 繼承它 @Override @Override @Override @Override @Override @Override @Override |
我在Log裡標注每個method的號碼,是OGG for Java執行順序:init—>metaDataChanged—>transactionBegin—>operationAdded—>transactionCommit—>reportStatus—>destroy。
- init:在ggsci>start javaue後,init只會被執行第一次。
- reportStatus:在ggsci>stop javaue後,reportStatus只被執行一次,回傳字串記錄於log4j.properties所寫的Log。
- destroy:在ggsci>stop javaue後,只被執行一次。
- 在每一筆交易被commit後,metaDataChanged—>transactionBegin—>operationAdded—>transactionCommit均被執行一輪,最重要的method是operationAdded和transactionCommit,由operationAdded是取得每一筆record(增改刪資訊),即DsOperation物件,加到一個List;到transactionCommit就取得transaction裡所有record,在OGG for Java預設作法就分出thread去處理。所以了解DsOperation構造就很重要。
- 解析DsOperation還需由AbstractHandler取得DsMetaData,以下是OggThread片段:
for (DsOperation op : this.ops) { // 取得每筆record |
DsOperation的Type一共有八種,目前會常用的是四種:
OpType \ Value | getBeforeValue | getAfterValue | Description |
DO_INSERT | null | Yes | All fields values |
DO_DELETE | Yes | null | 只會帶PK的before值 |
DO_UPDATE_FIELDCOMP | null | Yes | 不含PK值欄位的update |
DO_UPDATE_FIELDCOMP_PK | Yes | Yes | 含PK值欄位的update |
要注意的是,Update都不會帶所有欄位,只有被影響的欄位值,而DO_UPDATE_FIELDCOMP_PK只有PK欄位有After和Before值。
另外四種Type會在什麼情況出現還不知,分別是:DO_UPDATE_AC、DO_UPDATE_AC、DO_LOB和DO_TRUNCATE。要使truncate table可以作用到OGG的DO_TRUNCATE還需另外加裝script。而不解的是DO_UPDATE和DO_UPDATE_AC各代表什麼東東?
留言列表