Group Commit#

コミットスコープの種類 GROUP COMMIT

概要#

グループコミットの目標は、単一ノードの障害または一時的な停止が発生した場合のデータの損失から保護することです。これは、 COMMIT時にトランザクションを正常に確認するために複数のPGDノードを必要とすることにより実現します。確認はトランザクション処理のさまざまなポイントで送信できますが、トランザクションがディスクにフラッシュされ、他のすべてのトランザクションから見える場合、デフォルトの「可視」になります。

例#

SELECT bdr.add_commit_scope(
    commit_scope_name := example_scope,
    origin_node_group := left_dc,
    rule := ALL (left_dc) GROUP COMMIT(commit_decision=raft) AND ANY 1 (right_dc) GROUP COMMIT,
    wait_for_ready := true
);

この例では、 left_dcグループのすべてのノードとright_dcグループのいずれかのノードがコミットされたトランザクションを受信し、正常に確認する必要があるコミットスコープを作成します。

要件#

通常のオペレーションでは、グループコミットはアプリケーションに対して透過的です。フェールオーバー中に進行していたトランザクションには、アプリケーションまたは間のプロキシによってトリガーまたは統合される調整フェーズが必要です。このアクティビティは現在、元のノードが復旧した場合、またはクラスターから分離された場合にのみ発生します。この動作は、Postgresの古いビルトイン同期レプリケーションの場合と同じです。

グループコミットでコミットされたトランザクションは、その下で 2フェーズコミット2PC を使用します。したがって、ノードごとに発生するこのようなすべてのトランザクションを処理できるように十分に高いmax_prepared_transactions を構成します。

制限事項#

Limitations セクションのGroup Commitセクションを参照してください。

構成#

グループコミットを使用するには、最初に コミットスコープ を定義します。コミットスコープは、トランザクションのコミットに関係するPGDノードを決定します。

確認#

Confirmation Level

Group Commit Handling

received

A remote PGD node confirms the transaction immediately after receiving it, prior to starting the local application.

replicated

Confirms after applying changes of the transaction but before flushing them to disk.

durable

Confirms the transaction after all of its changes are flushed to disk.

visible (default)

Confirms the transaction after all of its changes are flushed to disk and it's visible to concurrent transactions.

動作#

Group Commitの動作は、コミットスコープによって適用される構成によって異なります。

決定をコミットする#

group 、partner 、およびraft の3つの方法でコミットを決定するようにグループコミットを構成できます。

group 決定がデフォルトです。コミットスコープグループで必要な数の確認を受け取ったときに、起点ノードによってコミットが確認されることを指定します。違いは、コミットの決定がPREPAREレプリケーションに基づいて行われるのに対し、耐久性はCOMMIT (PREPARED)レプリケーションをチェックすることです。

partner 決定は、

Commit At Most Once が使用するものです。このアプローチは、ノードグループに2つのデータノードが存在する場合にのみ機能します。これらの2つのノードはお互いのパートナーであり、オリジンではなくレプリカが何かをコミットするかどうかを決定します。このアプローチでは、アプリケーションが何らかの形でコンセンサスの一部であるため、

CAMOトランザクションプロトコルを使用して正常に動作するには、アプリケーションの変更が必要です。このアプローチの詳細については、

CAMOまたはコミット・アット・モスト・ワンス を参照してください。

raft 決定は、コミット決定にPGDビルトインのraftコンセンサスを使用します。 raft 決定を使用すると、パフォーマンスが低下する可能性があります。現在、 ALLコミットスコープグループでGROUP COMMITを使用する場合にのみ必要です。

ALLコミットスコープグループを使用するには、 トランザクション調整 問題を回避するためにコミット決定をraftに設定する必要があります。

競合の解決#

競合の解決はasync またはeager です。

非同期とは、PGDが、特定のノードに構成されている行レベルの解決を使用して、レプリケーション中にオプティミスティック競合解決を行うことを意味します。これは、元のトランザクションがコミットされたか、まだ進行中であるかに関係なく発生します。非同期競合解決の仕組みの詳細については、

競合 を参照してください。

Eagerとは、競合がCOMMIT契約の一部として熱心に解決され、競合するトランザクションがシリアル化エラーで中止されることを意味します。このアプローチは、パフォーマンスを犠牲にして非同期解決よりも高い分離を提供します。

ALLコミットスコープグループを使用するには、リコンシリエーションの問題を回避するために、

決定をコミットする をraft に設定する必要があります。

Eager競合解決の仕組みの詳細については、

Eager conflict resolution を参照してください。

アボート#

COMMITでコンセンサスを取得できないトランザクションが永久にハングしないように、 ABORT ON 句でタイムアウトを指定できます。タイムアウトの後、トランザクションのアボートが要求されます。アボート要求が送信されたときにトランザクションがコミットされることが既に決定されている場合、クライアントがアボートメッセージを受信する場合でも、トランザクションは最終的にCOMMITします。

Limitations も参照してください。

トランザクション調整#

オリジナルノードでのグループコミットトランザクションのコミットは、暗黙的に2フェーズコミットに変換されます。

最初のフェーズ準備では、トランザクションがローカルで準備され、コミットの準備が整います。データは永続化されますが、この段階ではコミットされていないため、他のトランザクションはこのトランザクションによって行われた変更を認識できません。この準備されたトランザクションは、通常の論理レプリケーションを介して残りのすべてのノードにコピーされます。

オリジンノードは、グループコミット文法のルールに従って、他のノードからの確認を求めます。クラスター内の最小限必要なノードから確認を取得した場合、このトランザクションをコミットすることを決定し、第2フェーズコミットに進み、そこでレプリケーションを介してこの決定を他のノードに送信し、同様にこのメッセージの取得で最終的にコミットします。

さまざまな段階で失敗する可能性があります。たとえば、オリジンノードは、トランザクションの準備後にクラッシュする場合があります。または、オリジンと1つ以上のレプリカがクラッシュする場合があります。

これにより、準備されたトランザクションがシステムに残ります。 Postgresのpg_prepared_xacts ビューは、システムで準備されたトランザクションを表示できます。準備されたトランザクションはロックおよびその他のリソースを保持している可能性があるため、アボートまたはコミットする必要があります。その決定は、ノードのコンセンサスで行う必要があります。

commit_決定がraft の場合、 raftはリコンシレーターとして機能し、これらのトランザクションは最終的に自動的にリコンサイルされます。

commit_決定がgroup の場合、トランザクションはraftを使用しません。代わりに、クラスター内の書き込みリードがリコンシリエーターの役割を実行します。これは、サブグループの変更に関して最も進んでいるノードであるためです。ノードがダウンしていることを検出し、ダウンしたノードをオリジンとして持っている可能性がある準備されたトランザクションを探すことにより、そのようなノードの調整を開始します。

このようなすべてのトランザクションについて、コミットスコープのルールに従ってノードに準備されたトランザクションがあるかどうかを確認し、決定を行います。この決定はraftを介して伝えられ、調整を行うにはノードの大部分が起動している必要があります。

このプロセスはバックグラウンドで発生し、これを制御または発行するために必要なユーザーコマンドはありません。