Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
邏輯複寫的行為與正常的 DML 操作類似,因為即使在訂閱節點上變更了資料,資料也會更新。 如果傳入的資料違反任何限制條件,複寫將會停止。這被稱為衝突。當複寫 UPDATE 或 DELETE 操作時,失去的資料不會產生衝突,而這些操作將會簡單地跳過。
衝突會產生錯誤並停止複寫;它必須由使用者手動解決。有關衝突的詳細訊息可以在使用者的伺服器日誌中找到。
解決方案可以透過變更訂閱戶上的資料來完成,以避免與傳入變更衝突或跳過與現有資料衝突的交易事務。透過呼叫 pg_replication_origin_advance() 函數以及與訂閱名稱和位置相對應的 node_name,可以跳過該交易事務。可以在 pg_replication_origin_status 系統檢視表中看到開始的目前位置。
邏輯複寫透過複寫發佈者資料庫上的資料快照開始。一旦完成,發佈者的變化就會即時發送給訂閱者。訂閱者按照對發佈者進行提交的順序套用資料,以確保任何單個訂閱中的發佈的交易事務一致性。
邏輯複寫採用類似於實體的串流複寫的體系結構構建立(請參閱第 26.2.5 節)。 它由「walsender」和「apply」過程實施。walsender 程序啟動 WAL 的邏輯解碼(在第 48 章中介紹)並載入標準的邏輯解碼套件(pgoutput)。該套件將從 WAL 讀取的變更轉換為邏輯複寫協定(請參閱第 52.5 節),並根據發佈規範過濾資料。然後使用串流複寫協定將資料連續傳輸到 apply 程序,後者將資料映射到本地資料表並按照正確的事務順序套用收到的各個變更。
使用者資料庫上的應用程序始終在將 session_replication_role 設定為 replica 的情況下運行,這會對事件觸發器和限制條件會產生影響。
邏輯複寫 apply 程序當下只觸發資料列觸發器,而不觸發查詢語句觸發器。但是,初始資料表同步會像 COPY 指令一樣執行,因此會觸發 INSERT 的資料列和查詢語句觸發器。
現有訂閱資料表中的初始資料被快照並複寫到特殊型別的 apply 程序的平行程序中。此過程將建立自己的臨時複寫插槽並複寫現有資料。一旦複寫了現有資料,程該序便進入同步模式,透過使用標準邏輯複寫對初始資料複寫過程中發生的任何變更進行串流傳輸,確保該資料表與主應用程序處於同步狀態。同步完成後,資料表的複寫控制將回到正常複寫繼續進行的主應用程序。
用於複寫連線的角色必須具有 REPLICATION 屬性(或者是超級使用者)。該角色的存取必須在 pg_hba.conf 中設定,並且必須具有 LOGIN 屬性。
為了能夠複製初始資料表資料,用於複寫連線的角色必須在發佈的資料表上具有 SELECT 權限(或者是超級使用者)。
要建立發佈,使用者必須在資料庫中具有 CREATE 權限。
要將資料表加到發佈中,使用者必須擁有該資料表的所有權。要建立自動發佈所有資料表的發佈,使用者必須是超級使用者。
要建立訂閱,使用者必須是超級使用者。
訂閱 apply 程序將以超級使用者的權限在本地資料庫中運行。
權限僅在複寫連線開始時檢查一次。由於每個變更記錄都是從發佈者處讀取的,因此不會重新檢查,也不會在套用每個變更時重新檢查。
首先在 postgresql.conf 中進行組態設定:
其他所需的設定的預設值已經足夠。
需要調整 pg_hba.conf 以允許複寫(這裡的內容取決於您想要用於連線的實際網路配置和使用者):
然後在發佈者的資料庫上:
在訂閱者的資料庫上:
以上將啟動複寫程序,此程序同步資料表 users 和 departments 的初始資料表內容,然後開始以增量變更複寫到這些資料表。
邏輯複寫(Logical Replication)是一種依據複寫指標(通常是主鍵)複製資料物件及其更新的方法。我們使用術語邏輯與物理複寫相對比,物理複寫使用確切的區塊位址進行每一個字元組的複寫。PostgreSQL 同時支持這兩種機制,請參閱第 26 章。邏輯複寫允許對資料複寫和安全性進行更精細的控制。
邏輯複寫使用 publish(發佈)和 subscribe(訂閱)模式,其中一個或多個訂閱者 subscribe 發布者節點上的一個或多個 publish。 訂閱戶從他們訂閱的 publish 中提取資料,並可能隨後重新發布資料以允許串聯複寫或更複雜的複寫架構。
資料表的邏輯複寫通常始於對發佈者資料庫上的資料進行快照並將其複寫到訂閱伺服器。一旦完成,發佈者的變化就會即時發送給訂閱者。訂閱者按照與發佈者相同的順序變動資料,以確保單個訂閱內的發佈的交易事務一致性。這種資料複寫方法有時被稱為交易事務複寫。
典型的邏輯複寫情況有:
在訂閱者時常向單個資料庫或資料庫的子集發送增量變更時。
當訂閱者收到個別的變更時能觸發事件。
將多個資料庫合併成一個資料庫(例如為了分析的需求)。
在不同的 PostgreSQL 版本之間複寫。
將複寫的資料給予不同的用戶群組存取權限。
在多個資料庫之間共享資料庫的一部份。
訂閱戶資料庫的行為與任何其他 PostgreSQL 的行為相同,並且可以透過定義其自己的發佈來用作其他資料庫的發佈者。當訂閱者被應用程序視為唯讀時,單個訂閱就不會發生衝突。另一方面,如果應用程序或其他使用者對同一組資料表執行了其他的寫入操作,則可能會出現衝突。
邏輯複寫目前有以下限制或功能不足的地方。這些可能會在將來的版本中解決。
資料庫模式和 DDL 指令不會被複寫。初始模式可以使用 pg_dump --schema-only 手動複寫。後續的結構變更需要手動保持同步。(但是,請注意,兩側的結構沒有必要完全相同。)當主要資料庫中的結構定義變更時,邏輯複寫是沒問題的:當發佈者上的結構産生變更並且複寫的資料開始到達訂閱戶但不符合資料表結構,複寫將産生錯誤,直到結構更新。在許多情況下,可以透過先將預定的架構變更套用於訂閱戶來避免間歇性的錯誤。
序列資料不會被複寫。序列支援的序列或識別欄位中的資料當然會作為資料表的一部分進行複寫,但序列本身仍然會顯示訂閱戶的初始值。如果使用者用作唯讀資料庫,那麼這通常不成問題。但是,如果打算對訂閱戶資料庫進行某種切換或故障轉移,則需要將序列更新為最新值,方法是複寫發佈者的目前資料(可能使用 pg_dump)或設定對該資料表而言足夠高的值。
TRUNCATE 指令不會被複寫。當然,這可以透過使用 DELETE 來解決。為了避免意外的 TRUNCATE 呼叫,您可以從資料表中撤銷 TRUNCATE 權限。
Large objects(請參閱第 34 章)不會被複寫。除了將資料儲存在普通資料表中之外,沒有其他解決方法。
只能從基本資料表到基本資料表複寫。也就是說,發佈和訂閱端的資料表必須是普通資料表,而不是檢視表、具體化檢視表、分割資料表或外部資料表。對於分割資料表,您可以一對一複寫分割區的層次結構,但目前不能複寫到不同的分割區設定。嘗試複寫基本資料表以外的資料表將産生錯誤。
可以在任何物理複寫主機上定義發佈。 定義發佈的節點稱為發佈者。發佈是從一個資料表或一組資料表中産生的一組變更,也可能被描述為變更集合或複寫集合。每個發佈僅能存在於一個資料庫中。
發佈與綱要不同,不會影響資料表的存取方式。如果需要,每個資料表可以加到多個發佈之中。 發佈目前可能只包含資料表。物件必須明確加入,除非為 ALL TABLES 建立發佈。
發佈可以選擇將其產生的變更限制為 INSERT,UPDATE 和 DELETE 的任意組合,類似於特定事件類型觸發器的方式。預設情況下,所有操作類型都被複寫。
發佈的資料表必須配置「副本識別」,以便能夠複寫 UPDATE 和 DELETE 操作,使在訂閱端可以識別更新或刪除適當的資料列。預設情況下,這是主鍵,如果有的話。另一個是唯一索引(具有某些附加要求)也可以設定為副本識別。如果該資料表沒有任何合適的方式,則可以將其設定為副本識別「full」,這意味著整個資料列都作為識別。但是,這效能是非常低的,只有在沒有其他解決方案可行的情況下才可以這樣使用。如果在發佈方設定了除「full」之外的副本識別,則還必須在訂閱戶設定包含相同或更少欄位的副本標別。有關如何設定副本識別的詳細訊息,請參閱 REPLICA IDENTITY。如果沒有副本識別的資料表被加到複寫 UPDATE 或 DELETE 操作的發佈中,則隨後的 UPDATE 或 DELETE 操作將導致發佈者出錯。不管任何副本識別,INSERT 操作都可以繼續進行。
每個發佈可以有多個訂閱者。
使用 CREATE PUBLICATION 指令建立發佈,稍後可以使用相應的命令變更或移除發佈。
可以使用 ALTER PUBLICATION 動態加入和移除單個資料表。ADD TABLE 和 DROP TABLE 操作都是交易安全的;所以一旦交易事務提交後,資料表就會在正確的快照上,並且啟動或停止複寫。
訂閱是邏輯複寫的下游。訂閱的節點被稱為訂閱者。訂閱定義了與另一個資料庫以及它想要訂閱的一組或多組發佈(一個或多個)的連線。
訂閱資料庫的行為與任何其他 PostgreSQL 服務的行為相同,也可以透過定義自己的發佈來成為其他資料庫的發佈者。
如果需要,用戶節點可能有多個訂閱。在單個(發佈者 - 訂閱者)配對之間定義多個訂閱允許的,在這種情況下必須小心以確保訂閱的發佈對象不重疊。
每個訂閱都將透過一個複寫插槽(replication slot)接收變更(請參閱第 26.2.6 節)。額外的臨時複寫插槽可能需要用於預先存在的資料表資料才能開始初始化資料同步。
邏輯複寫訂閱可以是同步複寫的備用資料庫(請參閱第 26.2.8 節)。備用名稱預設為訂閱名稱。可以在訂閱的連線訊息中將另一個名稱以 application_name 指定。
如果目前使用者是超級使用者,則 pg_dump 會匯出訂閱的內容。否則會提示警告訊息並跳過訂閱內容,因為非超級使用者無法讀取 pg_subscription 目錄中的訂閱訊息。
訂閱是使用 CREATE SUBSCRIPTION 加入的,可以隨時使用 ALTER SUBSCRIPTION 指令停止或恢復,並使用 DROP SUBSCRIPTION 移除訂閱。
當訂閱被移除並重新建立時,將會失去同步訊息。這意味著資料必須在事後重新同步。
資料庫結構的定義不會被複寫,並且已發佈的資料表必須存在於訂閱的伺服器上。只有一般的資料表可以是複寫的標的。例如,您不能複寫到檢視表(view)。
這些資料表使用完全限定的資料表名稱,在發佈者和訂閱者之間進行匹配。不支援複寫到訂閱戶上不同名稱的資料表。
資料表的欄位也按照名稱匹配。目標資料表中不同的欄位順序是允許的,但欄位型別必須匹配。目標資料表可以具有未由發佈資料表所提供的附加欄位。那些欄位將以它們的預設值填入。
如前所述,每個(活動)訂閱都會從遠端(發佈)端的複寫插槽接收變更。通常,使用 CREATE SUBSCRIPTION 建立訂閱時會自動建立遠端的複寫插槽,使用 DROP SUBSCRIPTION 移除訂閱時會自動移除該插槽。但是,在某些情況下,分別管理訂閱和底層複寫插槽可能很有用甚至是必要的。 以下是一些情況:
建立訂閱時,複寫插槽已經存在。在這種情況下,可以使用 create_slot = false 選項來與現有插槽關連以建立訂閱。
建立訂閱時,遠端主機無法存取或處於不明狀態。在這種情況下,可以使用 connect = false 選項建立訂閱。遠端主機將不會被聯繫。這是 pg_dump 所使用的。然後必須在訂閱啓動之前手動建立遠端的複寫插槽。
在移除訂閱時,應該保留複寫插槽。當使用者資料庫被移動到不同的主機並且從那裡被啓動時,這可能會有用。在這種情況下,在嘗試移除訂閱之前,請使用 ALTER SUBSCRIPTION 從插入位置解除關連。
在移除訂閱時,遠端主機無法存取。在這種情況下,在嘗試移除訂閱之前,請使用 ALTER SUBSCRIPTION 從插入位置解除關連。如果遠端資料庫服務不再存在,則不需要進一步的操作。但是,如果遠端資料庫服務不可存取,則應手動移除複寫插槽;否則它會繼續保留 WAL,最終可能會導致磁碟空間不足。應該仔細檢查這種情況。
邏輯複寫需要設定幾個系統組態選項。
在發佈端,必須將 wal_level 設定為 logical,並且必須將 max_replication_slots 設定為至少預計要連線的訂閱數量,並為資料表同步保留一些預留數量。然後 max_wal_senders 應至少設定為與 max_replication_slots 相同的數量再加上同時連線的實體副本數量。
用戶還需要設定 max_replication_slots。在這種情況下,它應至少設定為將加到訂閱伺服器的訂閱數。max_logical_replication_workers 必須至少設定為訂閱數量,再加上資料表同步的一些保留數。此外,可能需要調整 max_worker_processes 以滿足複寫程序,至少為(max_logical_replication_workers + 1)。請注意,某些延伸功能和平行查詢也需要 max_worker_processes 中的程序插槽。
由於邏輯複寫基於與物理性的串流複寫相似的體系結構,因此發佈節點上的監控與監控物理式串流複寫主節點類似(請參閱第 26.2.5.2 節)。
有關訂閱的監控訊息可以在 pg_stat_subscription 中找到。該檢視表對每個訂閱程序都有一個資料列。根據訂閱的狀態,訂閱可以有零個或多個活動訂閱程序。
一般而言,每一個啟用的訂閱會有單個 apply 程序運行。此檢視表中禁用的訂閱或當掉的訂閱將不會看到資料。如果任何資料表的初始資料同步正在進行,則會有額外的程序表示正在同步資料表。