熱備援是用來描述當伺服器處於封存復原或備用模式時,連接到伺服器並執行唯讀查詢的能力的術語。 這對於複製目的以及以極高的精確度將備份還原到所需狀態都很有用。 熱備援一詞也指伺服器在使用者繼續執行查詢和/或保持其連線開啟的情況下,從復原到正常運作的能力。
在熱備援模式下執行查詢與正常的查詢操作類似,但存在一些使用和管理上的差異,如下所述。
當備用伺服器上的 hot_standby 參數設定為 true 時,一旦復原將系統帶到一致的狀態,它就會開始接受連線。所有這些連線都是嚴格的唯讀;即使是暫存資料表也無法寫入。
備用伺服器上的資料需要一些時間才能從主要伺服器到達,因此主要伺服器和備用伺服器之間會存在可測量的延遲。 因此,幾乎同時在主要伺服器和備用伺服器上執行相同的查詢可能會傳回不同的結果。 我們說備用伺服器上的資料與主要伺服器最終一致。 一旦在備用伺服器上重播了交易的提交記錄,該交易進行的變更將對備用伺服器上取得的任何新快照可見。 快照可以在每個查詢的開始時或在每個交易的開始時取得,具體取決於當前的交易隔離等級。 有關更多詳細資訊,請參閱第 13.2 節。
在熱備援期間啟動的交易可以發出以下命令
查詢存取:SELECT
、COPY TO
游標命令:DECLARE
、FETCH
、CLOSE
設定:SHOW
、SET
、RESET
交易管理命令
BEGIN
、END
、ABORT
、START TRANSACTION
SAVEPOINT
、RELEASE
、ROLLBACK TO SAVEPOINT
EXCEPTION
區塊和其他內部子交易
LOCK TABLE
,但僅當明確處於以下模式之一時:ACCESS SHARE
、ROW SHARE
或 ROW EXCLUSIVE
。
計畫和資源:PREPARE
、EXECUTE
、DEALLOCATE
、DISCARD
外掛程式和擴充功能:LOAD
UNLISTEN
在熱備援期間啟動的交易永遠不會被指派交易 ID,並且無法寫入系統預寫式日誌。 因此,以下操作會產生錯誤訊息
資料操作語言 (DML):INSERT
、UPDATE
、DELETE
、MERGE
、COPY FROM
、TRUNCATE
。 請注意,沒有允許的操作會在復原期間執行觸發程序。 此限制甚至適用於暫存資料表,因為不指派交易 ID 就無法讀取或寫入資料表列,而這在熱備援環境中目前是不可能的。
資料定義語言 (DDL):CREATE
、DROP
、ALTER
、COMMENT
。 此限制甚至適用於暫存資料表,因為執行這些操作需要更新系統目錄資料表。
SELECT ... FOR SHARE | UPDATE
,因為不更新基礎資料檔案就無法取得列鎖定。
關於產生 DML 命令的 SELECT
陳述式的規則。
LOCK
明確要求高於 ROW EXCLUSIVE MODE
的模式。
LOCK
以簡短的預設形式,因為它要求 ACCESS EXCLUSIVE MODE
。
明確設定非唯讀狀態的交易管理命令
BEGIN READ WRITE
、START TRANSACTION READ WRITE
SET TRANSACTION READ WRITE
、SET SESSION CHARACTERISTICS AS TRANSACTION READ WRITE
SET transaction_read_only = off
兩階段提交命令:PREPARE TRANSACTION
、COMMIT PREPARED
、ROLLBACK PREPARED
,因為即使是唯讀交易也需要在準備階段(兩階段提交的第一階段)中寫入 WAL。
序列更新:nextval()
、setval()
LISTEN
、NOTIFY
在正常運作中,「唯讀」交易允許使用 LISTEN
和 NOTIFY
,因此熱備援會話在比普通唯讀會話稍為嚴格的限制下運作。 未來的版本可能會放寬其中一些限制。
在熱備援期間,參數 transaction_read_only
永遠為 true 且無法變更。但只要沒有嘗試修改資料庫,熱備援期間的連線行為會非常像其他資料庫連線。如果發生故障轉移或切換,資料庫會切換到正常的處理模式。在伺服器變更模式時,工作階段會保持連線。熱備援完成後,就可以啟動讀寫交易(即使是從熱備援期間開始的工作階段)。
使用者可以透過執行 SHOW in_hot_standby
來判斷目前的工作階段是否為作用中的熱備援。(在 14 之前的伺服器版本中,不存在 in_hot_standby
參數;對於較舊的伺服器,一個可行的替代方法是 SHOW transaction_read_only
。)此外,一組函數(表 9.96 恢復資訊函數)允許使用者存取關於備援伺服器的資訊。這些函數允許您編寫可以感知資料庫目前狀態的程式。這些函數可用於監控恢復的進度,或允許您編寫複雜的程式將資料庫恢復到特定狀態。
主伺服器和備援伺服器在很多方面是鬆散連接的。在主伺服器上的操作會對備援伺服器產生影響。因此,它們之間存在負面互動或衝突的可能性。最容易理解的衝突是效能:如果在主伺服器上發生大量資料載入,那麼這將在備援伺服器上產生類似的 WAL 紀錄流,因此備援查詢可能會爭奪系統資源,例如 I/O。
還有其他類型的衝突可能發生在熱備援中。這些衝突是硬衝突,因為可能需要取消查詢,在某些情況下甚至需要斷開工作階段才能解決它們。使用者可以透過幾種方式來處理這些衝突。衝突情況包括:
在主伺服器上取得的 Access Exclusive 鎖定,包括明確的 LOCK
指令和各種DDL動作,與備援查詢中對資料表的存取產生衝突。
在主伺服器上刪除資料表空間,與備援查詢使用該資料表空間作為暫存工作檔案產生衝突。
在主伺服器上刪除資料庫,與備援伺服器上連接到該資料庫的工作階段產生衝突。
從 WAL 應用 vacuum 清理記錄,與其快照仍然可以“看到”任何要移除的列的備援交易產生衝突。
從 WAL 應用 vacuum 清理記錄,與在備援伺服器上存取目標頁面的查詢產生衝突,無論要移除的資料是否可見。
在主伺服器上,這些情況只會導致等待;使用者可以選擇取消任何一個衝突的動作。然而,在備援伺服器上沒有選擇:WAL 記錄的動作已經在主伺服器上發生,因此備援伺服器不能拒絕應用它。此外,允許 WAL 應用無限期地等待可能非常不理想,因為備援伺服器的狀態將會越來越落後於主伺服器。因此,提供了一種機制來強制取消與要應用的 WAL 紀錄衝突的備援查詢。
問題情況的一個例子是主伺服器上的管理員執行 DROP TABLE
,而備援伺服器上目前正在查詢該資料表。顯然,如果在備援伺服器上應用 DROP TABLE
,備援查詢就無法繼續。如果這種情況發生在主伺服器上,DROP TABLE
將會等待直到另一個查詢完成。但是當在主伺服器上執行 DROP TABLE
時,主伺服器沒有關於備援伺服器上正在執行哪些查詢的資訊,因此它不會等待任何此類備援查詢。WAL 變更紀錄傳送到備援伺服器,而備援查詢仍在執行,從而導致衝突。備援伺服器必須延遲 WAL 紀錄(以及其後的所有內容)的應用,或者取消衝突的查詢,以便可以應用 DROP TABLE
。
當衝突的查詢很短時,通常希望透過稍微延遲 WAL 應用來允許它完成;但是 WAL 應用中的長時間延遲通常是不希望的。因此,取消機制具有參數 max_standby_archive_delay 和 max_standby_streaming_delay,它們定義了 WAL 應用中允許的最大延遲。一旦應用任何新接收的 WAL 資料所花的時間超過相關的延遲設定,就會取消衝突的查詢。有兩個參數,以便可以為從封存檔讀取 WAL 資料的情況(即,從基本備份進行初始恢復或“趕上”已經遠遠落後的備援伺服器)以及透過串流複製讀取 WAL 資料的情況指定不同的延遲值。
在主要為了高可用性而存在的備援伺服器中,最好將延遲參數設定得相對較短,以便伺服器不會因為備援查詢導致的延遲而遠遠落後於主伺服器。但是,如果備援伺服器旨在執行長時間運行的查詢,則較高甚至無限的延遲值可能是更可取的。但是請記住,如果長時間運行的查詢延遲了 WAL 紀錄的應用,它可能會導致備援伺服器上的其他工作階段看不到主伺服器上的最新變更。
一旦超過 max_standby_archive_delay
或 max_standby_streaming_delay
指定的延遲,就會取消衝突的查詢。這通常只會導致取消錯誤,儘管在重播 DROP DATABASE
的情況下,將會終止整個衝突的工作階段。此外,如果衝突是關於閒置交易持有的鎖定,則會終止衝突的工作階段(此行為將來可能會改變)。
可以立即重試取消的查詢(當然是在開始新的交易之後)。由於查詢取消取決於重播的 WAL 紀錄的性質,因此如果再次執行被取消的查詢,它很可能會成功。
請記住,延遲參數是與備援伺服器接收 WAL 資料以來經過的時間進行比較的。因此,允許備援伺服器上的任何一個查詢的寬限期永遠不會超過延遲參數,而且如果備援伺服器已經因為等待先前的查詢完成而落後,或者因為無法跟上繁重的更新負載而落後,則寬限期可能會大大縮短。
備用查詢與 WAL 重播之間最常見的衝突原因是「過早清理」。通常,PostgreSQL 允許在沒有需要看到舊版本資料的交易存在時,清理舊的資料列版本,以確保根據 MVCC 規則正確顯示資料。但是,此規則只能應用於在主伺服器上執行的交易。因此,主伺服器上的清理可能會移除仍然對備用伺服器上的交易可見的資料列版本。
資料列版本清理並不是與備用查詢衝突的唯一潛在原因。所有僅索引掃描(包括在備用伺服器上運行的掃描)都必須使用MVCC快照,該快照必須與可見性對應表「一致」。因此,每當 VACUUM
將包含一個或多個不對所有備用查詢可見的資料列的頁面,在可見性對應表中標記為全部可見時,都需要發生衝突。因此,即使對沒有需要清理的已更新或已刪除資料列的表運行 VACUUM
,也可能導致衝突。
使用者應清楚,在主伺服器上定期且大量更新的表,將很快導致備用伺服器上長時間運行的查詢被取消。在這種情況下,將 max_standby_archive_delay
或 max_standby_streaming_delay
設置為有限值,可以被認為類似於設置 statement_timeout
。
如果發現備用查詢取消的數量令人無法接受,則存在補救的可能性。第一種方法是設置參數 hot_standby_feedback
,這可以防止 VACUUM
移除最近已死亡的資料列,因此不會發生清理衝突。如果您這樣做,您應該注意到,這將延遲主伺服器上已死亡資料列的清理,這可能會導致不希望的表膨脹。但是,清理情況不會比備用查詢直接在主伺服器上運行的情況更糟,並且您仍然可以獲得將執行卸載到備用伺服器上的好處。如果備用伺服器頻繁地連接和斷開連接,您可能需要進行調整,以處理不提供 hot_standby_feedback
回饋的期間。例如,考慮增加 max_standby_archive_delay
,以便查詢不會在斷開連接期間因 WAL 封存檔中的衝突而快速取消。您還應該考慮增加 max_standby_streaming_delay
,以避免在重新連接後因新到達的串流 WAL 項目而快速取消。
可以使用備用伺服器上的 pg_stat_database_conflicts
系統檢視表來查看查詢取消的數量及其原因。pg_stat_database
系統檢視表也包含摘要資訊。
使用者可以控制在 WAL 重播等待衝突的時間超過 deadlock_timeout
時,是否產生日誌訊息。這由 log_recovery_conflict_waits 參數控制。
如果在 postgresql.conf
中 hot_standby
為 on
(預設值),並且存在 standby.signal
檔案,則伺服器將在熱備用模式下運行。但是,可能需要一段時間才能允許熱備用連線,因為伺服器在完成足夠的恢復以提供一致的狀態以供查詢運行之前,不會接受連線。在此期間,嘗試連線的用戶端將被拒絕並顯示錯誤訊息。要確認伺服器已啟動,可以從應用程式循環嘗試連線,或在伺服器日誌中尋找以下訊息
LOG: entering standby mode ... then some time later ... LOG: consistent recovery state reached LOG: database system is ready to accept read-only connections
一致性資訊在主伺服器上每個檢查點記錄一次。當讀取在 wal_level
未在主伺服器上設置為 replica
或 logical
的期間寫入的 WAL 時,無法啟用熱備用。在同時存在以下兩種情況時,到達一致狀態也可能會延遲
寫入交易包含超過 64 個子交易
長時間運行的寫入交易
如果您正在運行基於檔案的日誌傳輸(「暖備用」),您可能需要等到下一個 WAL 檔案到達,這可能與主伺服器上的 archive_timeout
設置一樣長。
某些參數的設置決定了用於追蹤交易 ID、鎖定和預備交易的共享記憶體大小。這些共享記憶體結構在備用伺服器上的大小必須不小於主伺服器,以確保備用伺服器在恢復期間不會耗盡共享記憶體。例如,如果主伺服器使用了預備交易,但備用伺服器沒有分配任何共享記憶體來追蹤預備交易,則在更改備用伺服器的配置之前,恢復無法繼續。受影響的參數為
max_connections
max_prepared_transactions
max_locks_per_transaction
max_wal_senders
max_worker_processes
確保這不會成為問題的最簡單方法是,將這些參數在備用伺服器上設置為等於或大於主伺服器上的值。因此,如果您想增加這些值,您應該首先在所有備用伺服器上執行此操作,然後再將更改應用於主伺服器。相反,如果您想減少這些值,您應該首先在主伺服器上執行此操作,然後再將更改應用於所有備用伺服器。請記住,當備用伺服器被提升時,它將成為隨後備用伺服器所需參數設置的新參考。因此,為了避免在切換或故障轉移期間出現此問題,建議在所有備用伺服器上保持這些設置相同。
WAL 會追蹤主伺服器上這些參數的更改。如果熱備用伺服器處理的 WAL 指示主伺服器上的當前值高於其自身的值,它將記錄警告並暫停恢復,例如
WARNING: hot standby is not possible because of insufficient parameter settings DETAIL: max_connections = 80 is a lower setting than on the primary server, where its value was 100. LOG: recovery has paused DETAIL: If recovery is unpaused, the server will shut down. HINT: You can then restart the server after making the necessary configuration changes.
此時,需要更新備用伺服器上的設置並重新啟動實例,然後才能繼續恢復。如果備用伺服器不是熱備用伺服器,那麼當它遇到不相容的參數更改時,它將立即關閉而不會暫停,因為此時保持它的運行沒有任何價值。
管理員選擇適當的 max_standby_archive_delay 和 max_standby_streaming_delay 設定非常重要。最佳選擇因應業務優先事項而異。例如,如果伺服器主要用作高可用性伺服器,那麼您會希望較低的延遲設定,甚至為零,儘管這是一個非常激進的設定。如果備用伺服器被用作決策支援查詢的額外伺服器,那麼將最大延遲值設定為數小時,甚至 -1(表示永遠等待查詢完成)可能是可以接受的。
在主要伺服器上寫入的交易狀態「提示位元 (hint bits)」不會記錄在 WAL 中,因此備用伺服器上的資料很可能會在備用伺服器上重新寫入提示。因此,即使所有使用者都是唯讀的,備用伺服器仍然會執行磁碟寫入;資料值本身不會發生任何變更。使用者仍然會寫入大型的排序暫存檔案並重新產生 relcache 資訊檔案,因此在熱備用模式下,資料庫的任何部分都不是真正唯讀的。另請注意,使用 dblink 模組寫入遠端資料庫,以及使用 PL 函數執行的其他資料庫外部操作仍然是可能的,即使該交易在本地是唯讀的。
以下類型的管理命令在恢復模式下不被接受:
資料定義語言 (DDL):例如,CREATE INDEX
權限和所有權:GRANT
、REVOKE
、REASSIGN
維護命令:ANALYZE
、VACUUM
、CLUSTER
、REINDEX
再次注意,實際上允許在主要伺服器上的「唯讀」模式交易期間執行其中一些命令。
因此,您無法建立僅存在於備用伺服器上的額外索引,也無法建立僅存在於備用伺服器上的統計資料。如果需要這些管理命令,則應在主要伺服器上執行它們,最終這些變更將傳播到備用伺服器。
pg_cancel_backend()
和 pg_terminate_backend()
將作用於使用者後端,但不會作用於執行恢復的啟動程序。 pg_stat_activity
不會將恢復交易顯示為活動狀態。 因此,pg_prepared_xacts
在恢復期間始終為空。 如果您想解決未決的預備交易,請在主要伺服器上檢視 pg_prepared_xacts
,並發出命令以解決那裡的交易,或在恢復結束後解決它們。
pg_locks
將像往常一樣顯示後端持有的鎖定。 pg_locks
還會顯示一個由啟動程序管理的虛擬交易,該交易擁有恢復重播的交易持有的所有 AccessExclusiveLocks
。 請注意,啟動程序不會取得鎖定來進行資料庫變更,因此除了 AccessExclusiveLocks
之外的鎖定不會在啟動程序的 pg_locks
中顯示;只是假定它們存在。
Nagios 外掛程式 check_pgsql 將起作用,因為它檢查的簡單資訊存在。 check_postgres 監控指令碼也將起作用,儘管某些報告的值可能會給出不同或令人困惑的結果。 例如,上次清理時間將不會被維護,因為備用伺服器上不會發生清理。 在主要伺服器上執行的清理仍然會將其變更傳送到備用伺服器。
WAL 檔案控制命令在恢復期間將不起作用,例如,pg_backup_start
、pg_switch_wal
等。
動態可載入模組可以正常工作,包括 pg_stat_statements
。
諮詢鎖定 (Advisory locks) 在恢復中正常工作,包括死鎖偵測。 請注意,諮詢鎖定永遠不會被 WAL 記錄,因此主要伺服器或備用伺服器上的諮詢鎖定都不可能與 WAL 重播發生衝突。 在主要伺服器上取得諮詢鎖定,並讓它在備用伺服器上啟動類似的諮詢鎖定也是不可能的。 諮詢鎖定僅與取得它們的伺服器有關。
基於觸發器的複寫系統(例如 Slony、Londiste 和 Bucardo)根本無法在備用伺服器上執行,但只要變更沒有被傳送到要套用的備用伺服器,它們就可以在主要伺服器上愉快地執行。 WAL 重播不是基於觸發器的,因此您無法從備用伺服器中繼到任何需要額外資料庫寫入或依賴使用觸發器的系統。
無法分配新的 OID,儘管某些UUID產生器可能仍然有效,只要它們不依賴於將新狀態寫入資料庫。
目前,不允許在唯讀交易期間建立暫存表,因此在某些情況下,現有指令碼將無法正確執行。 此限制可能會在稍後的版本中放寬。 這既是一個 SQL 標準合規性問題,也是一個技術問題。
只有當表空間為空時,DROP TABLESPACE
才能成功。 某些備用使用者可能會透過他們的 temp_tablespaces
參數主動使用表空間。 如果表空間中有暫存檔案,則會取消所有活動查詢以確保移除暫存檔案,以便可以移除表空間並且 WAL 重播可以繼續。
在主要伺服器上執行 DROP DATABASE
或 ALTER DATABASE ... SET TABLESPACE
將產生一個 WAL 條目,該條目將導致所有連線到備用伺服器上該資料庫的使用者被強制斷開連線。 無論 max_standby_streaming_delay
的設定如何,此動作都會立即發生。 請注意,ALTER DATABASE ... RENAME
不會斷開使用者連線,在大多數情況下這將不會被注意到,但在某些情況下,如果程式以某種方式依賴於資料庫名稱,則可能會導致程式混淆。
在正常(非恢復)模式下,如果您對具有登入功能的角色發出 DROP USER
或 DROP ROLE
,而該使用者仍處於連線狀態,則已連線使用者不會發生任何事情 — 他們保持連線。 但是,使用者無法重新連線。 此行為也適用於恢復,因此在主要伺服器上執行 DROP USER
不會斷開備用伺服器上的該使用者連線。
累積統計系統在恢復期間處於活動狀態。 所有掃描、讀取、區塊、索引使用率等都將在備用伺服器上正常記錄。 但是,WAL 重播不會增加關係和資料庫特定的計數器。 也就是說,重播不會增加 pg_stat_all_tables
欄位(如 n_tup_ins
),啟動程序執行的讀取或寫入也不會在 pg_statio_
檢視中追蹤,也不會增加相關聯的 pg_stat_database
欄位。
自動清理 (Autovacuum) 在恢復期間未啟用。 它將在恢復結束時正常啟動。
檢查點處理程序 (checkpointer process) 和背景寫入處理程序 (background writer process) 在恢復期間處於活動狀態。 檢查點處理程序將執行重新啟動點(類似於主要伺服器上的檢查點),背景寫入處理程序將執行正常的區塊清除活動。 這可以包括更新儲存在備用伺服器上的提示位元資訊。 CHECKPOINT
命令在恢復期間被接受,儘管它執行的是重新啟動點而不是新的檢查點。
在第 26.4.2 節和第 26.4.3 節中已提及各種參數。
在主要伺服器上,可以使用 wal_level 參數。如果在主要伺服器上設定 max_standby_archive_delay 和 max_standby_streaming_delay,則不會生效。
在備援伺服器上,可以使用參數 hot_standby、max_standby_archive_delay 和 max_standby_streaming_delay。
熱備援有一些限制。這些限制將來可能會被修復。
在取得快照之前,需要完全了解正在運行的交易。使用大量子交易(目前超過 64 個)的交易將會延遲唯讀連線的啟動,直到最長時間運行的寫入交易完成。如果發生這種情況,說明訊息將會發送到伺服器日誌。
備援查詢的有效起始點會在主要伺服器上的每個檢查點生成。如果在主要伺服器處於關機狀態時關閉備援伺服器,則可能無法重新進入熱備援,直到主要伺服器啟動,以便在 WAL 日誌中產生更多的起始點。在最常見的情況下,這並不是一個問題。通常,如果主要伺服器關機且不再可用,那很可能是由於嚴重的故障,需要將備援伺服器轉換為作為新的主要伺服器來運作。在主要伺服器被故意關閉的情況下,協調以確保備援伺服器順利成為新的主要伺服器也是標準程序。
在恢復結束時,由準備好的交易持有的 AccessExclusiveLocks
將需要兩倍數量的鎖定表項目。如果您計劃運行大量通常取得 AccessExclusiveLocks
的並行準備好的交易,或者您計劃運行一個取得許多 AccessExclusiveLocks
的大型交易,建議您選擇一個更大的 max_locks_per_transaction
值,可能達到主要伺服器上參數值的兩倍。如果您的 max_prepared_transactions
設定為 0,則無需考慮這一點。
在熱備援中尚無法使用可序列化的交易隔離等級。(請參閱第 13.2.3 節和第 13.4.1 節以了解詳細資訊。)嘗試在熱備援模式下將交易設定為可序列化隔離等級將會產生錯誤。
如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步說明的內容,請使用此表單來回報文件問題。