RDS PostgreSQL支援在唯讀執行個體上建立本地邏輯複製槽,下遊訂閱者可以直接連接唯讀執行個體消費變更,從而將邏輯複製的消費流量從主執行個體轉移到唯讀執行個體,減輕主執行個體的負載。
前提條件
PostgreSQL 16或以上版本,且核心小版本不低於20260530。如提示不支援,請升級核心小版本,具體操作,請參見升級核心小版本。
背景資訊
PostgreSQL 原生邏輯複製槽(Logical Replication Slot)在主執行個體上建立,下遊訂閱者必須串連主執行個體消費變更。RDS PostgreSQL 支援在唯讀執行個體上建立本地邏輯複製槽,使下遊訂閱者可以直接連接唯讀執行個體消費變更,以減輕主執行個體負載。邏輯複製槽的更多資訊,請參見PostgreSQL官方文檔。
注意事項
在唯讀執行個體上建立的邏輯複製槽為本地 slot,不參與主備容錯移轉。唯讀執行個體重搭(重建)後,這些 slot 將丟失,需要在重搭後重新建立。
建議僅在非高可用的唯讀執行個體上使用此方式。如果唯讀執行個體承擔高可用讀流量,slot 丟失可能導致下遊訂閱中斷,需評估業務影響。
使用樣本
以下樣本假設已有主執行個體(RW)和唯讀執行個體(RO),且唯讀執行個體通過流複製與主執行個體保持資料同步。本文介紹以下三種典型使用方式:
基本用法:在唯讀執行個體上手動建立並消費slot(使用
test_decoding外掛程式),適用於自訂解碼邏輯情境。通過Subscription訂閱唯讀執行個體(自動建立slot):最典型的使用情境,由
CREATE SUBSCRIPTION自動在唯讀執行個體上建立slot。通過Subscription訂閱唯讀執行個體(手動預建立slot):進階用法,先手動建立slot再建立訂閱,確保不丟失建立期間的變更。
基本用法:手動建立並消費slot
本樣本示範如何在唯讀執行個體上手動建立邏輯複製槽,並通過test_decoding外掛程式消費主執行個體的資料變更。
在唯讀執行個體上建立本地邏輯複製槽。
-- [RO] 建立本地logical slot SELECT pg_create_logical_replication_slot('my_slot', 'test_decoding');確認slot建立成功。
-- [RO] 確認slot建立成功 SELECT slot_name, plugin FROM pg_replication_slots WHERE slot_name = 'my_slot';查詢結果:
slot_name | plugin -----------+--------------- my_slot | test_decoding (1 row)在主執行個體上寫入資料。
-- [RW] 主庫寫入資料 INSERT INTO my_table VALUES (1), (2), (3);等待WAL回放到唯讀執行個體。
在主執行個體上查詢當前WAL位置:
-- [RW] 擷取主庫當前WAL位置 SELECT pg_current_wal_lsn();在唯讀執行個體上查詢回放進度,直到回放位置不小於主執行個體的WAL位置:
-- [RO] 查看唯讀執行個體回放進度 SELECT pg_last_wal_replay_lsn();說明PostgreSQL 15及以上版本,也可以使用
pg_wal_replay_wait(target_lsn)函數主動等待回放至指定LSN,無需輪詢。在唯讀執行個體上通過slot消費變更。
-- [RO] 通過slot消費變更 SELECT * FROM pg_logical_slot_get_changes('my_slot', NULL, NULL);查詢結果:
lsn | xid | data -----------+-----+---------------------------------------- 0/XXXXXXX | 123 | table public.my_table: INSERT: ... (3 rows)不再需要時,刪除slot。
-- [RO] 刪除slot SELECT pg_drop_replication_slot('my_slot');
通過Subscription訂閱唯讀執行個體(自動建立slot)
這是最典型的使用情境:下遊訂閱執行個體(Subscriber)直接連接唯讀執行個體,由CREATE SUBSCRIPTION自動在唯讀執行個體上建立slot。
在主執行個體上建立表和發布。
-- [RW] 主庫上建立表和publication CREATE TABLE tab_rep (id int PRIMARY KEY, data text); CREATE PUBLICATION my_pub FOR TABLE tab_rep;等待WAL回放到唯讀執行個體,確保publication在唯讀執行個體上可見。等待方法請參見"基本用法"中的步驟4。
在下遊訂閱執行個體上建立相同的表結構。
-- [Subscriber] 下遊執行個體建立表結構 CREATE TABLE tab_rep (id int PRIMARY KEY, data text);在下遊訂閱執行個體上建立訂閱,串連唯讀執行個體。
-- [Subscriber] 建立subscription,串連唯讀執行個體 -- subscription會自動在唯讀執行個體上建立名為'my_sub'的slot CREATE SUBSCRIPTION my_sub CONNECTION 'host=<RO_HOST> port=<RO_PORT> dbname=postgres' PUBLICATION my_pub WITH (copy_data = off);說明此操作會在唯讀執行個體上自動建立一個邏輯複製槽。該slot為唯讀執行個體本地slot,不參與容錯移轉,唯讀執行個體重搭後會丟失。
在主執行個體上寫入資料並驗證同步。
-- [RW] 主庫寫入資料 INSERT INTO tab_rep VALUES (1, 'hello'), (2, 'world');資料流向:RW →(流複製/WAL)→ RO →(邏輯複製)→ Subscriber。
-- [Subscriber] 驗證資料已同步 SELECT * FROM tab_rep;查詢結果:
id | data ----+------- 1 | hello 2 | world (2 rows)不再需要時,在下遊執行個體上刪除訂閱(會自動刪除唯讀執行個體上的slot)。
-- [Subscriber] 刪除subscription,自動清理唯讀執行個體上的slot DROP SUBSCRIPTION my_sub;
通過Subscription訂閱唯讀執行個體(手動預建立slot)
如果需要先建立slot再建立訂閱(例如確保不丟失建立期間的變更),可以手動預建立slot。
在唯讀執行個體上手動建立slot。
-- [RO] 先在唯讀執行個體上手動建立slot SELECT pg_create_logical_replication_slot('my_sub', 'pgoutput');在下遊訂閱執行個體上建立訂閱,使用已有的slot。
-- [Subscriber] 建立subscription,使用已有的slot,不再自動建立 CREATE SUBSCRIPTION my_sub CONNECTION 'host=<RO_HOST> port=<RO_PORT> dbname=postgres' PUBLICATION my_pub WITH (copy_data = off, create_slot = false);說明通過指定
create_slot = false,CREATE SUBSCRIPTION將直接使用唯讀執行個體上已有的slot,不會重複建立。後續使用方式與"通過Subscription訂閱唯讀執行個體(自動建立slot)"相同。