読み書き分離機能により SELECT 文が読み取り専用ノードにルーティングされる際、非同期レプリケーションの影響でこれらのノードはプライマリノードに対して遅延している可能性があります。PolarDB for PostgreSQL では、アプリケーションがこのレプリケーションギャップをどのように扱うかを制御するため、2 種類の整合性レベル — 結果整合性とセッションの一貫性(トランザクションレベルの読み取り一貫性とも呼ばれます)— を提供しています。
仕組み
PolarDB はクラスタアーキテクチャで動作します。各クラスターにはプライマリノードと 1 つ以上の読み取り専用ノードが含まれます。クラスターへの接続には、次の 2 種類のエンドポイントタイプを使用します。
クラスターエンドポイント(推奨):すべてのノード間でトラフィックをルーティングし、読み書き分離を自動的に有効にします。
プライマリエンドポイント:すべてのトラフィックをプライマリノードのみにルーティングします。
組み込みのプロキシレイヤーが読み書き分離を処理します。このレイヤーは各 SQL ステートメントを解析し、書き込み操作(INSERT、UPDATE、DELETE、CREATE)をプライマリノードに、読み取り操作(SELECT)を読み取り専用ノードにルーティングします。
プライマリノードから読み取り専用ノードへのデータレプリケーションは、先行書き込みログ(WAL)に基づく非同期物理レプリケーションを使用します。通常の負荷下では、レプリケーションは数ミリ秒以内に完了します。軽い負荷下では、同期遅延を 5 秒未満に抑えることができます。ただし、大規模テーブルに対する DDL 操作や一括挿入などの重い負荷下では、同期遅延が大幅に増加する可能性があります。

レプリケーションが非同期であるため、読み取り専用ノードにルーティングされた SELECT は、プライマリノードでの最新の書き込みにまだ追いついていないデータを返す可能性があります。このギャップをどのように扱うかは、選択した整合性レベルによって決まります。
整合性レベル
| 結果整合性 | セッションの一貫性 | |
|---|---|---|
| 読み取り動作 | SELECT はレプリケーションの完了を待たずに、直ちに利用可能な任意の読み取り専用ノードにルーティングされます。 | SELECT は、現在のセッションにおける書き込みをすでに完了した読み取り専用ノードに転送されます。 |
| 古いデータの読み取り | 発生する可能性あり — ノードが最新のデータを持っていない場合があります。 | 同一セッション内では発生しません — 読み取りは常に同じセッション内の書き込みを反映します。 |
| パフォーマンス | スループットがわずかに向上し、待機時間がありません。 | ほとんどのワークロードでオーバーヘッドは最小限です。 |
| 適用範囲 | 短時間のレプリケーションラグが許容可能な分析、レポート、および読み取り中心のワークロード。 | 同一セッション内の読み取りが直近の書き込みを確実に反映する必要があるトランザクションワークロード。 |
結果整合性
結果整合性では、プロキシは各 SELECT を最新のデータを持っているかどうかを確認せずに、利用可能な任意の読み取り専用ノードにルーティングします。ノードは即座に結果を返します。
これにより、同一セッション内で書き込みの直後に読み取りを行っても、古いデータが返される可能性があります。
INSERT INTO t1(id, price) VALUES(111, 96);
UPDATE t1 SET price = 100 WHERE id=111;
SELECT price FROM t1;
-- 読み取り専用ノードがまだ書き込みをレプリケートしていない場合、96 または NULL が返される可能性があります結果整合性は、短時間のレプリケーションラグが許容可能なワークロード(スケジュールジョブ、分析クエリ、集計レポート、またはデータを書き込まないユーザーによる読み取り専用アクセス)に適しています。
セッションの一貫性
セッションの一貫性では、プロキシがセッション内で書き込みが行われた後、続く読み取りをその書き込みをすでに適用済みの読み取り専用ノードにのみルーティングすることを保証します。SELECT は条件を満たすノードに転送され、最新の結果を返します。
同じ例でも、次のように予測可能な動作になります。
INSERT INTO t1(id, price) VALUES(111, 96);
UPDATE t1 SET price = 100 WHERE id=111;
SELECT price FROM t1;
-- 必ず 100 が返されますセッションの一貫性はほとんどのワークロードで最小限のオーバーヘッドしか発生せず、トランザクションユースケースの大部分をカバーします。ユーザーが自身の直近の書き込みを読み取る必要があるアプリケーションでは、デフォルトとして使用してください。
セッションの一貫性の仕組み

プロキシは、ログシーケンス番号(LSN)を使用して各ノードのリドゥログの進捗状況を追跡します。プライマリノードで書き込みがコミットされると、プロキシはその書き込みの LSN をセッション LSN として記録します。
同一セッションで次の読み取りが到着すると、プロキシはセッション LSN と各読み取り専用ノードの LSN を比較します。そして、LSN がセッション LSN 以上であるノードに読み取りを転送することで、そのノードが書き込みを適用済みであることを保証します。選択されたノードがクライアントに結果を返している間、他のノードはバックグラウンドで引き続きレプリケーションを実行します。
このメカニズムにより、セッションの一貫性、読み書き分離、および負荷分散を同時に実現します。
ベストプラクティス
ほとんどのワークロードではセッションの一貫性を使用してください。 クラスターのパフォーマンスへの影響は最小限であり、アプリケーションが直前に書き込んだデータを読み取る一般的なケースに対応できます。
セッションの境界に関係なく絶対に最新のデータを読み取る必要があるクエリについては、FORCE_MASTER ヒントワードを使用してプライマリノードにリダイレクトします。
/*FORCE_MASTER*/ select * from user;FORCE_MASTER は特定のクエリに限定して使用し、広範囲にわたって使用しないでください。すべての読み取りをプライマリノードにルーティングすると、読み書き分離の利点が失われ、プライマリノードの負荷が増大します。