Preventing conflicts#

地域分散PGDクラスターでは、すべての場所が同時に書き込みを受け入れます。競合は、レプリケーションが変更を伝播する前に、別のノードで同じデータが変更されると発生します。各ノードは変更をローカルにコミットし、レプリケーション中に他のノードから競合する変更を受信します。

PGDは、これらの衝突を検出して、自動的に解決しますが、自動解決はセーフティネットであり、良いデザインの代替ではありません。スキーマとアクセスパターンを設計して、競合が発生する頻度を最小限に抑えます。

PGDが競合を解決する方法を理解する#

PGDは、アプリケーションが関与せずに、ほとんどの競合を自動的に解決します。例外は、 error リゾルバーセットとの競合であり、レプリケーションを停止し、手動介入が必要です。他のすべての競合タイプの場合、それぞれに決定的なデフォルトリゾルバーがあります。どのリゾルバーが適用されるかを知ることは、自動解決が予想される結果を生成する場合と、生成しない場合を特定するのに役立ちます。すべての競合はbdr.conflict_history で追跡されます。

  • update_update 同じ行が2つの異なるノードで更新されました。 last-update-winsによって解決されました。

  • insert_insert 同じ主キーが2つの異なるノードに挿入されました。新しいタイムスタンプの行を維持することにより解決されました。

  • update_delete 行はあるノードで更新され、別のノードで削除されました。デフォルトでは、削除が優先されます。

  • delete_delete 行は両方のノードで同時に削除されました。データには関係ありませんが、ログに記録されます。

より難解なケースを含む競合タイプの完全なリストについては、 bdr_read_all_conflicts を参照してください。

競合を最小限に抑えるデザイン#

競合は、複数の場所が同じデータに同時に書き込まれている場合の症状です。それらを削減する最も効果的な方法は、各データの明確な所有場所を持つようにデータモデルをデザインすることです。

  • クラスター全体の一意のキーを使用します 自動インクリメントシーケンスはノードローカルであり、別のノードで同じ値を生成するため、 insert_insert 競合が発生します。クラスター全体で一意の主キーには、PGDのグローバルシーケンスタイプSnowflakeIdまたはgallocを使用します。クライアントサイドで生成されたUUIDも競合セーフですが、領域効率は低くなります。 PGDシーケンスオプションについては、 Sequences を参照してください。

  • 場所ごとにデータを分割する 各ユーザーまたはテナントが常に1つの場所に書き込む場合、そのデータに競合が発生することはできません。各ユーザー、テナント、またはデータパーティションをホームの場所に割り当て、そこに一貫して書き込みトラフィックをルーティングします。アカウント残高や在庫レベルなど、高い書き込み速度と厳密な一貫性要件を持つデータは、ロケーションベースのパーティショニングの良い候補です。製品カタログやルックアップテーブルなど、ほとんどが読み取られ、ほとんど変更されないデータは、競合のリスクなしでどこにでも書き込むことができます。

  • 可能であれば、追加専用パターンを使用します。 挿入のみを受信するテーブル監査ログ、イベントストリーム、時系列データは、更新または削除の競合を持つことはできません。これらのテーブルを挿入専用にデザインし、集計が必要な場合は別の概要テーブルを使用します。

  • 共有カウンターを回避します 複数の場所によってインクリメントされるカウンターは、発生を待機している競合です。代わりに、インクリメントを個々の行として記録し、読み取り時に集計するか、同時更新で正しくマージするように設計されたPGDのCRDTデータ型を使用します。 CRDTデータ型を使用した列レベルの競合の処理 を参照してください。

  • 長時間実行されるトランザクションを回避します 長期間ロックを保持するか、スナップショットを読み取るトランザクションは、競合する書き込みが別の場所から到着できるウィンドウを増加させます。トランザクションは短くしてください。

競合のモニタリング#

すべての競合タイプはbdr.conflict_history で追跡されます。 bdr.conflict_history_summary を定期的にチェックして、競合率の高いテーブルがないかどうかを確認します。

SELECT nspname, relname, conflict_type, count(*)
FROM bdr.conflict_history_summary
GROUP BY nspname, relname, conflict_type
ORDER BY count(*) DESC;

特定のテーブルでの高い競合率が持続する場合は、再検討する価値があるアクセスパターンを示しています。上記のデザインパターンを確認するか、アクセスパターンの変更が実現可能でない場合は、カスタム競合リゾルバーを検討してください。最近の競合に関係する実際の行値を検査するには

SELECT local_time, nspname, relname, conflict_type, conflict_resolution,
       key_tuple, local_tuple, remote_tuple, apply_tuple
FROM bdr.conflict_history
ORDER BY local_time DESC
LIMIT 20;

last-update-winsが誤った結果を生成し、アクセスパターンを変更できないテーブルの場合、 DBAにカスタム競合リゾルバーを構成するように依頼してください。 競合リゾルバーの構成 を参照してください。