PolarDBは、さまざまなシナリオで整合性レベルの要件を満たすために、最終的な整合性とトランザクションレベルの読み取り整合性を提供します。
アーキテクチャ
PolarDBはクラスタアーキテクチャで実行されます。 各クラスターには、プライマリノードと1つ以上の読み取り専用ノードが含まれます。 クライアントは、クラスターエンドポイントとプライマリエンドポイントの2種類のエンドポイントを使用して、PolarDBクラスターに接続できます。 クラスターエンドポイントを使用して、クラスター内のすべてのノードへのアクセスを有効にし、読み書き分離を実装することを推奨します。
PolarDB for PostgreSQLの読み書き分割
プライマリデータベースからセカンダリノードへのデータレプリケーションは簡単な方法です。 プライマリデータベースの先行書き込みログ (WAL) をセカンダリデータベースに非同期に転送するだけです。 データ複製により、セカンダリデータベースでクエリを処理できます。 これにより、プライマリデータベースのワークロードが削減され、高可用性が確保されます。
ただし、読み取り専用ノードを使用してクエリを処理する場合は、次の問題を考慮する必要があります。
- 1. クライアントは、2つのエンドポイントを介してプライマリデータベースとセカンダリデータベースに接続できます。 アプリケーションの接続のエンドポイントを指定する必要があります。
- 2. PolarDB for PostgreSQLはデータを非同期に複製します。 クライアントがデータ変更をコミットした直後に、データを読み取りレプリカに同期させることはできません。 したがって、読み取り専用ノードのデータは最新ではない可能性があります。 これは、データの整合性が保証されないことを示す。
問題1を修正するために、PolarDBは読み書き分離プロキシを使用します。 プロキシは、PolarDB for PostgreSQLクラスターのクライアントとの接続を確立し、クライアントからの各クエリを解析します。 UPDATE、DELETE、INSERT、CREATEなどの書き込み要求をプライマリノードに送信します。 ただし、SELECTなどの読み取り要求は読み取り専用ノードに送信されます。
ただし、同期レイテンシによるデータの不整合は解決されません。 SELECTステートメントを実行して読み取り専用ノードからデータを取得すると、返されるデータがプライマリノードに格納されているデータと一致しない可能性があります。 PolarDB for PostgreSQLクラスターの負荷が軽い場合、同期レイテンシを5秒未満に短縮できます。 重い負荷を伴うシナリオでは、同期レイテンシが大幅に増加する可能性があります。 たとえば、クラスターがデータ定義言語 (DDL) ステートメントを実行して、大きなテーブルに列を追加したり、大量のデータを挿入したりする必要がある場合に発生します。
最終的な一貫性とセッションの一貫性
- 最終的な整合性: PolarDBは、非同期物理レプリケーションを使用して、プライマリデータベースからセカンダリデータベースにデータを同期します。 プライマリデータベースの更新は、セカンダリデータベースにレプリケートされます。 ほとんどの場合、データ変更は、数ミリ秒のレイテンシでセカンダリデータベースに同期されます。 レイテンシは、プライマリデータベースの書き込み要求の負荷に基づいています。 これにより、非同期レプリケーションによって最終的な一貫性を実現できます。
- セッションの一貫性: セッションの一貫性は、最終的な一貫性に達する前に発生するデータの一貫性の問題を解決するために使用されます。 物理レプリケーションは高速です。 この機能に基づいて、PolarDBは非同期レプリケーションを完了した読み取り専用ノードにクエリを転送します。 詳細については、「実装」をご参照ください。
読み書き分離に基づくセッションの整合性
PolarDBは、読み書き分離アーキテクチャで実行されます。 従来の読み書き分離では、最終的な一貫性のみを保証できます。 プライマリノードから読み取り専用ノードへのデータレプリケーションには、レイテンシが存在します。 これは、同じクエリに対して異なるノードによって返される異なる応答をもたらす可能性がある。 たとえば、セッション内で次のステートメントを実行できます。
INSERT INTO t1(id、price) 値 (111、96);
UPDATE t1 SET price = 100 WHERE id=111;
SELECT価格からt1;
この例では、データが更新されていない読み取り専用ノードにPolarDBがSELECTリクエストを送信する可能性があるため、最後のクエリの結果は無効になります。 この問題を防ぐには、アプリケーションを変更します。 最も一般的な解決策は、ワークロードを分割することです。 高い一貫性が必要なワークロードの場合、リクエストはプライマリデータベースにのみ送信されます。 最終的に一貫性が必要なワークロードの場合、書き込み要求はプライマリデータベースに送信され、読み取り要求はセカンダリデータベースに送信されます。 しかし、この解決策は、アプリケーション開発をより複雑にし、プライマリデータベースの負荷を増大させ、読み書き分離性能を低下させる。
この問題に対処するために、PolarDBはセッションの一貫性を提供します。 同じセッション内で、読み取り要求は、データが更新された読み取り専用ノードに送信されます。 このようにして、文は読み取り専用ノード上の最新のデータのみを照会するために使用されます。
実装
PolarDBは、中間層 (プロキシ) を使用して読み書き分離を実現します。 プロキシは、各ノードに適用されるRedoログを追跡し、各ログシーケンス番号 (LSN) を記録します。 データが一次データベース内で更新されると、新しい更新のLSNがセッションLSNとして記録される。 新しい読み取り要求が到着すると、プロキシはセッションLSNをセカンダリデータベースのLSNと比較します。 それは、セッションレベルの一貫性を達成するために、LSNがセッションLSN以上である二次データベースに要求を転送する。 効率的な同期を確保するために、他のセカンダリデータベースへのレプリケーションが処理されている間、セカンダリデータベースは結果をクライアントに返します。 これにより、セカンダリデータベースは後続の読み取り要求が到着する前にデータを更新できます。 読み取りが書き込みよりも重いほとんどのシナリオでは、このメカニズムにより、セッションの一貫性、読み取り /書き込み分割、および負荷分散が保証されます。
整合性レベル選択のベストプラクティス
セッションの一貫性を使用することを推奨します。 この一貫性レベルは、クラスタのパフォーマンスに最小限の影響しか与えず、ほとんどのシナリオをサポートします。
次のソリューションを適用して、セッション間の一貫性を実現できます。
ヒントを使用して、特定のクエリをプライマリデータベースに強制的にリダイレクトします。
例: /* FORCE_MASTER */ select * from user;