2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Oracle GoldenGate自動競合検出および解消機能の紹介 その1

Posted at

はじめに

データレプリケーション製品のOracle GoldenGateでは、アクティブ・アクティブ型の双方向レプリケーションがサポートされています。本記事にて機能概要を紹介します。

Oracle GoldenGate双方向構成について

双方向構成の環境では、同一データセットのデータベースが存在し、業務アプリケーションは、任意のデータベースを更新する事が可能です。ソースDBにて更新されたトランザクションデータは、Oracle GoldenGateによって、ターゲットDBにレプリケーションされます。結果として各システムのデータベースデータは同一の内容になります。
img01.png

上記双方向構成においては、Primary SystemからSecondary Systemへのレプリケーション方向(上記図の青色)では、Primary SystemがソースDB、Secondary SystemがターゲットDBとなります。下記の流れでOracle GoldenGateによるレプリケーションが行われます。

  1. Primary ExtractプロセスがソースDBから更新データを抽出し、LocalTrailファイルへ出力する。
  2. DataPumpプロセスがLocalTrailファイルを読み取り、Secondary SystemのCollectorプロセスへ送信する。
  3. Collectorプロセスが、RemoteTrailファイルへ出力する。
  4. Replicatプロセスが、RemoteTrailファイルを読み取り、ターゲットDBを更新する。

逆にSecondary SystemからPrimary Systemへのレプリケーション方向(上記図の黄色)では、Secondary SystemがソースDB、Primary SystemがターゲットDBとなります。

業務アプリケーション等によるソースDBへの更新処理とOracle GoldenGateによるターゲットDBへの更新処理は非同期で行われるため、業務アプリケーションの処理時間影響は少ないですが、非同期で処理されるが故に、双方向構成で各データベースの同一データが、ほぼ同時に更新されてしまうと、データ競合の問題が発生します。競合の具体的な例を下記に示します。

時刻 Primary System Secondary System
10:00:00 UPDATE fish SET name = 'サバ' WHERE id = 1;
COMMIT;
10:00:01 UPDATE fish SET name = 'アジ' WHERE id = 1;
COMMIT;
10:00:05 GoldenGateが、上記更新データ(サバ)をSecondary Systemへレプリケーションする。
10:00:06 GoldenGateが、上記更新データ(アジ)をPrimary Systemへレプリケーションする。
10:00:07 Primary Systemのデータが、サバからアジに更新される。

SELECT name FROM fish WHERE id = 1;
NAME
-------
アジ
Secondary Systemのデータが、アジからサバに更新される。

SELECT name FROM fish WHERE id = 1;
NAME
----------
サバ

fishテーブルのid=1のデータが、ほぼ同時に更新された結果、競合が発生し、各データベースのデータは異なる状態となってしまいました。双方向構成の環境を運用する場合は、競合を解消するための仕組みを検討する必要があります。Oracle GoldenGateでは、競合を解消するための機能が、下記二つの方式にて提供されています。

  • Conflict Detection and Resolution(以降CDRと表記) Oracle GoldenGate 11g 11.2以降から使用可能
  • Automatic Conflict Detection and Resolution(以降Auto CDRと表記) Oracle GoldenGate 12c 12.3.0.1以降から使用可能

CDRは、競合の検出と解消するためのルールを柔軟な設計が可能です。Auto CDRは、競合の検出と解消ルールが自動化されており、比較的お手軽に導入する事が可能です。本記事では、Auto CDRを取り上げて紹介します。

Auto CDRの紹介

システム要件

Auto CDRを使用するためのシステム要件については、Oracle GoldenGate製品マニュアルに記載があります。Oracle GoldenGate 19.1の場合、マニュアル「Oracle DatabaseのためのOracle GoldenGateの使用」の「 自動競合検出および解決の要件 」をご参照願います。

Auto CDR有効化による定義変更

競合が発生する可能性のあるテーブル単位に、Auto CDRを有効化する必要があります。Auto CDRを有効化するとテーブル単位に下記が追加されます。

  • 対象テーブルに非表示のタイムスタンプ列が追加される(列名は、CDRTS\$ROW)。
  • ツームストンテーブルが追加される(テーブル名は、DT\$_<テーブル名>)。

実際にAuto CDRを有効化したfishテーブルの定義を、sqlplusを使用して確認した結果を下記に示します。sqlplusのシステム変数COLINVISIBLEをONに設定すると、非表示列の確認が可能です。
補足: fishテーブルのキー列はID列です。

SQL> SET COLINVISIBLE ON
SQL> DESC angler.fish
 名前                                       NULL?    型
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER
 NAME                                               VARCHAR2(100)
 CDRTS$ROW (INVISIBLE)                     NOT NULL TIMESTAMP(6)

また、ツースムストンテーブルが作成されている事を確認します。

SQL> DESC angler.dt$_fish;
 名前                                       NULL?    型
 ----------------------------------------- -------- ----------------------------
 ID                                                 NUMBER
 DELTIME$$                                          TIMESTAMP(6)

次にfishテーブルにデータを追加した際の動作を示します。
fishテーブルのCDRTS\$ROW列に、INSERT実行時のタイムスタンプが格納されます。(UPDATE時も同様)
補足: CDRTS\$ROWに格納される時刻データは、UTCで管理されます。

SQL> INSERT INTO angler.fish (id, name) VALUES (1,'セイゴ');
1行が作成されました。

SQL> COMMIT;
コミットが完了しました。

SQL> SELECT id, name, cdrts$row FROM angler.fish;
        ID NAME       CDRTS$ROW
---------- ---------- ------------------------
         1 セイゴ     21-10-02 05:42:53.492774

DELETE処理を実行するとツームストンテーブルに、削除したキー列値とタイムスタンプが記録されます。
実際にfishテーブルのデータをDELETEした場合の動作を示します。
補足: ツームストンテーブルのDELTIME\$\$列もUTC管理です。

SQL> DELETE FROM angler.fish WHERE id = 1;
1行が削除されました。

SQL> COMMIT;
コミットが完了しました。

SQL> SELECT * FROM angler.dt$_fish;
        ID DELTIME$$                  
---------- ------------------------
         1 21-10-02 08:28:58.396096

Auto CDRでは、上記の非表示列(CDRTS\$ROW)およびツームストンテーブルのタイムスタンプ列(DELTIME\$\$)の情報を使用して、競合の検出と解消が行われます。ちなみにツームストン(tombstone)は、「墓石」という意味だそうです。削除された情報が墓石に刻まれているイメージでしょうか。私の場合、プロレス技のツームストン・パイルドライバが思い浮かびました。

競合検出と解消方法

Auto CDRにより、競合がどのように検出されて、またどのように解消されるのかを競合タイプごとに示します。

競合タイプ: INSERT ROW EXISTS

  • 競合の検出
    ターゲットDBへのINSERT実行時に、同一キーのデータが存在した場合
  • 競合の解消
    ソースDBとターゲットDBのCDRTS\$ROW列値を比較し、新しいほうのデータが採用される

下記にINSERT ROW EXISTS競合と解消の例を示します。

時刻 Primary System Secondary System
10:00:00 INSERT INTO fish (id, name) VALUES (1, 'サバ');
COMMIT;

[補足]
CDRTS\$ROW列が、システム時刻の10:00:00で更新される。
10:00:01 INSERT INTO fish (id, name) VALUES (1, 'アジ');
COMMIT;

[補足]
CDRTS\$ROW列が、システム時刻の10:00:01で更新される。
10:00:02 Primary SystemからのレプリケーションデータをSecondary Systemへ適用する際に下記が発生する。

[競合の検出]
同一キーのデータがSecondary Systemに存在するため、INSERT ROW EXISTS競合が発生する。

[競合の解消]
Secondary SystemのCDRTS\$ROWが新しいため、Primary SystemのINSERTデータは破棄される。
10:00:03 Secondary SystemからのレプリケーションデータをPrimary Systemへ適用する際に下記が発生する。

[競合の検出]
同一キーのデータがPrimary Systemに存在するため、INSERT ROW EXISTS競合が発生する。

[競合の解消]
Secondary SystemのCDRTS\$ROWが新しいため、Primary SystemのデータをUPDATEする。

UPDATE fish SET name='アジ' WHERE id=1;
10:00:04 SELECT name FROM fish WHERE id = 1;
NAME
----------
アジ
SELECT name FROM fish WHERE id = 1;
NAME
----------
アジ

上記の通り、データの内容は一致した状態となり、データ不整合は発生しませんが、結果として、Primary Systemに登録されたデータが破棄されてしまいます。実際のシステム運用において、上記の動作が許容できるか慎重に検討する必要があります。許容できない場合は、Primary SystemとSecondary Systemのキーの値が、重複しないような設計が必要になります。

競合タイプ: UPDATE ROW EXISTS

  • 競合の検出
    ターゲットDBへのUPDATE実行時に、ソースDBの更新前CDRTS\$ROW列値とターゲットDBのCDRTS\$ROW列値が異なる場合
  • 競合の解消
    ソースDBの更新後CDRTS\$ROW列値とターゲットDBのCDRTS\$ROW列値を比較し、新しいほうのデータが採用される

下記にUPDATE ROW EXISTS競合と解消の例を示します。

時刻 Primary System Secondary System
10:00:00 UPDATE fish SET name = 'サバ' WHERE id = 1;
COMMIT;

[補足]
CDRTS\$ROW列が、システム時刻の10:00:00で更新される。(更新前のCDRTS\$ROW列は、9:50:00とする)
10:00:01 UPDATE fish SET name = 'アジ' WHERE id = 1;
COMMIT;

[補足]
CDRTS\$ROW列が、システム時刻の10:00:01で更新される。(更新前のCDRTS\$ROW列は、9:50:00とする)
10:00:02 Primary SystemからのレプリケーションデータをSecondary Systemへ適用する際に下記が発生する。

[競合の検出]
Primary Systemの更新前CDRTS\$ROW(9:50:00)とSecondary SystemのCDRTS\$ROW(10:00:01)が一致しないため、UPDATE ROW EXISTS競合が発生する。

[競合の解消]
Secondary SystemのCDRTS\$ROWが新しいため、Primary SystemのUPDATEデータは破棄される。
10:00:03 Secondary SystemからのレプリケーションデータをPrimary Systemへ適用する際に下記が発生する。

[競合の検出]
Secondary Systemの更新前CDRTS\$ROW(9:50:00)とPrimary SystemのCDRTS\$ROW(10:00:00)が一致しないため、UPDATE ROW EXISTS競合が発生する。

[競合の解消]
Secondary SystemのCDRTS\$ROWが新しいため、Primary SystemのデータをUPDATEする。

UPDATE fish SET name = 'アジ' WHERE id = 1;
10:00:04 SELECT name FROM fish WHERE id = 1;
NAME
----------
アジ
SELECT name FROM fish WHERE id = 1;
NAME
----------
アジ

上記の通り、データの内容は一致した状態となり、データ不整合は発生しませんが、結果として、Primary Systemに登録されたデータが破棄されてしまいます。実際にシステム運用において、上記の動作が許容できるか慎重に検討する必要があります。許容できない場合は、アクティブ/アクティブ型の双方向レプリケーションの構成を見直し、片方向レプリケーション構成を検討するなどの対応をとる必要があります。

競合タイプ: UPDATE ROW MISSING

  • 競合の検出
    ターゲットDBへのUPDATE実行時に、更新対象行が存在しない場合
  • 競合の解消
    ソースDBの更新後CDRTS\$ROW列値とターゲットDBのDELTIME\$\$列値(ツームストンテーブル)を比較し、新しいほうのデータが採用される

競合タイプ: DELETE ROW EXISTS

  • 競合の検出
    ターゲットDBへのDELETE実行時に、ソースDBの更新前CDRTS\$ROW列値とターゲットDBのCDRTS\$ROW列値が異なる場合
  • 競合の解消
    ソースDBのDELTIME\$\$列値(ツームストンテーブル)とターゲットDBのCDRTS\$ROW列値を比較し、新しいほうのデータが採用される

下記にUPDATE ROW MISSING競合および、DELETE ROW EXISTS競合の例を示します。
Primary System のUPDATE処理がSecondary Systemにレプリケーションされる際に、UPDATE ROW MISSING競合が発生します。またSecondary SystemのDELETE処理がPrimary Systemにレプリケーションされる際に、DELETE ROW EXISTS競合が発生します。

時刻 Primary System Secondary System
10:00:00 UPDATE fish SET name = 'サバ' WHERE id = 1;
COMMIT;

[補足]
CDRTS\$ROW列が、システム時刻の10:00:00で更新される。(更新前のCDRTS\$ROW列は、9:50:00とする)
10:00:01 DELETE FROM fish WHERE id = 1;
COMMIT;

[補足]
ツームストンテーブルにキー情報(id=1)とタイムスタンプ(10:00:01)が登録される。
10:00:02 DELETE FROM fish WHERE id = 1;
COMMIT;

[補足]
ツームストンテーブルにキー情報(id=1)とタイムスタンプ(10:00:01)が登録される。Primary SystemからのレプリケーションデータをSecondary Systemへ適用する際に下記が発生する。

[競合の検出]
id=1のデータがSecondary Systemに存在しないため、UPDATE ROW MISSING競合が発生する。

[競合の解消]
Secondary SystemのDELTIME\$\$が新しいため、Primary SystemのUPDATEデータは破棄される。
10:00:03 Secondary SystemからのレプリケーションデータをPrimary Systemへ適用する際に下記が発生する。

[競合の検出]
Secondary Systemの更新前CDRTS\$ROW(9:50:00)とPrimary SystemのCDRTS\$ROW(10:00:00)が一致しないため、DELETE ROW EXISTS競合が発生する。

[競合の解消]
Secondary SystemのDELTIME\$\$が、Primary SystemのCDRTS\$ROWよりも新しいため、Primary SystemのデータをDELETEする。

DELETE FROM fish WHERE id = 1;
10:00:04 SELECT * FROM fish;
レコードが選択されませんでした。
SELECT * FROM fish;
レコードが選択されませんでした。

上記の通り、データの内容は一致した状態となり、データ不整合は発生しませんが、結果として、Primary Systemに登録されたデータが破棄されてしまいます。実際のシステム運用において、上記の動作が許容できるか慎重に検討する必要があります。許容できない場合は、片方向レプリケーション構成を検討など、アクティブ/アクティブ型の双方向レプリケーションの構成を見直す必要があります。

競合タイプ: DELETE ROW MISSING

  • 競合の検出
    ターゲットDBへのDELETE実行時に、削除対象行が存在しない場合
  • 競合の解消
    不整合は発生しないため、解消するための処理は行われない

下記にDELETE ROW MISSING競合の例を示します。

時刻 Primary System Secondary System
10:00:00 DELETE FROM fish WHERE id = 1;
COMMIT;

補足
ツームストンテーブルにキー情報(id=1)とタイムスタンプ(10:00:00)が登録される。
10:00:01 DELETE FROM fish WHERE id = 1;
COMMIT;

補足
ツームストンテーブルにキー情報(id=1)とタイムスタンプ(10:00:01)が登録される。
10:00:02 Primary SystemからのレプリケーションデータをSecondary Systemへ適用する際に下記が発生する。

[競合の検出]
id=1のデータがSecondary Systemに存在しないため、DELETE ROW MISSING競合が発生する。
10:00:03 Secondary SystemからのレプリケーションデータをPrimary Systemへ適用する際に下記が発生する。

[競合の検出]
id=1のデータがPrimary Systemに存在しないため、DELETE ROW MISSING競合が発生する。
10:00:04 SELECT * FROM fish;
レコードが選択されませんでした。
SELECT * FROM fish;
レコードが選択されませんでした。

おわりに

Auto CDRの概要と、競合タイプごとにOracle GoldenGateがどのように競合を解消するのかを紹介しました。初めてご覧になった方には理解が難しかったかもしれませんが、Auto CDRにおける競合解決は、"タイムスタンプが古いデータは破棄されて、タイムスタンプの新しいデータが採用される"、とご理解いただくのが良いと思います。
次回は、実機を用いて、Auto CDRの有効化方法と競合解決履歴データの確認方法、運用時の考慮事項を紹介します。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?