このトピックでは、PolarDB for PostgreSQL クラスタの先行書き込みログ (WAL) 並列再生機能について説明します。
前提条件
PolarDB for PostgreSQL クラスタで、以下のいずれかのデータベースエンジンバージョンが実行されている必要があります。
PolarDB for PostgreSQL 16 リビジョンバージョン 2.0.16.3.1.1 以降。
PolarDB for PostgreSQL 15 リビジョンバージョン 2.0.15.7.1.1 以降。
PolarDB for PostgreSQL 14 リビジョンバージョン 2.0.14.5.1.0 以降。
PolarDB for PostgreSQL 11 リビジョンバージョン 2.0.11.9.17.0 以降。
PolarDB コンソールで、または 文を実行することで、クラスタの リビジョンバージョンを確認SHOW polardb_version;できます。リビジョンバージョンが要件を満たしていない場合は、更新してください。
背景情報
PolarDB for PostgreSQL クラスタは、プライマリノードと 1 つ以上の読み取り専用ノードで構成されます。読み取り専用ノードが読み取りリクエストを処理している間、バックグラウンドワーカープロセスとバックエンドプロセスは、LogIndex を使用して異なるバッファで WAL を再生します。これにより、WAL レコードの並列再生が実現します。
WAL レコードの再生は PolarDB クラスタの高可用性にとって不可欠であるため、標準の WAL 再生プロセスでこの並列ログ再生方式を採用することで、システムの最適化に貢献します。
WAL レコードの並列再生は、以下のシナリオで役立ちます。
プライマリノード、読み取り専用ノード、およびセカンダリノードのクラッシュリカバリ。
読み取り専用ノードで LogIndex データを使用してバックグラウンドワーカープロセスによって WAL レコードを継続的に再生する。
セカンダリノードで実行されている起動プロセスによって WAL レコードを継続的に再生する。
用語
ブロック: データブロック。
WAL: 先行書き込みログ。
タスクノード: サブタスクが実行されるノード。タスクノードは、一度に 1 つのサブタスクを受信して実行します。
タスクタグ: サブタスクタイプの識別子。同じタイプのサブタスクは特定の順序で実行されます。
タスク保留リスト: 並列実行フレームワークで再生サブタスクをスケジュールするために各子プロセスが使用するリスト。
WAL レコードの並列再生の仕組み
概要
1 つの WAL レコードには、複数のデータブロックへの変更が含まれる場合があります。
ithWAL エントリ (LSN はLSNi) にm個のデータブロックへの変更が記録されているとします。いくつかの概念は次のように定義されます。ithWAL エントリに記録された変更済みデータブロックのリストは、Blocki=[Blocki,0, Blocki,1,..., Blocki,m]として定義されます。最小リプレイサブタスクは、
Taski,j=LSNi->Blocki,jとして定義されます。これは、ithWAL レコードのBlocki,jへのリプレイを示します。m個のデータブロックへの変更を記録する ith WAL エントリは、m個の再生サブタスクのグループとして表すことができます。TASKi,∗=[Taski,0, Taski,1, ..., Taski,m]。複数の WAL エントリは、再生サブタスクグループのコレクションとして表されます。
TASK∗,∗=[Task0,∗, Task1,∗, ..., TaskN,∗]。
Task∗,∗では、サブタスクは常に前のサブタスクに依存するわけではありません。サブタスクグループのコレクションが
TASK∗,∗=[Task0,∗,Task1,∗,Task2,∗]であるとします。ここで、Task0,∗=[Task0,0,Task0,1,Task0,2]Task1,∗=[Task1,0,Task1,1]Task2,∗=[Task2,0]
であり、Block0,0=Block1,0、Block0,1=Block1,1、Block0,2=Block2,0 です。
3 つの再生サブタスクのペア [Task0,0,Task1,0]、[Task0,1,Task1,1]、[Task0,2,Task2,0] を並列に実行できます。
要約すると、WAL レコードを表す多くのサブタスクグループは、最終結果の整合性に影響を与えることなく並列に実行できます。この考えに基づいて、PolarDB は並列タスク実行のフレームワークを導入し、このフレームワークを WAL レコード再生プロセスに組み込みました。
並列タスク実行のフレームワーク
共有メモリは、同時プロセスの数に基づいて均等に分割されます。各セグメントは、プロセスに割り当てられた循環キューです。循環キューの深さはパラメータで構成されます。

ディスパッチャプロセス
タスクを指定されたプロセスに配信することにより、同時スケジューリングを制御します。
実行されたタスクを循環キューから削除します。
プロセスプール
プール内の各プロセスは、対応する循環キューからタスクを取得し、その状態に基づいてタスクを実行するかどうかを決定します。

タスク
循環キューはタスクノードで構成されます。タスクノードは、
idle、running、hold、finished、removedの 5 つの状態になる可能性があります。idle: タスクノードにタスクが割り当てられていません。running: タスクノードにタスクが割り当てられており、実行中または実行予定です。hold: タスクノードに、別のタスクに依存するタスクが割り当てられており、その実行を待機する必要があります。finished: タスクノードのタスクが実行されました。removed: ディスパッチャプロセスがタスクとその前提条件タスクを循環キューから削除しました。タスクノードのタスクが完了すると、その前提条件タスクも完了する必要があるため、すべて安全に削除できます。このメカニズムにより、ディスパッチャプロセスは依存関係の順序でタスクの実行結果を処理できます。
前の図では、黒でマークされた状態遷移はディスパッチャプロセスによって実行され、オレンジでマークされた状態遷移はプロセスプールによって実装されます。ディスパッチャプロセス
ディスパッチャプロセスには、タスク HashMap、タスク実行キュー、タスクアイドルノードという 3 つの重要なデータ構造があります。
タスク HashMap: タスクタグとタスク間のハッシュマッピングを記録します。
各タスクにはタスクタグが割り当てられます。依存タスクは同じタスクタグを持ちます。
タスクノードのタスクに前提条件がある場合、前提条件タスクが完了するまで、タスクノードは保留状態になります。
タスク実行キュー: 実行中のタスクを記録します。
タスクアイドルノード: プロセスプール内のさまざまなプロセスの
idleタスクノードを記録します。
ディスパッチャのスケジューリング戦略:
優先的に、同じタスクタグを持つタスクを実行し、直接の前提条件であるプロセスにタスクを割り当てます。目的は、依存タスクを同じプロセスに割り当てることによって、プロセス間の同期のオーバーヘッドを削減することです。
優先プロセスにフルキューがある場合、または同じタスクタグを持つタスクを実行しているプロセスがない場合、ディスパッチャはプロセスプールからプロセスを順番に選択し、
idle状態のタスクノードにタスクを割り当てます。このようにして、タスクはさまざまなプロセスに均等に分散されます。

プロセスプール
並列実行メカニズムは、同じタスクノードデータ構造を持つタスクに使用されます。プロセスプールの初期化中に
SchedContextが構成され、タスク実行の関数ポインタが指定されます。TaskStartup: プロセスが割り当てられたタスクを実行できるようになる前の初期化操作。
TaskHandler: 割り当てられたタスクを実行します。
TaskCleanup: プロセスが終了する前のクリーンアップ操作。

プロセスプール内のプロセスは、循環キューからタスクノードを取得します。タスクノードが
hold状態の場合、プロセスはタスクノードをhold listの末尾に挿入します。タスクノードがrunning状態の場合、プロセスはTaskHandlerを呼び出します。これが失敗した場合、プロセスはデフォルトで保留カウント 3 を割り当て、このタスクノードをhold listの先頭に付加します。
プロセスは、
hold listを先頭から末尾までスキャンします。runningタスクノードが見つかると、プロセスはタスクノードの保留カウントを確認します。保留カウントが 0 の場合、タスクは実行されます。保留カウントが 0 より大きい場合は、1 ずつ減ります。保留リストのスキャンプロセスを次の図に示します。
WAL レコードの並列再生
LogIndex は、WAL エントリと変更されたデータブロック間のマッピングを記録します。LSN で取得できます。PolarDB は、読み取り専用ノードで WAL レコードが継続的に再生されるときに、並列タスク実行のフレームワークを導入します。LogIndex データと併用することで、WAL の並列再生により、プライマリノードと読み取り専用ノード間のデータ同期が高速化されます。
ワークフロー
起動プロセスは WAL を解析し、WAL を再生せずに LogIndex データを構築します。
並列再生フレームワークのディスパッチャプロセスである LogIndex BG Writer プロセスは、LSN を使用して LogIndex データを取得し、再生サブタスクを構築して、プロセスプールに割り当てます。
並列ワーカープロセスは再生サブタスクを実行し、データブロックで単一の WAL レコードを再生します。
バックエンドプロセスは、データブロックを読み取りながら、ページタグを使用して LogIndex データを取得し、LogIndex データに従ってこのデータブロックにマップされたすべての WAL レコードを再生します。次の図は、並列再生のワークフローを示しています。

ディスパッチャプロセス: LSN を使用して LogIndex データを取得し、ページタグとそれぞれの LSN を順番にリストし、
{LSN -> ページタグ}マッピングをタスクノードとして構築します。ページタグは、同じタスクタグを共有するタスクが割り当てられているタスクノードを識別します。
各タスクノードは、再生のためにプロセスプール内の並列ワーカープロセスに配信されます。

構成
読み取り専用ノードの postgresql.conf ファイルで次のパラメータを構成して、WAL レコードの並列再生を有効にします。
polar_enable_parallel_replay_standby_mode = ON