二相コミットプロトコル
1つのノードに閉じたトランザクションについては、1つのデータベースサーバの場合と同じように動作します。中央管理ノードを経由して、データノードにアクセスした場合、下記のようになります。
更新トランザクションの場合、自動的に二相コミットになります。二相コミットにより、トランザクションは、全てのノードでコミットされたか、全てのノードでアボートされたかのいずれかであることが保証されます。単一データノードの更新であっても二相コミットが使用されます。
二相コミットは自動で実行されるため、使用者は明示的に“PREPARE TRANSACTION”を使用することができません。
二相コミットは、各データノードに2回ずつアクセスする必要があるため、その分の時間がかかります。
読み込みトランザクションのみが実行された場合、二相コミットは必要ありません。
第1フェーズ
データノード上の関連するすべてのトランザクションを準備(PREPARE)します。PREPAREの際に、外部トランザクションに一意のグローバルID(GID)が割り当てられます。
GIDフォーマット: postgres_scaleout_fdw_<fxid>_<umid>_<procid>_<cluster_name>
fxid: 中央管理ノードでのトランザクションID
umid: ユーザーマッピングOID
procid: 中央管理ノードでのプロセスID
cluster_name: 中央管理ノードに設定されているcluster_name
中央管理ノードでローカルコミット
すべてのトランザクションを準備したら、中央管理ノードはトランザクションをローカルにコミットします。トランザクションの状態を管理するため、レコードをpostgres_scaleout_fdw.xact_commitsテーブルに挿入します。
postgres_scaleout_fdw.xact_commitsのレコード:
列名 | データ型 | 詳細 |
---|---|---|
fxid | xid8 | 実行中のローカルトランザクションおよび外部準備済み(未解決)トランザクションに割り当てられたフルトランザクションIDの最小値 |
umids | oid[] | 最小フルトランザクションIDをフェッチしたサーバに対応するユーザーマッピングOIDのリスト |
また、内部的に、prefixがpostgres_scaleout_fdwの論理デコードのメッセージがWALに出力されます。
第2フェーズ
準備されたトランザクションは、中央管理ノードでのローカルトランザクションの結果に応じてコミットまたはロールバックされます。
読み取りトランザクションのみが実行された場合、ローカルおよび外部トランザクションをコミットするために二相コミットは必要ありません。中央管理ノードが直接データノードにCOMMITを送信し、結果を確認します。中央管理ノードはローカルでコミットします。COMMIT送信後、中央管理ノードがデータノードからのシグナルを受信しない場合(クラッシュなど)、中央管理ノードはデータノードにROLLBACKを送信します。
二相コミットのコミット処理中にいずれかのノードがダウンしたときには、リゾルバプロセスが自動でインダウト状態の解決を行います。
リゾルバランチャー:インスタンスに1つ起動されます。データベースごとに1つのリゾルバワーカーを起動します。postgres_scaleout_fdw.resolver_time_intervalごとに、新たなデータベースが作成されていないか確認します。
リゾルバワーカー:postgres_scaleout_fdw.resolver_time_intervalごとに、データノード上のインダウト状態のトランザクションを解決し、解決した外部トランザクションのテーブルレコードを削除します。
リゾルバワーカーは、pg_xact_status()とpostgres_scaleout_fdw.xact_commits テーブルを参照し、トランザクションをコミットするかロールバックするかを検証しています。
検証が完了すればpostgres_scaleout_fdw.xact_commitsのレコードは不要になるため、レコードを削除します。
下図は、中央管理ノードのローカルコミット前に、準備されていないトランザクションでデータノードがクラッシュします。中央管理ノードは、分散トランザクションをロールバックします。
下図は、ローカルコミット後に中央管理ノードがクラッシュします。リゾルバ処理は、外部トランザクションをコミットしようとし続けます。
下図は、ローカルコミット後にデータノードがクラッシュします。解決中にクラッシュしたデータノードが復旧されると、WALから情報が復旧され、リゾルバ処理は未確定の外部トランザクションを解決します。
注意
リゾルバプロセスは上記のように動作するため、アプリケーションにCOMMITが返った場合でも、リゾルバ処理が動作するまでの間は、当該トランザクションによる更新が可視にならない場合があります。
参考
リゾルバワーカーは、インダウト状態のトランザクションがないか確認するためにデータベースへの接続やSQLアクセスにより監視を行います。この際のアプリケーション名は‘resolver_worker’です。