この記事はOracle GoldenGate(OGG)におけるReplicatのパフォーマンスチューニングについてのtipsとなります。
以下の環境で確認したものとなりますので、環境による差異がある場合はコマンドがそのまま使用できるか等は確認いただければと思います。
項目 | 環境詳細 |
---|---|
Database | Oracle DB EE 19c / 3node RAC構成 |
GoldenGate | OGG 19c / Integrated Replicat / classic architecture |
サマリ
- 高負荷な処理ではstreams poolがネックとなるため、streams poolが枯渇しない程度にトランザクションサイズの判定閾値や並列度のチューニングする必要があります
- replicatの性能を上げるためにはシリアル処理が必須なトランザクションをうまく分離するようにプロセスを分割し、高いパラレル度で処理させることが重要です
メモリチューニング(streams pool)
replicatはOracle DBのメモリのうちstreams poolを使用します。streams poolが不足した場合、replicatは ORA-4031
によりABENDしてしまうことがあるためある程度余裕を持った状態での運用が必要となります。
streams poolの使用状況はgv$streams_pool_statistics
で確認できるため、replicatの実行中や特に処理量が多いと予想されるタイミング(初期同期時など)ではこのビューから使用状況を確認するのがおすすめです。
-- 確認用SQL
set line 300 pages 300 feed off
select
INST_ID,
TOTAL_MEMORY_ALLOCATED/1024/1024 as TOTAL_MEMORY_ALLOCATED,
CURRENT_SIZE/1024/1024 as CURRENT_SIZE,
TOTAL_MEMORY_ALLOCATED/CURRENT_SIZE * 100 as percentage
from gv$streams_pool_statistics
order by 1;
INST_ID TOTAL_MEMORY_ALLOCATED CURRENT_SIZE PERCENTAGE
---------- ---------------------- ------------ ----------
1 466 3072 15.2
2 2796 3072 91.0
3 2669 3072 86.9
replicatのメモリ使用傾向
replicatによるstreams poolの使用量は、基本的には処理レコード数に比例して伸びる傾向があります。そのため、レコード数の多いトランザクションをパラレルで処理する場合に枯渇しやすく注意が必要です。
トランザクションの大きさ、処理の並列度を考えるには、replicatにおけるlarge transactionという考え方を理解するがあります。
replicatではあるサイズ以上(eager_size
、デフォルトで15100レコード)のトランザクションはlarge transactionに分類され、シリアルで処理されるという挙動をします。シリアルの処理とパラレルの処理では以下のような挙動の差があるため注意が必要です。
- シリアル処理
- メモリ不足時は
ORA-4031
でエラーになりやすい
- メモリ不足時は
- パラレル処理
- メモリ不足時は
wait for memory allocation
により待機する傾向がある
- メモリ不足時は
eager_size
付近の大きさのトランザクションが多数ある場合、総処理量は少ないが同時処理される量は多くなる、といった状況が発生しえます。
特にeager_size
より少し小さいトランザクションが多数ある場合はメモリ不足でreplicatがエラーになりやすく、eager_size
や並列度の調整を行うことが必要かもしれません。
# 総処理量が少ないのに同時処理量は多い例
# 仮定
- replicatの並列度は4に設定されている
- eager_size=15100 # デフォルトの設定
DBOPTIONS INTEGRATEDPARAMS (PARALLELISM 4, EAGER_SIZE 15100)
# case 1(総処理量は少ないが、同時処理量は大きい)
総処理量 : 100,000レコード(10,000レコード * 10トランザクション)
トランザクションのレコード数はeager_size以下のため、パラレルで処理される
--> 同時処理量は 40,000レコード(10,000レコード * 4並列)となる
# case 2(総処理量は多いが、同時処理量は小さい)
総処理量 : 200,000レコード(20,000レコード * 10トランザクション)
トランザクションのレコード数はeager_size以上のため、シリアルで処理される
--> 同時処理量は 20,000レコード(20,000レコード * 1並列)となる
RACにおける接続先ノードの分散
replicatは接続先インスタンスのstreams poolしか使用できないため、単一replicatでは単一インスタンスのstreams poolしか使用できません。
RAC環境である場合はreplicatを複数プロセスに分けて接続先インスタンスを別々にすることで各インスタンスのstreams poolを効率的に使用できます。
例として以下のようにRACの各インスタンスへの接続先を定義してそれに対応したreplicatプロセスを定義することで、各インスタンスのstreams poolを使用させてメモリを有効に活用することができます(プロセス分割のコマンド例は後述します)。
# 3node RACにて各インスタンスの接続用のcredentialを作成する
$ ./ggsci
GGSCI> ALTER CREDENTIALSTORE ADD USER ggadm@dbserver1:1521/instance1, ALIAS ggadm_instance1
GGSCI> ALTER CREDENTIALSTORE ADD USER ggadm@dbserver2:1521/instance2, ALIAS ggadm_instance2
GGSCI> ALTER CREDENTIALSTORE ADD USER ggadm@dbserver3:1521/instance3, ALIAS ggadm_instance3
# 各replicatに上述のcredentialを割り当てる
------------------------------------------
REPLICAT rep1
USERIDALIAS ggadm_instance1
...(略)...
------------------------------------------
REPLICAT rep2
USERIDALIAS ggadm_instance2
...(略)...
------------------------------------------
REPLICAT rep3
USERIDALIAS ggadm_instance3
...(略)...
------------------------------------------
パラレル実行のチューニング
パラレル実行の仕様
replicatはパラレル実行が可能であり基本的にPARALLELISM
のパラメータで制御されます。具体的には、PARALLELISM
の値に応じて以下のように実際のプロセス数が変動します。
-
PARALLELISM
が1の場合- パラレル実行にはならず常にシリアルでの実行になる
-
PARALLELISM
が1より大きい場合- 負荷を加味しつつ
PARALLELISM
(デフォルト4)以上MAX_PARALLELISM
(デフォルト50)以下のプロセス数で動作する。これはPARALLELISM_INTERVAL
(デフォルト5秒)毎に再計算され、プロセスの増減がされる - 適用するトランザクションのレコード数が
eager_size
(デフォルト15100)を超える場合、large transaction扱いなり常にシリアルで適用される - 例外としてシーケンス操作、DDLなどは常にシリアルで適用される(詳細はMOSのDoc 2349663.1を参照ください)
- 負荷を加味しつつ
replicatのパフォーマンスを上げるにはパラレル度を上げて並列で動作させることは重要となります。
並列度を高く設定してもパラレル実行不可なトランザクションが混在するとシリアル実行に切り替わってしまいパフォーマンスが上がらないため、上述のようなパラレル実行できない処理(large transaction, シーケンス操作, DDL)はそれ専用のプロセスに分けられると効率が良くなります。
large transactionの補足
通常、replicatはパラレルで適用するために各トランザクション(LCR)の末尾のCommit recordを見て各トランザクションの依存関係を確認する必要があります。しかし、large transactionではCommit recordを見ずに先頭から適用しています(これがDirect modeでの適用と呼ばれる)。
このような挙動は、おそらくはトランザクションのサイズが大きすぎる場合にCommit recordを見て依存関係を確認する部分のオーバーヘッドが高いためのものと思われます。
replicat処理状況の確認方法
replicatの動作状況は以下のようにgv$gg_apply_server
ビューにて確認可能です。
以下の例では、SERVER_ID
が各replicatのパラレル実行される子プロセス、TOTAL_MESSAGES_APPLIED
が処理されたメッセージ数となります。この例では
REP1は各プロセスの処理メッセージ数が均等に伸びておりうまくパラレルで動作できていることが読み取れますが、一方でREP2, 3は処理メッセージ数がほぼ1-2プロセスに偏っておりほとんどシリアルで動作してしまっており非効率なことがわかります。
set line 200 pages 200
break on inst_id on apply_name
select inst_id, apply_name, server_id, state, total_messages_applied
from gv$gg_apply_server order by 2,3;
INST_ID APPLY_NAME SERVER_ID STATE TOTAL_MESSAGES_APPLIED
------- ----------- ---------- -------------------- ----------------------
1 OGG$REP1 0 IDLE 9535516
1 IDLE 329179
2 IDLE 3884629
3 IDLE 3517435
4 IDLE 3711645
2 OGG$REP2 0 IDLE 0
1 EXECUTE TRANSACTION 16279952 -- トランザクション実行中
2 IDLE 0
3 IDLE 0
4 IDLE 0
5 INACTIVE 0
3 OGG$REP3 0 IDLE 0
1 IDLE 9408427
2 EXECUTE TRANSACTION 9010171 -- トランザクション実行中
3 IDLE 0
4 IDLE 0
5 INACTIVE 0
6 INACTIVE 0
シリアル処理(large transaction)の調査
replicatの処理性能が出ないケースでは上記のように特定の子プロセスに処理が偏り、並列度が低くなってしまっていることが多々あります。処理が偏ってしまう際はlarge transactionがネックになっている可能性が高いため、large transactionの有無及び頻度、サイズの確認が重要です。
もっとも簡単なlarge transactionの確認方法としては、以下のようにログ(ggserr.log)にlarge transactionの情報が出力されるためこちらで確認するのが良いでしょう。ログを確認することでどの程度の大きさのlarge transactionが含まれているかがわかります。
2022-08-22T19:43:38.607+0900 INFO OGG-25221 Oracle GoldenGate Delivery for Oracle, rep1.prm: Processing transaction (XID: 20.28.41565525, Seqno: 70258, RBA: 18628234) larger than eager size (15,100).
2022-08-22T19:52:53.451+0900 INFO OGG-25222 Oracle GoldenGate Delivery for Oracle, rep1.prm: Large transaction completed. Total records: 1,482,854.
より詳細にはgv$gg_apply_server
での確認するのが良いと思われます。もしlarge transactionがある場合、シリアルで適用されるため1つのプロセスのみがEXECUTE TRANSACTION
になり、他のプロセスはWAIT DEPENDENCY
で待機させられます。
例として、以下のようなSTATEになっている場合はlarge transactionが処理されており他の子プロセスが待機してしまっている状態の可能性が高いです。
set line 200 pages 200
break on inst_id on apply_name
select inst_id, apply_name, server_id, state
from gv$gg_apply_server
where inst_id = 2
order by 2,3;
INST_ID APPLY_NAME SERVER_ID STATE
------- ----------- ---------- --------------------
2 OGG$REP2 0 WAIT DEPENDENCY -- large transaction待ち
1 EXECUTE TRANSACTION
2 WAIT DEPENDENCY -- large transaction待ち
3 WAIT DEPENDENCY -- large transaction待ち
4 WAIT DEPENDENCY -- large transaction待ち
5 INACTIVE
WAIT DEPENDENCY
で待機している/させているオブジェクトの特定は以下のようにgv$goldengate_table_stats
の統計値を見ることで確認が可能です。
gv$goldengate_table_stats
のwait_dependenciesが大きい場合、他の子プロセスのlarge transactionの実行に阻害されて待機させられています。性能を改善したい場合は待機の原因となっているオブジェクトを別プロセスに分離することで、待機を解消し並列度を上げるといった方法が考えられます。
set tab off line 1000 pages 200 feed off
select
apply_name,
source_table_owner,
source_table_name,
destination_table_owner,
destination_table_name,
sum(total_inserts + total_updates+total_deletes) Total_Operations,
sum(wait_dependencies) Wait_Dependencies
from gv$goldengate_table_stats
group by apply_name, source_table_owner, source_table_name, destination_table_owner, destination_table_name
order by 1,2,3,4,5;
APPLY_NAME SOURCE_TABLE_OWNER SOURCE_TABLE_NAME DESTINATION_TABLE_OWNER DESTINATION_TABLE_NAME TOTAL_OPERATIONS WAIT_DEPENDENCIES
----------- ------------------- ------------------ ------------------------ ----------------------- ---------------- -----------------
OGG$REP1 FINANCE TABLE_1 HR TABLE_1 20597978 0
OGG$REP2 FINANCE TABLE_2 HR TABLE_2 17227673 45872 -- wait dependenciyでの待機が増えており競合がありうる
OGG$REP2 FINANCE TABLE_3 HR TABLE_3 19574793 0
-- 上記以外にも様々な統計値が確認できるため、以下のような項目も調べるとよいかと思います
set tab off line 1000 pages 200 feed off
select
apply_name,
source_table_owner,
source_table_name,
destination_table_owner,
destination_table_name,
sum(total_inserts + total_updates+total_deletes) Total_Operations,
sum(total_inserts) Total_Inserts,
sum(total_updates) Total_Updates,
sum(total_deletes) Total_Deletes,
sum(insert_collisions) Insert_Collisions,
sum(update_collisions) Update_Collisions,
sum(delete_collisions) Delete_Collisions,
sum(reperror_records) Reperror_Discards,
sum(reperror_ignores) Reperror_Ignores,
sum(wait_dependencies) Wait_Dependencies
from gv$goldengate_table_stats
group by apply_name, source_table_owner, source_table_name, destination_table_owner, destination_table_name
order by 1,2,3,4,5;
APPLY_NAME SOURCE_TABLE_OWNER SOURCE_TABLE_NAME DESTINATION_TABLE_OWNER DESTINATION_TABLE_NAME TOTAL_OPERATIONS TOTAL_INSERTS TOTAL_UPDATES TOTAL_DELETES INSERT_COLLISIONS UPDATE_COLLISIONS DELETE_COLLISIONS REPERROR_DISCARDS REPERROR_IGNORES WAIT_DEPENDENCIES
----------- ------------------- ------------------ ------------------------ ----------------------- ---------------- ------------- ------------- ------------- ----------------- ----------------- ----------------- ----------------- ---------------- -----------------
OGG$REP1 FINANCE TABLE_1 HR TABLE_4 20597978 20597978 0 0 0 0 0 0 0 0
OGG$REP2 FINANCE TABLE_2 HR TABLE_5 17227673 17227673 0 0 0 0 0 0 0 0
OGG$REP3 FINANCE TABLE_3 HR TABLE_6 19574793 906089 18668704 0 0 0 0 0 0 0
シリアル処理(シーケンス操作、DDL)の調査
シーケンスやDDLも強制的にシリアル処理となる処理ですが、これらが原因で待機が発生しているかはgv$gg_apply_receiver
に手がかりがあるケースが多いです。
私がこれまで構築した中ではプロセスがWaiting for Replicat flush request to complete
での待機はシーケンスやDDLで待たされているケースが多く、これらの待機が見受けられる場合はシーケンスやDDLがネックになっていないか疑った方が良いでしょう。
set line 400 pages 200 tab off
select
apply_name,
total_messages_received,
total_available_messages,
state rcvstate,
last_received_msg_position,
acknowledgement_position
from gv$gg_apply_receiver
order by 1;
APPLY_NAME TOTAL_MESSAGES_RECEIVED TOTAL_AVAILABLE_MESSAGES RCVSTATE LAST_RECEIVED_MSG_PO ACKNOWLEDGEMENT_POSI
----------- ----------------------- ------------------------ ---------------------------------------------- -------------------- --------------------
OGG$REP1 21837584 0 Waiting for message from client 96272047041 96272046238
OGG$REP2 19056004 37 Waiting for Replicat flush request to complete 96271648329 96271648329 -- シーケンスかDDLによる待機
OGG$REP3 20589910 0 Waiting for message from client 96271972353 96271662925
上記の方法以外には、DDLが適用されている場合はggserr.logに該当DDL文が出力されるためログの確認が最も楽な手段となります。
シーケンスやDDLがネックになるケースでもlarge transactionの際と同様にプロセスを分割して対象オブジェクトを分けることで性能改善できる可能性があります。
その他のパラレル実行時の注意
ワークロードによってはパラレル実行する際にdead lockが発生するケースがありえます。このケースは厄介で、replicatがdead lockで待機してハングしたような状態になってしまいます(おそらくreplicatはstopも受け付けないでしょう)。
dead lockが出ている場合はアラートログにdead lockが出た旨のエラーが出ているはずですので、アラートログの確認が有効です。ある程度は並列度を下げることでdead lockは抑止できるため、並列度の調整が必要になるでしょう。
性能面で許容できるならシリアルにしてしまえば確実に発生は防げます。
Replicatの操作例
パラメータの変更(PARALLELISM, EAGER_SIZE)
この記事で紹介したPARALLELISM
やeager_size
を変更する場合、replicatのパラメータファイルに以下のように記載します。
DBOPTIONS INTEGRATEDPARAMS (PARALLELISM 8, EAGER_SIZE 25000)
DBOPTIONS INTEGRATEDPARAMS
のその他のパラメータは以下を参照ください。
プロセスの分割例
以下では例として単一プロセス構成でのreplicatを3プロセスに分割します。各プロセスはRACの別々のインスタンスに接続する形とします。
まず、各ノード指定で接続するためのcredentialを追加します。
$ ./ggsci
GGSCI> ALTER CREDENTIALSTORE ADD USER ggadm@dbserver1:1521/instance1, ALIAS ggadm_instance1
GGSCI> ALTER CREDENTIALSTORE ADD USER ggadm@dbserver2:1521/instance2, ALIAS ggadm_instance2
GGSCI> ALTER CREDENTIALSTORE ADD USER ggadm@dbserver3:1521/instance3, ALIAS ggadm_instance3
# 各replicatに上述のcredentialを割り当てる
------------------------------------------
REPLICAT rep1
USERIDALIAS ggadm_instance1
...(略)...
続いて既存のreplicatを停止して静止点を作り、Trail, RBAの位置を確認します。確認した値でreplicatプロセスの位置を調整しつつプロセス追加します。
$ ./ggsci
GGSCI> stop replicat rep
GGSCI> info replicat rep
# ここではLog Read Checkpointのトレイルファイルの番号とRBAを確認する。以下のように出力されているはず
REPLICAT REP Last Started 2022-07-01 11:18 Status RUNNING
INTEGRATED
Checkpoint Lag 142:03:51 (updated 00:30:29 ago)
Process ID 75261
Log Read Checkpoint File /gg_trail/trails/tr000012575 # <-- ここのファイルの番号の部分(12575)
2022-06-28 20:10:03.310164 RBA 26483779 # <-- ここのRBAの値(26483779)
GGSCI> add replicat rep1, integrated, exttrail /gg_trail/trails/tr, extseqno [trailファイル番号], extrba [RBA番号]
GGSCI> add replicat rep2, integrated, exttrail /gg_trail/trails/tr, extseqno [trailファイル番号], extrba [RBA番号]
GGSCI> add replicat rep3, integrated, exttrail /gg_trail/trails/tr, extseqno [trailファイル番号], extrba [RBA番号]
例)
GGSCI> add replicat rep1, integrated, exttrail /gg_trail/trails/tr, extseqno 12575, extrba 26483779
分割元のreplicatの適用済みSCNを確認し、aftercsn指定で分割後のreplicatを起動します。
$ sqlplus / as sysdba
SQL> alter session set container=[pdbname];
SQL> col SERVER_NAME for a15
col APPLIED_HIGH_POSITION for a20
select SERVER_NAME, APPLIED_HIGH_POSITION from dba_gg_inbound_progress;
SERVER_NAME APPLIED_HIGH_POSITIO
------------ --------------------
OGG$REP 96272266383
# 上記で確認したAPPLIED_HIGH_POSITIONを適用済みのSCNとして使う
# afterscn付きでstartしないと適用するトランザクションの重複等でエラーになるため注意する
$ ./ggsci
GGSCI> start replicat rep1, afterscn [上記のAPPLIED_HIGH_POSITIO]
GGSCI> start replicat rep2, afterscn [上記のAPPLIED_HIGH_POSITIO]
GGSCI> start replicat rep3, afterscn [上記のAPPLIED_HIGH_POSITIO]
例)
GGSCI> start replicat rep1, afterscn 96272266383