
Oracle GoldenGate自動競合検出および解消機能の紹介(前編)
1. はじめに
はじめまして、NTTデータ先端技術の千葉です。
直近数年は、Oracle Exadata Database Machineのインフラ設計構築プロジェクト、データベース移行プロジェクトに従事しています。今回は、Oracle GoldenGateの活用事例を紹介します。
2. Oracle GoldenGate双方向構成について
Oracle GoldenGateでは、アクティブ/アクティブ型の双方向構成がサポートされています。双方向構成の環境では、同一データセットのデータベースが存在し、業務アプリケーションは、任意のデータベースを更新する事が可能です。ソースDBにて更新されたトランザクションデータは、Oracle GoldenGateによって、ターゲットDBにレプリケーションされます。結果として各システムのデータベースデータは同一の内容になります。
上記双方向構成においては、Primary SystemからSecondary Systemへのレプリケーション方向(上記図の青色)では、Primary SystemがソースDB、Secondary SystemがターゲットDBとなります。
下記の流れでOracle GoldenGateによるレプリケーションが行われます。
- ①Primary ExtractプロセスがソースDBから更新データを抽出し、LocalTrailファイルへ出力する。
- ②DataPumpプロセスがLocalTrailファイルを読み取り、Secondary SystemのCollectorプロセスへ送信する。
- ③Collectorプロセスが、RemoteTrailファイルへ出力する。
- ④Replicatプロセスが、RemoteTrailファイルを読み取り、ターゲットDBを更新する。
逆にSecondary SystemからPrimary Systemへのレプリケーション方向(上記図の黄色)では、Secondary SystemがソースDB、Primary SystemがターゲットDBとなります。
業務アプリケーション等によるソースDBへの更新処理とOracle GoldenGateによるターゲットDBへの更新処理は非同期で行われるため、業務アプリケーションの処理時間影響は少ないですが、非同期で処理されるが故に、双方向構成で各データベースの同一データが、ほぼ同時に更新されてしまうと、データ競合の問題が発生します。競合の具体的な例を下記に示します。
時刻 | Primary System | Secondary System |
---|---|---|
10:00:00 |
SQL> UPDATE fish SET name = 'サバ' WHEERE id = 1; SQL> COMMIT; |
|
10:00:01 |
SQL> UPDATE fish SET name = 'アジ' WHEERE id = 1; SQL> COMMIT; |
|
10:00:05 | Oracle GoldenGateが、上記更新データ(サバ)をSecondary Systemへレプリケーションする。 | |
10:00:06 | Oracle GoldenGateが、上記更新データ(アジ)をPrimary Systemへレプリケーションする。 | |
10:00:07 |
Primary Systemのデータが、サバからアジに更新される。 SQL> SELECT * FROM fish; ID NAME ---------- ---------- 1 アジ |
Secondary Systemのデータが、アジからサバに更新される。 SQL> SELECT * FROM fish; ID NAME ---------- ---------- 1 サバ |
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以降から使用可能
上記1のCDRは、競合の検出と解消するためのルールを柔軟な設計が可能です。上記2のAuto CDRは、競合の検出と解消ルールが自動化されており、比較的お手軽に導入する事が可能です。本コラムでは、上記2のAuto CDRについて紹介します。本記事が、双方向構成を検討されている方々の手助けになれば幸いです。
3. Auto CDRの紹介
システム要件
Auto CDRを使用するためのシステム要件については、Oracle GoldenGate製品マニュアルに記載があります。Oracle GoldenGate 19.1の場合、マニュアル「Oracle DatabaseのためのOracle GoldenGateの使用」の「自動競合検出および解決の要件(https://docs.oracle.com/cd/F22974_01/oracle-db/automatic-conflict-detection-and-resolution2.html)」をご参照願います。
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 |
SQL> INSERT INTO fish (id, name) VALUES (1, 'サバ'); 補足: CDRTS$ROW列が、システム時刻の10:00:00で更新される。 SQL> COMMIT; |
|
10:00:01 |
SQL> INSERT INTO fish (id, name) VALUES (1, 'アジ'); 補足: CDRTS$ROW列が、システム時刻の10:00:01で更新される。 SQL> COMMIT; |
|
10:00:02 |
Primary SystemからのレプリケーションデータをSecondary Systemへ適用する際に下記が発生する。 [競合の検出] [競合の解消] |
|
10:00:03 |
Secondary SystemからのレプリケーションデータをPrimary Systemへ適用する際に下記が発生する。 [競合の検出] [競合の解消] UPDATE fish SET name='アジ' WHERE id=1; |
|
10:00:04 |
SQL> SELECT * FROM fish; ID NAME ---------- ---------- 1 アジ |
SQL> SELECT * FROM fish; ID NAME ---------- ---------- 1 アジ |
上記の通り、データの内容は一致した状態となり、データ不整合は発生しませんが、結果として、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 |
SQL> UPDATE fish SET name = 'サバ' WHERE id = 1; 補足: CDRTS$ROW列が、システム時刻の10:00:00で更新される。(更新前のCDRTS$ROW列は、9:50:00とする) SQL> COMMIT; |
|
10:00:01 |
SQL> UPDATE fish SET name = 'アジ' WHERE id = 1; 補足: CDRTS$ROW列が、システム時刻の10:00:01で更新される。(更新前のCDRTS$ROW列は、9:50:00とする) SQL> COMMIT; |
|
10:00:02 |
Primary SystemからのレプリケーションデータをSecondary Systemへ適用する際に下記が発生する。 [競合の検出] [競合の解消] |
|
10:00:03 |
Secondary SystemからのレプリケーションデータをPrimary Systemへ適用する際に下記が発生する。 [競合の検出] [競合の解消] UPDATE fish SET name = 'アジ' WHERE id = 1; |
|
10:00:04 |
SQL> SELECT * FROM fish; ID NAME ---------- ---------- 1 アジ |
SQL> SELECT * FROM fish; ID NAME ---------- ---------- 1 アジ |
上記の通り、データの内容は一致した状態となり、データ不整合は発生しませんが、結果として、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 |
SQL> UPDATE fish SET name = 'サバ' WHERE id = 1; 補足: CDRTS$ROW列が、システム時刻の10:00:00で更新される。(更新前のCDRTS$ROW列は、9:50:00とする) SQL> COMMIT; |
|
10:00:01 |
SQL> DELETE FROM fish WHERE id = 1; 補足: ツームストンテーブルにキー情報(id=1)とタイムスタンプ(10:00:01)が登録される。 SQL> COMMIT; |
|
10:00:02 |
Primary SystemからのレプリケーションデータをSecondary Systemへ適用する際に下記が発生する。 [競合の検出] [競合の解消] |
|
10:00:03 |
Secondary SystemからのレプリケーションデータをPrimary Systemへ適用する際に下記が発生する。 [競合の検出] [競合の解消] |
|
10:00:04 |
SQL> SELECT * FROM fish; レコードが選択されませんでした。 |
SQL> SELECT * FROM fish; レコードが選択されませんでした。 |
上記の通り、データの内容は一致した状態となり、データ不整合は発生しませんが、結果として、Primary Systemに登録されたデータが破棄されてしまいます。実際のシステム運用において、上記の動作が許容できるか慎重に検討する必要があります。許容できない場合は、片方向レプリケーション構成を検討など、アクティブ/アクティブ型の双方向レプリケーションの構成を見直す必要があります。
競合タイプ: DELETE ROW MISSING
競合の検出 | 競合の解消 |
---|---|
ターゲットDBへのDELETE実行時に、削除対象行が存在しない場合 | 不整合は発生しないため、解消するための処理は行われない |
下記にDELETE ROW MISSING競合の例を示します。
時刻 | Primary System | Secondary System |
---|---|---|
10:00:00 |
SQL> DELETE FROM fish WHERE id = 1; 補足: ツームストンテーブルにキー情報(id=1)とタイムスタンプ(10:00:00)が登録される。 SQL> COMMIT; |
|
10:00:01 |
SQL> DELETE FROM fish WHERE id = 1; 補足: ツームストンテーブルにキー情報(id=1)とタイムスタンプ(10:00:01)が登録される。 SQL> COMMIT; |
|
10:00:02 |
Primary SystemからのレプリケーションデータをSecondary Systemへ適用する際に下記が発生する。 [競合の検出] |
|
10:00:03 |
Secondary SystemからのレプリケーションデータをPrimary Systemへ適用する際に下記が発生する。 [競合の検出] |
|
10:00:04 |
SQL> SELECT * FROM fish; レコードが選択されませんでした。 |
SQL> SELECT * FROM fish; レコードが選択されませんでした。 |
4. おわりに
前編では、Auto CDRの概要と、競合タイプごとにOracle GoldenGateがどのように競合を解消するのかを紹介しました。初めてご覧になった方には理解が難しかったかもしれませんが、Auto CDRにおける競合解決は、"タイムスタンプが古いデータは破棄されて、タイムスタンプの新しいデータが採用される"、とご理解いただくのが良いと思います。
後編では、実機を用いて、Auto CDRの有効化方法と競合解決履歴データの確認方法、運用時の考慮事項を紹介します。
5. 番外編~私の散歩道~
自転車圏内にある地元の弁当屋"ダイナマイトキッチン"を紹介します。ダイナマイトキッチンは、デカ盛りのメニューをお手頃価格で販売しているテイクアウト専門の弁当屋で、画像は、私のお気に入りであるデカ唐揚げ弁当(おかずのみ)です。画像の通り、454g(容器の重さ含む)の大ボリュームでなんと540円 (価格は2021年10月時点)です。数は10個で、重量はそれぞれ43g, 44g, 50g, 43g, 47g, 42g, 44g, 42g, 43g, 45gでした。重量の平均は、44.3gで、標本不偏分散は6.233です。唐揚げの重量は正規分布に従うと仮定して、母平均μに対する90%の信頼区間を求めると、42.85g < μ < 45.75g となります。ばらつきが小さいため、二名でシェアしてもケンカになりませんね!ご興味のある方は、ぜひ検索してみてください。
※文章中の商品名、会社名、団体名は、一般に各社の商標または登録商標です。