Group Commit (legacy)#

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

概要#

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

例#

SELECT bdr.create_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の古いビルトイン同期レプリケーションの場合と同じです。

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

制限事項#

Known issues and limitations のGroup Commitセクションを参照してください。

構成#

GROUP_COMMIT は、オプショナルのGROUP COMMIT パラメーター、ABORT ON およびDEGRADE ON 句をサポートしています。構成パラメーターの完全な説明については、

GROUP_COMMIT コミットスコープリファレンスを参照してください。または、 DEGRADE ON オプション一般の詳細については、 Degrading commit scope rules セクションを参照してください。

確認#

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 CAMOが使用するものです。このアプローチは、ノードグループに2つのデータノードが存在する場合にのみ機能します。これらの2つのノードはお互いのパートナーであり、オリジンではなくレプリカが何かをコミットするかどうかを決定します。このアプローチでは、アプリケーションが何らかの形でコンセンサスの一部であるため、 CAMOトランザクションプロトコルを使用して正常に動作するには、アプリケーションの変更が必要です。このアプローチの詳細については、 Commit At Most Once を参照してください。

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

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

競合の解決#

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

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

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

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

Eager競合解決の仕組みの詳細については、 熱心な競合解決 を参照してください。

アボート#

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

制限事項 も参照してください。

トランザクション調整#

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

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

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

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

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

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

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

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

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

熱心な競合解決#

Eager競合解決Eager Replicationとしても知られ、 COMMIT決定プロセス中にシリアル化可能なエラーで互いに競合するトランザクションをアボートすることにより、競合を防止します。

DDL overview の競合解決オプションの1つとして コミットスコープへの移行 を使用して構成します。

使用法#

迅速な競合解決を有効にするには、クライアントをコミットスコープに切り替える必要があります。ここで示すように、セッションレベルまたは個々のトランザクションでそれを使用します。

BEGIN;

SET LOCAL bdr.commit_scope = eager_scope;

... other commands possible...

クライアントは、トランザクションの最後にCOMMIT の発行を継続し、PGDに2つのフェーズを管理させることができます。

COMMIT;

この場合、 eager_scope コミットスコープは次のように定義されます。

SELECT bdr.create_commit_scope(
    commit_scope_name := eager_scope,
    origin_node_group := top_group,
    rule := ALL (top_group) GROUP COMMIT (conflict_resolution = eager, commit_decision = raft) ABORT ON (timeout = 60s),
    wait_for_ready := true
);

Eager競合解決ルールのコミットスコープグループは、ALL またはMAJORITY のみです。 ALL を使用する場合、 commit_decision 設定もraft に設定する必要があります。

エラー処理#

PGDがトランザクションを管理することを考えると、クライアントはCOMMIT の結果のみを確認する必要があります。これは、シングルノードのPostgresを含む、いかなる場合にもお勧めします。

オリジンノードに障害が発生した場合、残りのノードは最終的に少なくともABORT ON timeout の後、グローバルに準備されたトランザクションをロールバックすることを決定します。 Raftは、一貫性のないコミットとロールバックの決定を防ぎます。ただし、これには接続されたノードの大部分が必要です。切断されたノードは、必要に応じて最終的にコミットまたはロールバックするようにトランザクションを準備し続け、決定してさらに進行した可能性のあるノードの大部分と調整します。

Eager Replicationの効果一般#

アボート率の増加#

シングルノードPostgres、またはデフォルトの非同期レプリケーションモードのPGDでも、 COMMIT 時のエラーはほとんどありません。競合解決にeager を使用するコミットスコープの使用により追加された同期ステップも、エラーのソースも追加します。アプリケーションは、通常は再試行ループを適用することにより、このようなエラーを適切に処理するように準備する必要があります。

アボートの率は、ワークロードにのみ依存します。多くの行を変更する大規模なトランザクションは、他の同時トランザクションと競合する可能性が非常に高くなります。

MAJORITYおよびALLノードレプリケーション一般の影響#

コミットレイテンシーの増加#

コミットスコープの使用により同期ステップを追加すると、ノード間の通信が増加し、コミット時のレイテンシーが増加することを意味します。 ALL がコミットスコープで使用される場合、これは、ノードがダウンするとトランザクションが失敗するため、システムの可用性が低下することを意味します。

1つ以上のノードが遅延している場合、確認を取得する際の往復遅延が大きくなり、高遅延が発生する可能性があります。 ALLまたはMAJORITYノードレプリケーションでは、約2つのネットワークラウンドトリップ、最悪の場合、最も遠いピアノードまでが追加されます。論理スタンバイノードと、まだ参加またはキャッチアップ中のノードは含まれませんが、最終的に変更を受け取ります。

ピアノードがトランザクションのローカルでの準備を確認する前に、それをローカルに適用する必要があります。これにより、トランザクションのサイズによっては、コミットレイテンシーがさらに増加します。この設定はsynchronous_commit 設定とは無関係です。