WAL parallel replay

更新时间:
复制 MD 格式

This topic describes the WAL parallel replay feature of PolarDB for PostgreSQL and .

Applicability

This feature is available for the following versions of PolarDB for PostgreSQL:

  • PostgreSQL 18 with revision version 2.0.18.0.1.0 or later

  • PostgreSQL 17 with revision version 2.0.17.2.1.0 or later

  • PostgreSQL 16 with revision version 2.0.16.3.1.1 or later

  • PostgreSQL 15 with revision version 2.0.15.7.1.1 or later

  • PostgreSQL 14 with revision version 2.0.14.5.1.0 or later

  • PostgreSQL 11 with revision version 2.0.11.9.17.0 or later

Note

You can check your cluster's revision version in the console or by running the SHOW polardb_version; statement. If the revision version does not meet the requirements, you must upgrade the revision version.

Background

In the primary/read-only architecture of PolarDB for PostgreSQL and , read-only nodes achieve parallel WAL replay. During operations, the LogIndex background replay process (LogIndex Background Worker) and backend session processes both use LogIndex data to replay WAL records on different buffers, creating a parallel replay mechanism.

Because WAL replay is critical for the high availability of a PolarDB cluster, applying this parallel replay method to the standard log replay path provides a significant optimization.

WAL parallel replay is advantageous in the following three scenarios:

  • Crash recovery on the primary, read-only, and secondary nodes.

  • Continuous WAL replay by the LogIndex background worker on a read-only node.

  • Continuous WAL replay by the Startup process on a secondary node.

Terms

  • data block: A unit of data storage.

  • WAL: An abbreviation for write-ahead logging.

  • task node: A node in the parallel execution framework that receives and executes a single subtask.

  • task tag: An identifier that categorizes subtasks. Subtasks with the same tag have execution order dependencies.

  • hold list: A linked list that each child process in the parallel execution framework uses to schedule and execute replay subtasks.

How it works

  • Overview

    A single WAL record can modify multiple data blocks.

    1. Assume that the i-th WAL log has an LSN of LSNi and modifies m data blocks. Then, the list of data blocks modified by the i-th WAL log is defined as Blocki​=[Blocki,0​,Blocki,1​,...,Blocki,m​].

    2. The minimum replay subtask is defined as Taski,j​=LSNi​−>Blocki,j, which represents the replay of the i-th WAL log on the data block Blocki,j.

    3. Therefore, a WAL log that modifies m blocks can be represented as a set of m replay sub-tasks: TASKi,∗​=[Taski,0​,Taski,1​,...,Taski,m​].

    4. Therefore, multiple WAL logs can be represented as a series of replay subtasks: TASK∗,∗​=[Task0,∗​,Task1,∗​,...,TaskN,∗​].

    In the log replay subtask set Task∗,∗, the execution of each subtask is not always dependent on the execution result of a preceding subtask.

    Assume the set of replay subtasks is as follows: TASK∗,∗​=[Task0,∗​,Task1,∗​,Task2,∗​], where:

    • Task0,∗​=[Task0,0​,Task0,1​,Task0,2​]

    • Task1,∗​=[Task1,0​,Task1,1​]

    • Task2,∗​=[Task2,0​]

    And, Block0,0=Block1,0, Block0,1=Block1,1, and Block0,2=Block2,0.

    In this case, three sets of subtasks can be replayed in parallel: [Task0,0,Task1,0], [Task0,1,Task1,1], and [Task0,2,Task2,0].

    In summary, many subtask sequences within the complete set of WAL replay tasks can run in parallel without affecting the consistency of the final result. Based on this principle, PolarDB introduces a parallel task execution framework and applies it to the WAL replay process.

  • Parallel task execution framework

    The framework divides a segment of shared memory equally among concurrent processes. Each resulting segment, allocated to one process, acts as a circular queue. You can configure the depth of each circular queue with parameters.共享内存分配

    • Dispatcher process

      • Controls concurrent scheduling by dispatching tasks to specific processes.

      • Removes completed tasks from the queue.

    • process pool

      Each process in the pool retrieves tasks from its corresponding circular queue and decides whether to execute them based on their state.进程组

    • Task

      The circular queue contains task nodes. Each task node can be in one of five states: Idle, Running, Hold, Finished, or Removed.

      • Idle: The task node has no assigned task.

      • Running: The task node is assigned a task that is waiting for execution or is currently being executed.

      • Hold: The task depends on a preceding task and must wait for that task to finish.

      • Finished: The task has been completed by a process in the process pool.

      • Removed: When the Dispatcher process finds a task in the Finished state, it implies all its prerequisite tasks are also finished. The Dispatcher process then changes the state to Removed, indicating it has cleared the task and its prerequisites from the management structure. This process ensures that the Dispatcher handles dependent tasks in the correct order.

      The Dispatcher process performs transitions marked by black lines, while the parallel replay process pool performs those marked by orange lines.任务

    • Dispatcher process

      The Dispatcher process uses three key data structures: a Task HashMap, a Task Running Queue, and Task Idle Nodes.

      • The Task HashMap stores the hash mappings between task tags and their corresponding task execution lists.

        • Each task is assigned a specific task tag. If two tasks have a dependency, they share the same task tag.

        • When dispatching tasks, if a task node has a prerequisite, the Dispatcher process marks its state as Hold, causing it to wait until the prerequisite is executed.

      • The Task Running Queue tracks all tasks that are currently being executed.

      • Task Idle Nodes records the task nodes from different processes in the process pool that are currently in the Idle state.

      The Dispatcher process uses the following scheduling strategy:

      • If a task to be executed has the same task tag as another task already in execution, the new task is preferentially assigned to the process running the last task in that task tag's linked list. This strategy aims to keep dependent tasks on the same process to reduce inter-process synchronization overhead.

      • If the preferred process queue is full or no task with the same Task Tag is running, a process is selected sequentially from the process pool, and a task node in the Idle state is retrieved from that process to run the task. The purpose is to distribute tasks as evenly as possible among different processes.

      调度策略

    • process pool

      This parallel execution targets tasks of the same type that have the same task node data structure. When the process pool is initialized, configure SchedContext to specify the function pointer that is responsible for executing specific tasks:

      • TaskStartup: The initialization action required before a process can execute a task.

      • TaskHandler: The function responsible for executing a specific task based on the provided task node.

      • TaskCleanup: The cleanup action required before an execution process exits.

      进程组1

      A process in the process pool retrieves a task node from a circular queue. If the current status of the task node is Hold, the process inserts the task node at the tail of the hold list. If the status of the task node is Running, the process calls the TaskHandler to execute it. If the TaskHandler fails to execute, the process sets a default retry count of 3 for the task node and inserts it at the head of the hold list.Process pool 2

      The process first searches the hold list from the head to retrieve an executable Task. If the Task's status is Running and its waiting call count is 0, the process executes the Task. If the Task's status is Running but its waiting call count is greater than 0, the process decrements the waiting call count by 1.Process pool 3

  • WAL parallel replay

    LogIndex data records the mapping between WAL records and the data blocks they modify, and it supports LSN-based lookups. During continuous WAL replay on a standby node, PolarDB introduces the parallel task execution framework and uses LogIndex data to parallelize WAL replay tasks, which speeds up data synchronization on the standby node.

    Workflow

    • The Startup process parses WAL records and builds LogIndex data but does not replay the WAL records themselves.

    • The LogIndex BGW background replay process acts as the Dispatcher process for the parallel task execution framework. It uses LSNs to retrieve LogIndex data, creates replay subtasks, and assigns them to the parallel replay process pool.

    • Processes within the parallel replay process pool execute replay subtasks, applying a single log record to a data block.

    • When a backend process actively reads a data block, it uses the page tag to look up the LogIndex data. It retrieves the linked list of LSNs that modified the data block and replays the full chain of log records on that block.工作流程

    • The Dispatcher process uses the LSN to retrieve LogIndex data, enumerates the PageTag and the corresponding LSN in the LogIndex insertion order, and constructs a {LSN -> PageTag} mapping to form the corresponding task node.

    • The page tag is used as the task tag for the task node.

    • The enumerated task nodes are then dispatched to the child processes in the parallel execution framework's process pool for replay.工作流程

Enable WAL parallel replay

To enable WAL parallel replay, add the following parameter to the postgresql.conf file on the standby node.

polar_enable_parallel_replay_standby_mode = ON