Topik ini menjelaskan fitur WAL parallel replay dari PolarDB for PostgreSQL dan .
Keberlakuan
Fitur ini tersedia untuk versi berikut dari PolarDB for PostgreSQL:
-
PostgreSQL 18 dengan versi revisi 2.0.18.0.1.0 atau lebih baru
-
PostgreSQL 17 dengan versi revisi 2.0.17.2.1.0 atau lebih baru
-
PostgreSQL 16 dengan versi revisi 2.0.16.3.1.1 atau lebih baru
-
PostgreSQL 15 dengan versi revisi 2.0.15.7.1.1 atau lebih baru
-
PostgreSQL 14 dengan versi revisi 2.0.14.5.1.0 atau lebih baru
-
PostgreSQL 11 dengan versi revisi 2.0.11.9.17.0 atau lebih baru
Anda dapat melihat versi mesin minor di Konsol atau dengan menjalankan pernyataan SHOW polardb_version;. Jika versi mesin minor tidak memenuhi persyaratan, upgrade versi mesin minor.
Latar Belakang
Pada arsitektur primary/read-only dari PolarDB for PostgreSQL dan , node read-only menerapkan WAL replay paralel. Selama operasi, proses replay latar belakang LogIndex (LogIndex Background Worker) dan proses session backend sama-sama menggunakan data LogIndex untuk mereplay catatan WAL pada buffer yang berbeda, sehingga membentuk mekanisme replay paralel.
Karena replay WAL sangat penting bagi ketersediaan tinggi kluster PolarDB, penerapan metode replay paralel ini pada jalur replay log standar memberikan optimisasi signifikan.
WAL parallel replay memberikan keuntungan dalam tiga skenario berikut:
-
Crash recovery pada node primary, read-only, dan secondary.
-
Replay WAL berkelanjutan oleh worker latar belakang LogIndex pada node read-only.
-
Replay WAL berkelanjutan oleh proses Startup pada node secondary.
Istilah
-
data block: Satuan penyimpanan data.
-
WAL: Singkatan dari write-ahead logging.
-
task node: Node dalam kerangka eksekusi paralel yang menerima dan mengeksekusi satu subtask.
-
task tag: Pengenal yang mengkategorikan subtask. Subtask dengan tag yang sama memiliki ketergantungan urutan eksekusi.
-
hold list: Daftar berantai yang digunakan setiap proses anak dalam kerangka eksekusi paralel untuk menjadwalkan dan mengeksekusi subtask replay.
Cara Kerja
-
Ikhtisar
Satu catatan WAL dapat memodifikasi beberapa data block.
-
Misalkan log WAL ke-
imemiliki LSN sebesarLSN<sub>i</sub>dan memodifikasimblok data. Daftar blok data yang dimodifikasi oleh log WAL ke-ididefinisikan sebagaiBlock<sub>i</sub>=[Block<sub>i,0</sub>,Block<sub>i,1</sub>,...,Block<sub>i,m</sub>]. -
Subtask replay minimum didefinisikan sebagai
Task<sub>i,j</sub>=LSN<sub>i</sub>−>Block<sub>i,j</sub>, yang merepresentasikan replay log WAL pada blok dataBlock<sub>i,j</sub>nomori. -
Dengan demikian, satu log WAL yang memodifikasi
mblok dapat direpresentasikan sebagai himpunanmsubtask replay:TASK<sub>i,∗</sub>=[Task<sub>i,0</sub>,Task<sub>i,1</sub>,...,Task<sub>i,m</sub>]. Oleh karena itu, beberapa log WAL dapat direpresentasikan sebagai rangkaian subtask replay:
TASK<sub>∗,∗</sub>=[Task<sub>0,∗</sub>,Task<sub>1,∗</sub>,...,Task<sub>N,∗</sub>].
Dalam himpunan subtask replay log
Task<sub>∗,∗</sub>, eksekusi setiap subtask tidak selalu bergantung pada hasil eksekusi subtask sebelumnya.Misalkan himpunan subtask replay adalah sebagai berikut:
TASK<sub>∗,∗</sub>=[Task<sub>0,∗</sub>,Task<sub>1,∗</sub>,Task<sub>2,∗</sub>], dengan:-
Task<sub>0,∗</sub>=[Task<sub>0,0</sub>,Task<sub>0,1</sub>,Task<sub>0,2</sub>] -
Task<sub>1,∗</sub>=[Task<sub>1,0</sub>,Task<sub>1,1</sub>] -
Task<sub>2,∗</sub>=[Task<sub>2,0</sub>]
Selain itu, Block0,0 = Block1,0, Block0,1 = Block1,1, dan Block0,2 = Block2,0.
Dalam kasus ini, tiga set subtugas dapat dijalankan ulang secara paralel: [Tugas0,0, Tugas1,0], [Tugas0,1, Tugas1,1], dan [Tugas0,2, Tugas2,0].
Secara ringkas, banyak urutan subtask dalam keseluruhan himpunan tugas replay WAL dapat dijalankan secara paralel tanpa memengaruhi konsistensi hasil akhir. Berdasarkan prinsip ini, PolarDB memperkenalkan kerangka eksekusi tugas paralel dan menerapkannya pada proses replay WAL.
-
-
Kerangka eksekusi tugas paralel
Kerangka ini membagi segmen memori bersama secara merata di antara proses konkuren. Setiap segmen hasil pembagian, yang dialokasikan ke satu proses, berfungsi sebagai antrian melingkar (circular queue). Anda dapat mengonfigurasi kedalaman setiap antrian melingkar melalui parameter.

-
Proses Dispatcher
-
Mengontrol penjadwalan konkuren dengan mendistribusikan tugas ke proses tertentu.
-
Menghapus tugas yang telah selesai dari antrian.
-
-
process pool
Setiap proses dalam pool mengambil tugas dari antrian melingkar yang sesuai dan menentukan apakah akan mengeksekusinya berdasarkan status tugas tersebut.

-
Tugas
Antrian melingkar berisi node tugas. Setiap node tugas dapat berada dalam salah satu dari lima status: Idle, Running, Hold, Finished, atau Removed.
-
Idle: Node tugas tidak memiliki tugas yang ditetapkan.
-
Running: Node tugas telah diberi tugas yang sedang menunggu eksekusi atau sedang dieksekusi.
Hold: Tugas bergantung pada tugas sebelumnya dan harus menunggu hingga tugas tersebut selesai.
-
Finished: Tugas telah diselesaikan oleh proses dalam process pool.
-
Removed: Ketika proses Dispatcher menemukan tugas dalam status Finished, hal ini menyiratkan bahwa semua tugas prasyaratnya juga telah selesai. Proses Dispatcher kemudian mengubah statusnya menjadi Removed, yang menandakan bahwa tugas tersebut beserta prasyaratnya telah dihapus dari struktur manajemen. Proses ini memastikan bahwa Dispatcher menangani tugas yang saling bergantung dalam urutan yang benar.
Dalam proses transisi status pada mesin keadaan di atas, transisi yang ditandai garis hitam dilakukan oleh proses Dispatcher, sedangkan transisi yang ditandai garis oranye dilakukan oleh kelompok proses replay paralel. -
-
Dispatcher process
Proses Dispatcher menggunakan tiga struktur data utama: Task HashMap, Task Running Queue, dan Task Idle Nodes.
-
Task HashMap menyimpan pemetaan hash antara task tag dan daftar eksekusi tugas yang sesuai.
-
Setiap tugas diberi task tag tertentu. Jika dua tugas memiliki ketergantungan, keduanya berbagi task tag yang sama.
Saat mendistribusikan tugas, jika node tugas memiliki prasyarat, proses Dispatcher menandai statusnya sebagai Hold sehingga tugas tersebut menunggu hingga prasyaratnya dieksekusi.
-
-
Task Running Queue melacak semua tugas yang sedang dieksekusi.
-
Task Idle Nodes mencatat node tugas dari berbagai proses dalam process pool yang saat ini berada dalam status
Idle.
Proses Dispatcher menggunakan strategi penjadwalan berikut:
-
Jika tugas yang akan dieksekusi memiliki task tag yang sama dengan tugas lain yang sedang berjalan, tugas baru tersebut diprioritaskan untuk ditugaskan ke proses yang menjalankan tugas terakhir dalam daftar berantai task tag tersebut. Strategi ini bertujuan menjaga tugas yang saling bergantung tetap berada dalam proses yang sama guna mengurangi overhead sinkronisasi antar-proses.
-
Jika antrian proses yang diprioritaskan penuh atau tidak ada tugas dengan Task Tag yang sama sedang berjalan, proses dipilih secara berurutan dari process pool, dan node tugas dalam status
Idlediambil dari proses tersebut untuk menjalankan tugas. Tujuannya adalah mendistribusikan tugas secara merata di antara berbagai proses.

-
-
process pool
Eksekusi paralel ini menargetkan tugas dengan jenis yang sama yang memiliki struktur data node tugas yang identik. Saat process pool diinisialisasi, konfigurasikan
SchedContextuntuk menentukan pointer fungsi yang bertanggung jawab mengeksekusi tugas tertentu:-
TaskStartup: Aksi inisialisasi yang diperlukan sebelum proses dapat mengeksekusi tugas.
-
TaskHandler: Fungsi yang bertanggung jawab mengeksekusi tugas tertentu berdasarkan node tugas yang diberikan.
TaskCleanup: Tindakan pembersihan yang diperlukan sebelum proses eksekusi berakhir.

Proses dalam process pool mengambil node tugas dari antrian melingkar. Jika status saat ini dari node tugas adalah
Hold, proses tersebut memasukkan node tugas ke ujung ekorhold list. Jika status node tugas adalahRunning, proses tersebut memanggilTaskHandleruntuk mengeksekusinya. JikaTaskHandlergagal mengeksekusi, proses tersebut menetapkan jumlah percobaan ulang default sebanyak 3 kali untuk node tugas tersebut dan memasukkannya ke kepalahold list.
Proses tersebut pertama-tama mencari
hold listdari kepala untuk mengambil Tugas yang dapat dieksekusi. Jika status Tugas tersebut adalahRunningdan jumlah panggilan tunggunya adalah 0, proses tersebut mengeksekusi Tugas tersebut. Jika status Tugas tersebut adalahRunningtetapi jumlah panggilan tunggunya lebih besar dari 0, proses tersebut mengurangi jumlah panggilan tunggu sebanyak 1.
-
-
-
WAL parallel replay
Data LogIndex mencatat pemetaan antara catatan WAL dan data block yang dimodifikasinya, serta mendukung pencarian berbasis LSN. Selama replay WAL berkelanjutan pada node standby, PolarDB memperkenalkan kerangka eksekusi tugas paralel dan menggunakan data LogIndex untuk memparalelkan tugas replay WAL, sehingga mempercepat sinkronisasi data pada node standby.
Alur Kerja
-
Proses Startup mengurai catatan WAL dan membangun data LogIndex tetapi tidak mereplay catatan WAL tersebut.
Proses replay latar belakang LogIndex BGW berperan sebagai Dispatcher dalam kerangka eksekusi tugas paralel. Proses ini menggunakan LSN untuk mengambil data LogIndex, membuat subtask replay, lalu menugaskannya ke pool proses replay paralel.
-
Proses dalam process pool replay paralel mengeksekusi subtask replay, menerapkan satu catatan log ke satu data block.
-
Ketika proses backend secara aktif membaca data block, proses tersebut menggunakan page tag untuk mencari data LogIndex. Proses tersebut mengambil daftar berantai LSN yang memodifikasi data block tersebut dan mereplay seluruh rantai catatan log pada block tersebut.

-
Proses Dispatcher menggunakan LSN untuk mengambil data LogIndex, mengenumerasi PageTag dan LSN yang sesuai berdasarkan urutan penyisipan LogIndex, serta membangun pemetaan
{LSN -> PageTag}guna membentuk node tugas yang sesuai. -
Tag halaman digunakan sebagai task tag untuk node tugas tersebut.
-
Node tugas yang telah dienumerasi kemudian didistribusikan ke proses anak dalam process pool kerangka eksekusi paralel untuk direplay.

-
Aktifkan WAL parallel replay
Untuk mengaktifkan WAL parallel replay, tambahkan parameter berikut ke file postgresql.conf pada node siaga.
polar_enable_parallel_replay_standby_mode = ON