PolarDB for PostgreSQL (Compatible with Oracle) では、レプリケーションの遅延によって古くなったデータが読み取られる可能性がある読み書き分離シナリオに対応するため、セッションの一貫性と結果整合性の 2 つの整合性レベルを提供します。ここでいう「整合性」は、ACID(原子性、整合性、隔離性、耐久性)における C(Consistency)を指します。
仕組み
PolarDB では、プライマリノードから読み取り専用ノードへデータを非同期で書き込み前方ログ(WAL)を転送することによりレプリケーションを行います。PolarProxy が読み書き分離を処理し、書き込み操作(INSERT、UPDATE、DELETE、CREATE)はプライマリノードに、SELECT 文は読み取り専用ノードにルーティングします。

レプリケーションは非同期であるため、読み取り専用ノードは一時的にプライマリノードと同期していないデータを返すことがあります。通常、この遅延は数ミリ秒程度ですが、大量の書き込み負荷(例:大規模テーブルへのカラム追加などの DDL 操作やバルクデータ挿入)下では増加します。この遅延がデータの不整合の根本原因です。
PolarProxy は各ノードで適用されたリドロッグ(redo log)を追跡し、各ログシーケンス番号(LSN)を記録します。プライマリノードが書き込みを処理すると、PolarProxy はその書き込みの LSN をセッション LSNとして記録します。その後、同一セッション内で実行される読み取り要求に対しては、PolarProxy がセッション LSN を各利用可能なノードの LSN と比較し、LSN がセッション LSN 以上であるノードにリクエストをルーティングします。

レプリケーションの効率を維持するため、PolarDB は選択されたノードがクライアントに応答を返す間に、他の読み取り専用ノードへのデータ複製を継続します。次の読み取り要求が到着する頃には、それらのノードもすでに最新の状態になっています。ほとんどのワークロードでは読み取り操作が書き込み操作よりも圧倒的に多いため、この方式により、読み書き分離および負荷分散を維持しつつ、セッションの一貫性を確保できます。
各レベルの概要
| レベル | 動作 | 使用するタイミング |
|---|---|---|
| セッションの一貫性 | 同一セッション内の読み取りは、常にそのセッション自身による書き込みを反映します。PolarProxy は、LSN が十分に最新である読み取り専用ノードが利用可能になるまで待機したうえでリクエストをルーティングします。 | ほとんどのアプリケーションシナリオ — 整合性と最小限のパフォーマンスオーバーヘッドのバランスをとる場合。 |
| 結果整合性 | 読み取りは、最終コミット済み書き込みより前の任意時点のデータを返す可能性があります。同一セッション内の異なる SELECT 文は、レプリケーションの遅延状況に応じて異なる結果を返すことがあります。 | 読み取り負荷が非常に高いワークロード — 読み取り専用ノードへの負荷分散が、読み書き後の即時可視性保証よりも優先される場合。 |
セッションの一貫性
セッションの一貫性(因果的一貫性とも呼ばれます)は、セッション内で読み取り要求の前に書き込まれたデータが、応答において常に可視であることを保証します。以下の実行シーケンスを例に説明します:
INSERT INTO t1(id, price) VALUES(111, 96);
UPDATE t1 SET price = 100 WHERE id=111;
SELECT price FROM t1;上記の SELECT 文は、他のノードにおけるレプリケーションの遅延に関係なく、同一セッション内では常に 100 を返します。
セッションの一貫性は、結果整合性と比較してクラスターに対するルーティング負荷がやや高くなりますが、そのオーバーヘッドは極めて小さいです。これは、大多数のアプリケーションシナリオにおける整合性要件を満たすことができ、推奨デフォルト設定です。
結果整合性
結果整合性では、各 SELECT 文は、最新の WAL を適用済みかどうかに関係なく、利用可能な読み取り専用ノードのいずれかにルーティングされます。同じ実行シーケンスを例にすると:
INSERT INTO t1(id, price) VALUES(111, 96);
UPDATE t1 SET price = 100 WHERE id=111;
SELECT price FROM t1;SELECT 文は、クエリ実行時のレプリケーション遅延の状況に応じて、96 または 100 のいずれかを返す可能性があります。同一セッション内で繰り返し実行しても、返される値が異なる場合があります。
プライマリノードへの負荷低減が最優先事項であり、アプリケーション側で読み書き後の短時間の不整合を許容できる場合に、結果整合性をご利用ください。
ベストプラクティス
ほとんどのシナリオではセッションの一貫性をご利用ください。 これは、クラスターのパフォーマンスへの影響を最小限に抑えつつ、大多数のアプリケーションが求める整合性要件を満たします。
厳密なセッション間整合性が必要な場合は、ヒントワードを使用して特定のクエリを強制的にプライマリノードにルーティングします:
/*FORCE_MASTER*/ select * from user;ヒントワードは最高のルーティング優先度を持ち、整合性レベルおよびトランザクション分割の設定をすべてオーバーライドします。ご利用前に、ワークロードへの影響を評価してください。ヒントワード内に環境変数を変更する文(例:/*FORCE_SLAVE*/ set names utf8;)を含めるとエラーが発生します。
次のステップ
クラスターの整合性レベルを変更するには、「PolarProxy の設定」をご参照ください。