おらくるのいる生活

OracleのDBAとしての、障害対応やらパフォーマンス・チューニングやらの日々を綴っています

Oracle Golden Gateを使ってみた 応用編(2)

前回で事前準備を行ったので、今回はパラメータ設定と、実際に競合を発生させて結果を確認してゆきます。

bismarc256.hateblo.jp

まず、レプリケートのループを回避する設定を入れます。これをやらないと一方の更新が他方に同期され、その同期された更新が再び元のDBに同期され…となって、永久ループに陥ってしまいます。

具体的にはREPLICATのパラメータでタグを設定します。「00」はデフォルトのタグ名です。

DBOPTIONS SETTAG 00

EXTRACTのパラメータでタグ付きのレコードを除外する設定を行います。

TRANLOGOPTIONS EXCLUDETAG 00

次に、競合解消方法をパターンごとにREPLICATのパラメータで指定します。

今回は設定例(1)として、Golden Gateのマニュアルに載っていた例をそのまま使用します。

レプリケート先のグループ名はrepg2、レプリケート元はrepg4で、それ以外は同じ内容をレプリケート元と先で設定します。

$ cat repg2.prm
REPLICAT repg2
DBOPTIONS SETTAG 00
DBLOGIN USERID ggadmin,password welcome1

ASSUMETARGETDEFS
MAP ggtest.TAB2, TARGET ggtest.TAB2, MAPINVISIBLECOLUMNS,
    COMPARECOLS (ON UPDATE ALL, ON DELETE ALL),
    RESOLVECONFLICT (UPDATEROWEXISTS, (DEFAULT, USEMAX (CDRTS$ROW))),
    RESOLVECONFLICT (INSERTROWEXISTS, (DEFAULT, USEMAX (CDRTS$ROW))),
    RESOLVECONFLICT (DELETEROWEXISTS, (DEFAULT, OVERWRITE)),
    RESOLVECONFLICT (UPDATEROWMISSING, (DEFAULT, OVERWRITE)),
    RESOLVECONFLICT (DELETEROWMISSING, (DEFAULT, DISCARD));

設定例(1)のMAP文の説明は以下の通りです。

  • INSERTROWEXISTS競合には、USEMAX解決を使用する。つまり、挿入時に行が存在する場合は、last_mod_time列を解決列として使用し、証跡の値とデータベースの値のどちらが大きいかを判別する。証跡の値の方が大きい場合、レコードを適用するが、挿入を更新に変更する。データベースの値の方が大きい場合、レコードを無視する。
  • UPDATEROWEXISTS競合には、USEMAX解決を使用する。つまり、更新時に行が存在する場合は、last_mod_time列を解決列として使用する。証跡の値の方が大きい場合、更新を適用する。
  • USEMINとUSEMAXを使用し、値がまったく同じ場合、RESOLVECONFLICTはトリガーされず、受け取った行は無視される。USEMINEQとUSEMAXEQを使用し、値がまったく同じ場合、解決策はトリガーされる。
  • DELETEROWEXISTS競合には、OVERWRITE解決を使用する。つまり、削除操作時に行が存在する場合は、削除を適用する。
  • UPDATEROWMISSING競合には、OVERWRITE解決を使用する。つまり、更新時に行が存在しない場合は、更新を挿入に変更して適用する。
  • DELETROWMISSING競合には、DISCARD解決を使用する。つまり、削除操作時に行が存在しない場合は、証跡レコードを破棄する。

更にレプリケート元の設定を続けます。

EXTRACTパラメータ

$ cat extg2.prm
EXTRACT extg2
TRANLOGOPTIONS EXCLUDETAG 00
USERID ggadmin,password welcome1
EXTTRAIL /u01/app/oracle/ogg_1/dirdat/stod/l2
TABLE GGTEST.TAB2;

データポンプEXTRACTパラメータ

$ cat dpg2.prm
EXTRACT dpg2
USERID ggadmin,password welcome1
RMTHOST mitsdb01, MGRPORT 31003
RMTTRAIL /u01/app/oracle/ogg_2/dirdat/stod/r2
TABLE GGTEST.TAB2;

レプリケート先の設定は以下の通りです。

EXTRACTパラメータ

$ cat extg4.prm
EXTRACT extg4
TRANLOGOPTIONS EXCLUDETAG 00
USERID ggadmin,password welcome1
EXTTRAIL /u01/app/oracle/ogg_2/dirdat/dtos/l4
TABLE GGTEST.TAB2;

データポンプEXTRACTパラメータ

$ cat dpg4.prm
EXTRACT dpg4
USERID ggadmin,password welcome1
RMTHOST mitsdb01, MGRPORT 31002
RMTTRAIL /u01/app/oracle/ogg_1/dirdat/dtos/r4
TABLE GGTEST.TAB2;

パラメータファイルの設定が終わったので、両データベースにそれぞれ接続し、以下を実行します。

レプリケート元

Extractの登録
REGISTER EXTRACT extg2 DATABASE

プライマリExtractの追加
ADD EXTRACT extg2, INTEGRATED TRANLOG, BEGIN NOW

ローカル証跡の追加
ADD EXTTRAIL /u01/app/oracle/ogg_1/dirdat/stod/l2, EXTRACT extg2

データ・ポンプExtractグループの追加
ADD EXTRACT dpg2,EXTTRAILSOURCE /u01/app/oracle/ogg_1/dirdat/stod/l2

リモート証跡の追加
ADD RMTTRAIL /u01/app/oracle/ogg_2/dirdat/stod/r2,EXTRACT dpg2

Replicatグループの追加
チェックポイント表の作成
ADD CHECKPOINTTABLE ggadmin.chktbl
ADD REPLICAT repg4,  EXTTRAIL /u01/app/oracle/ogg_2/dirdat/stod/r4,CHECKPOINTTABLE ggadmin.chktbl

レプリケート先

Extractの登録
REGISTER EXTRACT extg4 DATABASE

プライマリExtractの追加
ADD EXTRACT extg4, INTEGRATED TRANLOG, BEGIN NOW

ローカル証跡の追加
ADD EXTTRAIL /u01/app/oracle/ogg_2/dirdat/dtos/l4, EXTRACT extg4

データ・ポンプExtractグループの追加
ADD EXTRACT dpg4,EXTTRAILSOURCE /u01/app/oracle/ogg_2/dirdat/dtos/l4

リモート証跡の追加
ADD RMTTRAIL /u01/app/oracle/ogg_1/dirdat/dtos/r2,EXTRACT dpg4

Replicatグループの追加
ADD REPLICAT repg2,  EXTTRAIL /u01/app/oracle/ogg_1/dirdat/dtos/r2,CHECKPOINTTABLE ggadmin.chktbl

まず、レプリケート先でデータを挿入し、結果を確認します。

SQL> insert into tab2 values(1,'ggd',systimestamp);

1 row created.

SQL> select * from tab2;

      COL1 COL2       COL3
---------- ---------- ----------------------------------------
         1 ggd        25-MAR-22 11.37.23.635009 AM

レプリケート元でも同じキーでデータを挿入します。

SQL> insert into tab2 values(1,'ggs',systimestamp);

1 row created.

SQL> select * from tab2;

      COL1 COL2       COL3
---------- ---------- ----------------------------------------
         1 ggs        25-MAR-22 11.37.36.913159 AM

この後、双方でcommitを実行し、数秒待ってデータを確認します。

レプリケート元

SQL> select * from tab2;

      COL1 COL2       COL3
---------- ---------- ----------------------------------------
         1 ggs        25-MAR-22 11.37.36.913159 AM

レプリケート先

SQL> select * from tab2;

      COL1 COL2       COL3
---------- ---------- ----------------------------------------
         1 ggs        25-MAR-22 11.37.36.913159 AM

レプリケート元の方が後からinsertされたので、レプリケート元のデータで上書きされています。これはまあ、想定通りと言うか、当然の結果ですね。

 

次にupdateとdeleteの競合テストを行います。

レプリケート元でupdateを発行します。

SQL> update tab2 set col2='ggsggs' where col1=1;

1 row updated.

SQL> select * from tab2;

      COL1 COL2       COL3
---------- ---------- ----------------------------------------
         1 ggsggs     25-MAR-22 11.37.36.913159 AM

レプリケート先で同じレコードを削除します。

SQL> delete from tab2;

1 row deleted.

SQL> select * from tab2;

no rows selected

双方でcommit発行して、数秒後に確認します。

レプリケート元

SQL> select * from tab2;

no rows selected

レプリケート先

SQL> select * from tab2;

      COL1 COL2       COL3
---------- ---------- ----------------------------------------
         1 ggsggs     25-MAR-22 11.37.36.913159 AM

レプリケート元では更新した行が無くなってしまい、レプリケート先では削除した行が復活してレプリケート元の更新内容が反映されています。

これはどういう事かと言うと

  • updateした側は、相手側のdelete情報が来た時、削除を適用するので削除される
  • 削除した側は相手側のupdate情報が送られて来た時、OVERWRITE解決するので相手側のupdate後の状態になる(レコードが復活する)

なので仕様通りと言うか、設定どおりです。

でもレプリケート元と先でデータが一致していないので、ちょっと想定外と言いますか、期待と違ってしまいました…。

なので次回は設定例(2)を検証してみます。