天天看點

PostgreSQL伺服器管理:高可用、負載均衡和複制

本文檔為postgresql 9.6.0文檔,本轉載已得到原譯者彭煜玮授權。

資料庫伺服器可以一起工作,這樣如果主要的伺服器失效則允許一個第二伺服器快速接手它的任務(高可用性),或者可以允許多個計算機提供相同的資料(負載均衡)。理想情況下,資料庫伺服器能夠無縫地一起工作。提供靜态網頁服務的網頁伺服器可以非常容易地通過把網頁請求均衡到多個機器來組合。事實上,隻讀的資料庫伺服器也可以相對容易地組合起來。不幸的是,大部分資料庫伺服器收到的請求是讀/寫混合的,并且讀/寫伺服器更難于組合。這是因為盡管隻讀資料隻需要在每台伺服器上放置一次,但對于任意伺服器的一次寫動作卻必須被傳播給所有的伺服器,這樣才能保證未來對于那些伺服器的讀請求能傳回一緻的結果。

這種同步問題是伺服器一起工作的最根本的困難。因為沒有單一解決方案能夠消除該同步問題對所有用例的影響。有多種解決方案,每一種方案都以一種不同的方式提出了這個問題,并且對于一種特定的負載最小化了該問題所産生的影響。

某些方案通過隻允許一台伺服器修改資料來處理同步。能修改資料的伺服器被稱為讀/寫、主要或主要伺服器。跟蹤主要機中改變的伺服器被稱為後備或從屬伺服器。如果一台後備伺服器隻有被提升為一台主要伺服器後才能被連接配接,它被稱為一台溫後備伺服器,而一台總是能夠接受連接配接并且提供隻讀查詢的後備伺服器被稱為一台熱後備伺服器。

某些方案是同步的,即一個資料修改事務隻有到所有伺服器都送出了該事務之後才被認為是送出成功。這保證了一次故障轉移不會丢失任何資料并且所有負載均衡的伺服器将傳回一緻的結果(不管哪台伺服器被查詢)。相反,異步的方案允許在一次送出和它被傳播到其他伺服器之間有一些延遲,這産生了切換到一個備份伺服器時丢失某些事務的可能性,并且負載均衡的伺服器可能會傳回略微陳舊的結果。當同步通信可能很慢時,可以使用異步通信。

方案也可以按照它們的粒度進行分類。某些方案隻能處理一整個資料庫伺服器,而其他的允許在每個表或每個資料庫的級别上進行控制。

在任何選擇中,都必須考慮性能。通常在功能和性能之間都存在着權衡。例如,在一個低速網絡上的一種完全同步的方案可能使性能減少超過一半,而一種異步的方案産生的性能影響可能是最小的。

本節的剩餘部分勾勒了多種故障轉移、複制和負載均衡方案。其中也有一個術語表可用。

1. 不同方案的比較

共享磁盤故障轉移

共享磁盤故障轉移避免了隻使用一份資料庫拷貝帶來的同步開銷。它使用一個由多個伺服器共享的單一磁盤陣列。如果主資料庫伺服器失效,後備伺服器則可以挂載并啟動資料庫,就好像它從一次資料庫崩潰中恢複過來了。這是一種快速的故障轉移,并且不存在資料丢失。

共享硬體功能在網絡儲存設備中很常見。也可以使用一個網絡檔案系統,但是要注意的是該檔案系統應具有完全的posix行為(見section 18.2.2)。這種方法的一個重大限制是如果共享磁盤陣列失效或損壞,主要和後備伺服器都會變得無法工作。另一個問題是在主要伺服器運作時,後備伺服器永遠不能通路共享存儲。

檔案系統(塊裝置)複制

共享硬體功能的一種修改版本是檔案系統複制,在其中對一個檔案系統的所有改變會被鏡像到位于另一台計算機上的一個檔案系統。唯一的限制是該鏡像過程必須能保證後備伺服器有一份該檔案系統的一緻的拷貝 — 特别是對後備伺服器的寫入必須按照主要機上相同的順序進行。drbd是用于 linux 的一種流行的檔案系統複制方案。

事務日志傳送

溫備和熱備伺服器能夠通過讀取一個預寫式日志(wal)記錄的流來保持為目前狀态。如果主伺服器失效,後備伺服器擁有主伺服器的幾乎所有資料,并且能夠快速地被變成新的主資料庫伺服器。這可以是同步的或異步的,并且隻能用于整個資料庫伺服器。

可以使用基于檔案的日志傳送(section 26.2)、流複制(見section 26.2.5)或兩者的組合來實作一個後備伺服器。關于熱備的資訊可見section 26.5。

基于觸發器的主-備複制

一個主-備複制設定會把所有資料修改查詢發送到主伺服器。主伺服器異步地将資料修改發送給後備伺服器。當主伺服器正在運作時,後備伺服器可以回答隻讀查詢。後備伺服器對資料倉庫查詢是一種理想的選擇。

slony-i是這種複制類型的一個例子。它使用表粒度,并且支援多個後備伺服器。因為它會異步更新後備伺服器(批量),在故障轉移時可能會有資料丢失。

基于語句的複制中間件

通過基于語句的複制中間件,一個程式攔截每一個 sql 查詢并把它發送給一個或所有伺服器。每一個伺服器獨立地操作。讀寫查詢必須被發送給所有伺服器,這樣每一個伺服器都能接收到任何修改。但隻讀查詢可以被隻發送給一個伺服器,這樣允許讀負載在伺服器之間分布。

如果查詢被簡單地且未經修改地廣播,random()、current_timestamp之類的函數以及序列在不同伺服器上可能有不同的值。這是因為每一個伺服器會獨立地操作,并且 sql 查詢被廣播(而不是真正被修改的行)。如果這不可接受,中間件或應用必須從一個單一伺服器查詢這樣的值并且然後将那些值用在寫查詢中。另一個選項是将這個複制選項和一種傳統主-備設定一起使用,即資料修改查詢隻被發送給主伺服器并且通過主-備複制傳播到後備伺服器,而不是通過複制中間件。必須要注意的是,所有事務要麼在所有伺服器上都送出,要麼在所有伺服器上都中止,也許可以使用兩階段送出(prepare transaction和commit prepared)。pgpool-ii和continuent tungsten是這種複制類型的例子。

異步多主要機複制

對于不會被定期連接配接的伺服器(如筆記本或遠端伺服器),保持伺服器間的資料一緻是一個挑戰。通過使用異步的多主要機複制,每一個伺服器獨立工作并且定期與其他伺服器通信來确定沖突的事務。這些沖突可以由使用者或沖突解決規則來解決。bucardo 是這種複制類型的一個例子。

同步多主要機複制

在同步多主要機複制中,每一個伺服器能夠接受寫請求,并且在每一個事務送出之前,被修改的資料會被從原始伺服器傳送給每一個其他伺服器。繁重的寫活動可能導緻過多的鎖定,進而導緻很差的性能。事實上,寫性能通常比一個單一伺服器還要糟。讀請求可以被發送給任意伺服器。某些實作使用共享磁盤來減少通信負荷。同步多主要機複制主要對于讀負載最好,盡管它的大優點是任意伺服器都能接受寫請求 — 沒有必要在主伺服器和後備伺服器之間劃分負載,并且因為資料修改被從一個伺服器發送到另一個伺服器,不會有非确定函數(如random())的問題。

postgresql不提供這種複制類型,盡管在應用代碼或中間件中可以使用postgresql的兩階段送出(prepare transaction和commit prepared)來實作這種複制。

商業方案

because 因為postgresql是開源的并且很容易被擴充,一些公司已經使用postgresql并且建立了帶有唯一故障轉移、複制和負載均衡能力的商業性的閉源方案。

table 26-1總結了上述多種方案的能力。

table 26-1. 高可用、負載均衡和複制特性矩陣

PostgreSQL伺服器管理:高可用、負載均衡和複制

有一些方案不适合上述的類别:

資料分區

資料分區将表分開成資料集。每個集合隻能被一個伺服器修改。例如,資料可以根據辦公室劃分,如倫敦和巴黎,每一個辦公室有一個伺服器。如果查詢有必要組合倫敦和巴黎的資料,一個應用可以查詢兩個伺服器,或者可以使用主/備複制來在每一台伺服器上保持其他辦公室資料的一個隻讀拷貝。

多伺服器并行查詢執行

上述的很多方案允許多個伺服器來處理多個查詢,但是沒有一個允許一個單一查詢使用多個伺服器來更快完成。這種方案允許多個伺服器在一個單一查詢上并發工作。這通常通過把資料在伺服器之間劃分并且讓每一個伺服器執行該查詢中屬于它的部分,然後将結果傳回給一個中心伺服器,由它整合結果并發回給使用者。pgpool-ii具有這種能力。同樣,也可以使用pl/proxy工具集來實作這種方案。

2. 日志傳送後備伺服器

連續歸檔可以被用來建立一個高可用性(ha)叢集配置,其中有一個或多個後備伺服器随時準備在主伺服器失效時接管操作。這種能力被廣泛地稱為溫備或日志傳送。

主伺服器和後備伺服器一起工作來提供這種能力,但這些伺服器隻是松散地組織在一起。主伺服器在連續歸檔模式下操作,而每一個後備伺服器在連續恢複模式下操作并且持續從主伺服器讀取 wal 檔案。要啟用這種能力不需要對資料庫表做任何改動,是以它相對于其他複制方案降低了管理開銷。這種配置對主伺服器的性能影響也相對較低。

直接從一個資料庫伺服器移動 wal 記錄到另一台伺服器通常被描述為日志傳送。postgresql通過一次一檔案(wal 段)的 wal 記錄傳輸實作了基于檔案的日志傳送。不管 wal 檔案(16 mb)要被送到一個臨近的系統、同一站點的另一個系統或是在地球遙遠的另一端的一個系統上,它都可以在任何距離上被簡單和便宜地傳送。這種技術所需的帶寬取根據主伺服器的事務率而變化。基于記錄的日志傳送具有更細的粒度并且能夠在網絡連接配接上以流的方式增量傳遞 wal 的改變(見section 26.2.5)。

需要注意的是日志傳送是異步的,即 wal 記錄是在事務送出後才被傳送。正因為如此,在一個視窗期内如果主伺服器發生災難性的失效則會導緻資料丢失,還沒有被傳送的事務将會被丢失。基于檔案的日志傳送中這個資料丢失視窗的尺寸可以通過使用參數archive_timeout進行限制,它可以被設定成低至數秒。但是這樣低的設定大體上會增加檔案傳送所需的帶寬。流複制(見section 26.2.5)允許更小的資料丢失視窗。

這種配置的恢複性能是足夠好的,後備伺服器在被激活後通常隻有片刻就可以到達完全可用。是以,這被稱為一種提供高可用性的溫備配置。從一個已歸檔的基礎備份恢複一個伺服器并且前滾将需要較長時間,是以該技術隻提供了災難恢複的一種方案,而不适合于高可用性。一台後備伺服器也可以被用于隻讀查詢,在這種情況下它被稱為一台熱備伺服器。

2.1. 規劃

建立主伺服器和後備伺服器通常是明智的,是以它們可以盡可能相似,至少從資料庫伺服器的角度來看是這樣。特别地,與表空間相關的路徑名将被未經修改地傳遞,是以如果該特性被使用,主、備伺服器必須對表空間具有完全相同的挂載路徑。記住如果create tablespace在主伺服器上被執行,在指令被執行前,它所需要的任何新挂載點必須在主伺服器和所有後備伺服器上先建立好。硬體不需要完全相同,但是經驗顯示,在應用和系統的生命期内維護兩個相同的系統比維護兩個不相似的系統更容易。在任何情況下硬體架構必須相同 — 從一個 32 位系統傳送到一個 64 位系統将不會工作。

通常,不能在兩個運作着不同主版本postgresql的伺服器之間傳送日志。postgresql 全球開發組的政策是不在次版本更新中改變磁盤格式,是以在主伺服器和後備伺服器上運作不同次版本将會成功地工作。不過,在這方面并沒有提供正式的支援,是以我們建議讓主備伺服器上運作的版本盡可能相同。當更新到一個新的次版本時,最安全的政策是先更新後備伺服器 — 一個新的次版本發行更可能相容從前一個次版本讀取 wal 檔案。

2.2. 後備伺服器操作

在後備模式中,伺服器持續地應用從主要伺服器接收到的 wal。後備伺服器可以從一個 wal 歸檔(restore_command)或者通過一個 tcp 連接配接直接從主要機(流複制)讀取 wal。後備伺服器将也嘗試恢複在後備集簇的pg_xlog目錄中找到的 wal。那通常在一次資料庫重新開機後發生,那時後備機将在重新開機之前重播從主要機流過來的 wal,但是你也可以在任何時候手動拷貝檔案到pg_xlog讓它們被重播。

在啟動時,後備機通過恢複歸檔位置所有可用的 wal 來開始,這稱為restore_command。一旦它到達那裡可用的 wal 的末尾并且restore_command失敗,它會嘗試恢複pg_xlog目錄中可用的任何 wal。如果那也失敗并且流複制已被配置,後備機會嘗試連接配接到主伺服器并且從在歸檔或pg_xlog中找到的最後一個可用記錄開始流式傳送 wal。如果那失敗并且沒有配置流複制,或者該連接配接後來斷開,後備機會傳回到步驟 1 并且嘗試再次從歸檔裡的檔案恢複。這種嘗試歸檔、pg_xlog和流複制的循環會一直重複知道伺服器停止或者一個觸發器檔案觸發了故障轉移。

當pg_ctl promote被運作或一個觸發器檔案被找到(trigger_file),後備模式會退出并且伺服器會切換到普通操作。在故障轉移之前,在歸檔或pg_xlog中立即可用的任何 wal 将被恢複,但不會嘗試連接配接到主要機。

2.3. 為後備伺服器準備主要機

如section 25.3中所述,在主伺服器上設定連續歸檔到一個後備伺服器可通路的歸檔目錄。即使主伺服器垮掉該歸檔位置也應當是後備伺服器可通路的,即它應當位于後備伺服器本身或者另一個可信賴的伺服器,而不是位于主要伺服器上。

如果你想要使用流複制,在主伺服器上設定認證來允許來自後備伺服器的複制連接配接。即建立一個角色并且在pg_hba.conf中提供一個或多個資料庫域被設定為replication的項。還要保證在主伺服器的配置檔案中max_wal_senders被設定為足夠大的值。如果要使用複制槽,請確定max_replication_slots也被設定得足夠高。

2.4. 建立一個後備伺服器

要建立後備伺服器,恢複從主伺服器取得的基礎備份。在後備伺服器的集簇資料目錄中建立一個恢複指令檔案recovery.conf,并且打開standby_mode。将restore_command設定為一個從 wal 歸檔中複制檔案的簡單指令。如果你計劃為了高可用性目的建立多個後備伺服器,将recovery_target_timeline設定為latest來使得該後備伺服器遵循發生在故障轉移到另一個後備伺服器之後發生的時間線改變。

note: 不要把 pg_standby 或相似的工具和這裡描述的内建後備模式一起使用。如果檔案不存在,restore_command應該立即傳回,如果必要該伺服器将再次嘗試該指令。

如果你想要使用流複制,在primary_conninfo中填入一個 libpq 連接配接字元串,其中包括主機名(或 ip 位址)和連接配接到主伺服器所需的任何附加細節。如果主伺服器需要一個密碼用于認證,密碼也應該被指定在primary_conninfo中。

如果你正在為高性能目的建立後備伺服器,像主伺服器一樣建立 wal 歸檔、連接配接和認證,因為在故障轉移後該後備伺服器将作為一個主伺服器工作。

如果你正在使用一個 wal 歸檔,可以使用archive_cleanup_command參數來移除後備伺服器不再需要的檔案,這樣可以最小化 wal 歸檔的尺寸。pg_archivecleanup工具被特别設計為在典型單一後備配置下與archive_cleanup_command共同使用,見pg_archivecleanup。不過要注意,如果你正在為備份目的使用歸檔,有一些檔案即使後備伺服器不再需要你也需要保留它們,它們被用來從至少最後一個基礎備份恢複。

recovery.conf的一個簡單例子是:

你可以有任意數量的後備伺服器,但是如果你使用流複制,確定你在主伺服器上将max_wal_senders設定得足夠高,這樣可以允許它們能同時連接配接。

2.5. 流複制

流複制允許一台後備伺服器比使用基于檔案的日志傳送更能保持為最新的狀态。後備伺服器連接配接到主伺服器,主伺服器則在 wal 記錄産生時即将它們以流式傳送給後備伺服器而不必等到 wal 檔案被填充。

預設情況下流複制是異步的(見section 26.2.8),在這種情況下主伺服器上送出一個事務與該變化在後備伺服器上變得可見之間存在短暫的延遲。不過這種延遲比基于檔案的日志傳送方式中要小得多,在後備伺服器的能力足以跟得上負載的前提下延遲通常低于一秒。在流複制中,不需要archive_timeout來縮減資料丢失視窗。

如果你使用的流複制沒有基于檔案的連續歸檔,該伺服器可能在後備機收到 wal 段之 前回收這些舊的 wal 段。如果發生這種情況,後備機将需要重新從一個新的基礎備 份初始化。通過設定wal_keep_segments為一個足夠高的值來確定舊 的 wal 段不會被太早重用或者為後備機配置一個複制槽,可以避免發生這種情況。如 果設定了一個後備機可以通路的 wal 歸檔,就不需要這些解決方案,因為該歸檔可以 為後備機保留足夠的段,後備機總是可以使用該歸檔來追趕主要機。

如果你使用的流複制沒有基于檔案的連續歸檔,你必須在主伺服器上設定wal_keep_segments為一個足夠高的值來確定舊的 wal 段不會被太早再利用,因為後備伺服器可能還需要它們來追上主伺服器。如果後備伺服器落後太多,它需要從一個新的基礎備份進行初始化。如果你設定了一個後備伺服器可通路的 wal 歸檔,wal_keep_segments就不是必要的,因為後備伺服器總是可以使用該歸檔來追上主伺服器。

要使用流複制,按section 26.2所述建立一個基于檔案的日志傳送後備伺服器。将一個基于檔案日志傳送後備伺服器轉變成流複制後備伺服器的步驟是把recovery.conf檔案中的primary_conninfo設定指向主伺服器。設定主伺服器上的listen_addresses和認證選項(見pg_hba.conf),這樣後備伺服器可以連接配接到主伺服器上的僞資料庫replication。

在支援 keepalive 套接字選項的系統上,設定tcp_keepalives_idle、tcp_keepalives_interval和tcp_keepalives_count有助于主伺服器迅速地注意到一個斷開的連接配接。

設定來自後備伺服器的并發連接配接的最大數目。

當後備伺服器被啟動并且primary_conninfo被正确設定,後備伺服器将在重放完歸檔中所有可用的 wal 檔案之後連接配接到主伺服器。如果連接配接被成功建立,你将在後備伺服器中看到一個 walreceiver 程序,并且在主伺服器中有一個相應的 walsender 程序。

2.5.1. 認證

設定好用于複制的通路權限非常重要,這樣隻有受信的使用者可以讀取 wal 流,因為很容易從 wal 流中抽取出需要特權才能通路的資訊。後備伺服器必須作為一個超級使用者或一個具有replication特權的賬戶向主伺服器認證。我們推薦為複制建立一個專用的具有replication和login特權的使用者賬戶。雖然replication特權給出了非常高的權限,但它不允許使用者修改主系統上的任何資料,而superuser特權則可以。

複制的用戶端認證由一個在database域中指定replication的pg_hba.conf記錄控制。例如,如果後備伺服器運作在主機 ip 192.168.1.100并且用于複制的賬戶名為foo,管理者可以在主伺服器上向pg_hba.conf檔案增加下列行:

主伺服器的主機名和端口号、連接配接使用者名和密碼在recovery.conf檔案中指定。在後備伺服器上還可以在~/.pgpass檔案中設定密碼(在database域中指定replication)。例如,如果主伺服器運作在主機 ip 192.168.1.50、端口5432上,并且密碼為foopass,管理者可以在後備伺服器的recovery.conf檔案中增加下列行:

2.5.2. 監控

流複制的一個重要健康名額是在主伺服器上産生但還沒有在後備伺服器上應用的 wal 記錄數。你可以通過比較主伺服器上的目前 wal 寫位置和後備伺服器接收到的最後一個 wal 位置來計算這個滞後量。它們分别可以用主伺服器上的pg_current_xlog_location和後備伺服器上的pg_last_xlog_receive_location來檢索。後備伺服器的最後 wal 接收位置也被顯示在 wal 接收者程序的程序狀态中,即使用ps指令顯示的狀态。

你可以通過pg_stat_replication視圖檢索 wal 發送者程序的清單。pg_current_xlog_location與sent_location域之間的巨大差異表示主伺服器承受着巨大的負載,而sent_location和後備伺服器上pg_last_xlog_receive_location之間的差異可能表示網絡延遲或者後備伺服器正承受着巨大的負載。

2.6. 複制槽

複制槽提供了一種自動化的方法來確定主要機在所有的後備機收到 wal 段 之前不會移除它們,并且主要機也不會移除可能導緻 恢複沖突的行,即使後備機斷開也是如此。

作為複制槽的替代,也可以使用wal_keep_segments 阻止移除舊的 wal 段,或者使用archive_command 把段儲存在一個歸檔中。不過,這些方法常常會導緻保留的 wal 段比需要的 更多,而複制槽隻保留已知所需要的段。這些方法的一個優點是它們為 pg_xlog的空間需求提供了界限,但目前使用複制槽無法做到。

類似地,hot_standby和 vacuum_defer_cleanup_age保護了相關行不被 vacuum 移除,但是前者在後備機斷開期間無法提供保護,而後者則需要被設定為一個很高 的值已提供足夠的保護。複制槽克服了這些缺點。

2.6.1. 查詢和操縱複制槽

每個複制槽都有一個名字,名字可以包含小寫字母、數字和下劃線字元。

已有的複制槽和它們的狀态可以在 pg_replication_slots 視圖中看到。

槽可以通過流複制協定 或者 sql 函數建立并且移除。

2.6.2. 配置執行個體

你可以這樣建立一個複制槽:

要配置後備機使用這個槽,在後備機的recovery.conf中應該配置 primary_slot_name。這裡是一個簡單的例子:

2.7. 級聯複制

級聯複制特性允許一台後備伺服器接收複制連接配接并且把 wal 記錄流式傳送給其他後備伺服器,就像一個轉發器一樣。這可以被用來減小對于主要機的直接連接配接數并且使得站點間的帶寬開銷最小化。

一台同時扮演着接收者和發送者角色的後備伺服器被稱為一台級聯後備伺服器。“更直接”(通過更少的級聯後備伺服器)連接配接到主要機的後備伺服器被稱為上遊伺服器,而那些離得更遠的後備伺服器被稱為下遊伺服器。級聯複制并沒有對下遊伺服器的數量或布置設定限制。

一台級聯後備伺服器不僅僅發送從主要機接收到的 wal 記錄,還要發送那些從歸檔中恢複的記錄。是以即使某些上遊連接配接中的複制連接配接被中斷,隻要還有新的 wal 記錄可用,下遊的流複制都會繼續下去。

級聯複制目前是異步的。同步複制設定目前對級聯複制無影響。

不管在什麼樣的級聯布置中,熱備回報都會向上遊傳播。

如果一台上遊後備伺服器被提升為新的主要機,且下遊伺服器的recovery_target_timeline被設定成'latest',下遊伺服器将繼續從新的主要機得到流。

要使用級聯複制,要建立級聯後備伺服器讓它能夠接受複制連接配接(即設定max_wal_senders和hot_standby,并且配置基于主機的認證)。你還将需要設定下遊後備伺服器中的primary_conninfo指向級聯後備伺服器。

2.8. 同步複制

postgresql流複制預設是異步的。如果主伺服器崩潰,則某些已被送出的事務可能還沒有被複制到後備伺服器,這會導緻資料丢失。資料的丢失量與故障轉移時的複制延遲成比例。

同步複制能夠保證一個事務的所有修改都能被傳送到一台或者多台同步後備伺服器。這擴大了由一次事務送出所提供的标準持久化級别。在計算機科學理論中這種保護級别被稱為 2-safe 複制。而當synchronous_commit被設定為remote_write時,則是 group-1-safe (group-safe 和 1-safe)。

在請求同步複制時,一個寫事務的每次送出将一直等待,直到收到一個确認表明該送出在主伺服器和後備伺服器上都已經被寫入到磁盤上的事務日志中。資料會被丢失的唯一可能性是主伺服器和後備伺服器在同一時間都崩潰。這可以提供更進階别的持久性,盡管隻有系統管理者要關系兩台伺服器的放置和管理。等待确認提高了使用者對于修改不會丢失的信心,但是同時也不必要地增加了對請求事務的響應時間。最小等待時間是在主伺服器和後備伺服器之間的來回時間。

隻讀事務和事務復原不需要等待後備伺服器的回複。子事務送出也不需要等待後備伺服器的響應,隻有頂層送出才需要等待。長時間運作的動作(如資料載入或索引建構)不會等待最後的送出消息。所有兩階段送出動作要求送出等待,包括預備和送出。

2.8.1. 基本配置

一旦流複制已經被配置,配置同步複制就隻需要一個額外的配置步驟:synchronous_standby_names必須被設定為一個非空值。synchronous_commit也必須被設定為on,但由于這是預設值,通常不需要改變。這樣的配置将導緻每一次送出都等待确認消息,以保證後備伺服器已經将送出記錄寫入到持久化存儲中。synchronous_commit可以由個體使用者設定,是以它可以在配置檔案中配置、可以為特定使用者或資料庫配置或者由應用動态配置,這樣可以在一種每事務基礎上控制持久性保證。

在一個送出記錄已經在主伺服器上被寫入到磁盤後,wal 記錄接着被發送到後備伺服器。每次一批新的 wal 資料被寫入到磁盤後,後備伺服器會發送回複消息,除非在後備伺服器上wal_receiver_status_interval被設定為零。如果synchronous_commit被設定為remote_apply,當送出記錄被重放時後備伺服器會發送回應消息,這會讓該事務變得可見。如果從主伺服器的synchronous_standby_names優先清單中選中該後備伺服器作為一個同步後備,将會根據來自該後備伺服器和其他同步後備的回應消息來決定何時釋放正在等待确認送出記錄被收到的事務。這些參數允許管理者指定哪些後備伺服器應該是同步後備。注意同步複制的配置主要在主要機上。命名的後備伺服器必須直接連接配接到主要機,主要機對使用級聯複制的下遊後備伺服器一無所知。

将synchronous_commit設定為remote_write将導緻每次送出都等待後備伺服器已經接收送出記錄并将它寫出到其自身所在的作業系統的确認,但并非等待資料都被刷出到後備伺服器上的磁盤。這種設定提供了比on要弱一點的持久性保障:在一次作業系統崩潰事件中後備伺服器可能丢失資料,盡管它不是一次postgresql崩潰。不過,在實際中它是一種有用的設定,因為它可以減少事務的響應時間。隻有當主伺服器和後備伺服器都崩潰并且主伺服器的資料庫同時被損壞的情況下,資料丢失才會發生。

把synchronous_commit設定為remote_apply将導緻每一次送出都會等待,直到目前的同步後備伺服器報告說它們已經重放了該事務,這樣就會使該事務對使用者查詢可見。在簡單的情況下,這為帶有因果一緻性的負載均衡留出了餘地。

如果請求一次快速關閉,使用者将停止等待。不過,在使用異步複制時,在所有未解決的 wal 記錄被傳輸到目前連接配接的後備伺服器之前,伺服器将不會完全關閉。

2.8.2. 多個同步後備

同步複制支援一個或者更多個同步後備伺服器,事務将會等待,直到所有同步後備伺服器都确認收到了它們的資料為止。事務必須等待其回複的同步後備的數量由synchronous_standby_names指定。這個參數也指定後備伺服器的名稱清單,它決定了每一個後備伺服器被選中為同步後備的優先級。出現在清單中越靠前優先級越高。出現在清單中靠後位置的後備伺服器表示潛在的同步後備。如果任何一個目前後備伺服器由于任何原因斷開連接配接,它将立刻被下一個具有最高優先級的後備伺服器替代。

多個同步後備的synchronous_standby_names示例為:

在這個例子中,如果有四個後備伺服器s1、s2、s3和s4在運作,兩個後備伺服器s1和s2将被選中為同步後備,因為它們出現在後備伺服器名稱清單的前部。s3是一個潛在的同步後備,當s1或s2中的任何一個失效, 它就會取而代之。s4則是一個異步後備因為它的名字不在清單中。

2.8.3. 性能規劃

同步複制通常要求仔細地規劃和放置後備伺服器來保證應用能令人滿意地工作。等待并不利用系統資源,但是事務鎖會持續保持直到傳輸被确認。其結果是,不小心使用同步複制将由于響應時間增加以及較高的争用率而降低資料庫應用的性能。

postgresql允許應用開發者通過複制來指定所要求的持久性級别。這可以為整個系統指定,不過它也能夠為特定的使用者或連接配接指定,甚至還可以為單個事務指定。

例如,一個應用的載荷的組成可能是這樣:10% 的改變是重要的客戶詳情,而 90% 的改變是不太重要的資料,即使它們丢失業務也比較容易容忍(例如使用者間的聊天消息)。

通過在應用級别(在主伺服器上)指定的同步複制選項,我們可以為大部分重要的改變提供同步複制,并且不會拖慢整體的載荷。應用級别選項是使高性能應用享受同步複制的一種重要和實用的工具。

你應該認為網絡帶寬必須比 wal 資料的産生率高。

2.8.4. 高可用性規劃

當synchronous_commit被設定為on、remote_apply或者remote_write時, synchronous_standby_names指定産生的事務送出要等待其回應的同步後備的數量和名稱。如果任一同步後備崩潰,這類事務送出可能無法完成。

高可用的最佳方案是確定有所要求數量的同步後備。這可以通過使用synchronous_standby_names指定多個潛在後備伺服器來實作。出現在該清單前部的後備伺服器将被用作同步後備。後面的後備伺服器将在目前同步後備伺服器失效時取而代之。

當一台後備伺服器第一次附加到主伺服器時,它将處于一種還沒有正确同步的狀态。這被描述為追趕模式。一旦後備伺服器和主伺服器之間的遲滞第一次變成零,我們就來到了實時的流式狀态。在後備伺服器被建立之後的很長一段時間内可能都是追趕模式。如果後備伺服器被關閉,則追趕周期将被增加,增加量由後備伺服器被關閉的時間長度決定。隻有當後備伺服器到達流式狀态後,它才能成為一台同步後備。

如果在送出正在等待确認時主伺服器重新開機,那些正在等待的事務将在主資料庫恢複時被标記為完全送出。沒有辦法确認所有後備伺服器已經收到了在主伺服器崩潰時所有還未處理的 wal 資料。某些事務可能不會在後備伺服器上顯示為已送出,即使它們在主伺服器上顯示為已送出。我們提供的保證是:在 wal 資料已經被所有後備伺服器安全地收到之前,應用将不會收到一個事務成功送出的顯式确認。

如果實在無法保持所要求數量的同步後備,那麼應該減少synchronous_standby_names中指定的事務送出應該等待其回應的同步後備的數量(或者禁用),并且在主伺服器上重載配置檔案。

如果主伺服器與剩下的後備伺服器是隔離的,你應當故障轉移到那些其他剩餘後備伺服器中的最佳候選者上。

如果在事務等待時你需要重建一台後備伺服器,確定指令 pg_start_backup() 和 pg_stop_backup() 被運作在一個synchronous_commit = off的會話中,否則那些請求将永遠等待後備伺服器出現。

2.9. 在後備機上連續歸檔

當在一個後備機上使用連續歸檔時,有兩種不同的情景:wal 歸檔在主伺服器 和後備機之間共享,或者後備機有自己的 wal 歸檔。當後備機擁有其自身的 wal 歸檔時,将archive_mode設定為 always,後備機将在收到每個 wal 段時調用歸檔指令, 不管它是從歸檔恢複還是使用流複制恢複。共享歸檔可以類似地處理,但是 archive_command必須測試要被歸檔的檔案是否 已經存在,以及現有的檔案是否有相同的内容。這要求 archive_command中有更多處理,因為它必須當心 不要覆寫具有不同内容的已有檔案,但是如果完全相同的檔案被歸檔兩次時 應傳回成功。并且如果兩個伺服器嘗試同時歸檔同一個檔案,所有這些都必須 在沒有競争情況的前提下完成。

如果archive_mode被設定為on,歸檔器 在恢複或者後備模式中無法啟用。如果後備伺服器被提升,它将在被提升後開始 歸檔,但是它将不會歸檔任何不是它自身産生的 wal。要在歸檔中得到完整的 一系列 wal 檔案,你必須確定所有 wal 在到達後備機之前都被歸檔。對于基于 檔案的日志傳輸來說天然就是這樣,因為後備機隻能恢複在歸檔中找到的檔案, 而啟用了流複制時則不是這樣。當一台伺服器不在恢複模式中時,在 on和always模式之間沒有差别。

3. 故障轉移

如果主伺服器失效,則後備伺服器應該開始故障轉移過程。

如果後備伺服器失效,則不會有故障轉移發生。如果後備伺服器可以被重新開機(即使晚一點),由于可重新開機恢複的優勢,那麼恢複處理也能被立即重新開機。如果後備伺服器不能被重新開機,則一個全新的後備伺服器執行個體應該被建立。

如果主伺服器失效并且後備伺服器成為了新的主伺服器,那麼接下來舊的主伺服器重新開機後,你必須有一種機制來通知舊的主伺服器不再成為主伺服器。有些時候這被稱為stonith(shoot the other node in the head,關閉其他節點),這對于避免出現兩個系統都認為它們是主伺服器的情況非常必要,那種情況将導緻混亂并且最終導緻資料丢失。

很多故障轉移系統僅使用兩個系統,主系統和後備系統,它們由某種心跳機制連接配接來持續驗證兩者之間的連接配接性和主系統的可用性。也可能會使用第三個系統(稱為目擊者伺服器)來防止某些不當故障轉移的情況,但是除非非常小心地建立它并且經過了嚴格地測試,額外的複雜度可能會使該工作得不償失。

postgresql并不提供在主伺服器上辨別失敗并且通知後備資料庫伺服器所需的系統軟體。現在已有很多這樣的工具并且很好地與成功的故障轉移所需的作業系統功能整合在一起,例如 ip 位址遷移。

一旦發生到後備伺服器的故障轉移,就隻有單一的一台伺服器在操作。這被稱為一種退化狀态。之前的後備伺服器現在是主伺服器,但之前的主伺服器處于關閉并且可能一直保持關閉。要回到正常的操作,一個後備伺服器必須被重建,要麼在之前的主系統起來時使用它重建,要麼使用第三台(可能是全新的)伺服器來重建。在大型集簇上,pg_rewind功能可以被用來加速這個過程。一旦完成,主伺服器和後備伺服器可以被認為是互換了角色。某些人選擇使用第三台伺服器來為新的主伺服器提供備份,直到新的後備伺服器被重建,不過顯然這會使得系統配置和操作處理更複雜。

是以,從主伺服器切換到後備伺服器可以很快,但是要求一些時間來重新準備故障轉移叢集。從主伺服器到後備伺服器的正常切換是有用的,因為它允許每個系統有正常的關閉時間來進行維護。這也可以作為一種對故障轉移機制的測試,以保證在你需要它時它真地能夠工作。我們推薦寫一些管理過程來做這些事情。

要觸發一台日志傳送後備伺服器的故障轉移,運作pg_ctl promote或者建立一個觸發器檔案,其檔案名和路徑由recovery.conf中的trigger_file設定指定。如果你正在規劃使用pg_ctl promote進行故障轉移,trigger_file就不是必要的。如果你正在建立隻用于從主伺服器分流隻讀查詢而不是高可用性目的的報告伺服器,你不需要提升它。

4. 日志傳送的替代方法

前一節描述的内建後備模式的一種替代方案是使用一個輪詢歸檔位置的restore_command。這是版本 8.4 及以下版本中唯一可用的選項。在這種設定中,設定standby_mode為關閉,因為你要自行實作後備操作所需的輪詢。關于這種實作的一個參考請見pg_standby子產品。

注意在這種模式中,伺服器将一次應用一整個檔案的 wal,是以如果你使用後備伺服器來查詢(見熱備),那麼主伺服器上的一個動作和後備伺服器上該動作變得可見之間會有一個延遲,該延遲對應着填滿 wal 檔案的時間。archive_timeout可以被用來縮短該延遲。還要注意你不能把流複制和這種方法組合起來使用。

在主伺服器和後備伺服器上都會發生的操作是通常的連續歸檔和恢複任務。兩個資料庫伺服器之間唯一的接觸點是兩者共享的 wal 檔案歸檔:主伺服器寫這個歸檔,後備伺服器讀取這個歸檔。必須要小心地保證來自獨立主伺服器的 wal 歸檔不會混合在一起或者混淆。如果歸檔隻被後備操作需要,它不必很大。

使得兩台松耦合的伺服器一起工作的訣竅是在後備伺服器上使用的restore_command,當要求下一個 wal 檔案時,會等待它在主伺服器上變得可用。restore_command在後備伺服器的recovery.conf檔案中指定。正常的恢複處理将從 wal 歸檔請求一個檔案,如果該檔案不可用則會報告失敗。對于後備處理來說下一個 wal 檔案不可用很正常,是以後備伺服器必須等待它出現。對于以.backup或.history結尾的檔案沒有必要等待,并且必須傳回一個非零的傳回碼。一個等待的restore_command可以用一種習慣的腳本編寫,在其中輪詢下一個 wal 檔案的存在之後進行循環。也必須有某種方式來觸發故障轉移,那将打斷restore_command:打破循環并傳回一個檔案未找到錯誤給後備伺服器。這會結束恢複并且後備伺服器将接下來變成一個正常的伺服器。

一個合适的restore_command的僞代碼是:

在pg_standby子產品中提供了一個等待的restore_command的工作例子。它也可被用作如何正确實作上述邏輯的參考。它也可以根據需要被擴充來支援指定的配置和環境。

觸發故障轉移的方法是規劃和設計中的一個重要部分。一種潛在的選項是restore_command指令。它對每一個 wal 檔案被執行一次,但是運作restore_command的程序會為每一個檔案建立和死亡,是以沒有守護程序或伺服器程序,并且也不能使用信号或信号句柄。是以,restore_command不适合于觸發故障轉移。可以使用一種簡單的逾時功能,特别是和主伺服器上已知的archive_timeout設定一起。但是,由于一個網絡問題或者繁忙的主伺服器可能足以發起故障轉移,這有點容易産生錯誤。如果可以安排,一種提醒機制(例如顯式建立一個觸發器檔案)是最理想的。

4.1. 實作

使用這種替代方案配置一個後備伺服器的簡短過程如下所示。對于每一步的細節,可以參考之前的小節。

1.盡可能将主系統和後背系統設定成近乎一緻,包括在同一發行級别上的兩個相同的postgresql拷貝。

2.在後備伺服器上建立從主系統到一個 wal 歸檔目錄的連續歸檔。確定在主伺服器上archive_mode、archive_command和archive_timeout被恰當地設定。

3.建立主伺服器的一個基礎備份,并且把該資料載入到後備伺服器。

4.在後備伺服器上開始從本地 wal 歸檔的恢複,在recovery.conf中指定一個按之前所述進行等待的restore_command。

恢複将 wal 歸檔當作隻讀的來處理,是以一旦一個 wal 檔案已經被複制到後備系統,在它正在被後備資料庫伺服器讀取時可以被同時複制到錄音帶。是以,可以在為了長期災難恢複目的存儲檔案的同時運作一個用于高可用性的後備伺服器。

為了測試的目的,可以在一個相同的系統上運作主伺服器和後備伺服器。這對于伺服器魯棒性并不會提供任何有意義的改進,對 ha 也一樣。

4.2. 基于記錄的日志傳送

也可以使用這種替代方法來實作基于記錄的日志傳送,不過這需要定制開發,并且隻有在一整個 wal 檔案被傳送之後改變才會對熱後備查詢可見。

一個外部程式可以調用pg_xlogfile_name_offset()函數來找出 wal 的目前末端的檔案名和其中準确的位元組偏移。它接着可以直接通路 wal 檔案并且将從上一個已知的 wal 末尾到目前末尾之間的資料拷貝到後備伺服器。通過這種方法,資料丢失的視窗是複制程式的輪詢周期時間,這可以為非常小,并且不會有強制部分使用的段檔案被歸檔所浪費的帶寬。注意後備伺服器的restore_command腳本隻能處理整個 wal 檔案,是以增量複制的資料通常不會對後備伺服器可用。隻有當主伺服器死掉時它才有用 — 那時最後一個部分 wal 檔案會在允許它發生之前被喂給後備伺服器。這個處理的正确實作要求restore_command腳本和資料複制程式的合作。

從postgresql 版本 9.0 開始,你可以使用流複制來實作事半功倍的效果。

5. 熱備

術語熱備用來描述處于歸檔恢複或後備模式中的伺服器連接配接到伺服器并運作隻讀查詢的能力。這有助于複制目的以及以高精度恢複一個備份到一個期望的狀态。術語熱備也指伺服器從恢複轉移到正常操作而使用者能繼續運作查詢并且保持其連接配接打開的能力。

在熱備模式中運作查詢與正常查詢操作相似,盡管如下所述存在一些用法和管理上的差別。

5.1. 使用者概覽

當hot_standby參數在一台後備伺服器上被設定為真時,一旦恢複将系統帶到一個一緻的狀态它将開始接受連接配接。所有這些連接配接都被限制為隻讀,甚至臨時表都不能被寫入。

後備伺服器上的資料需要一些時間從主伺服器到達後備伺服器,是以在主伺服器和後備伺服器之間将有一段可以度量的延遲。近乎同時在主伺服器和後備伺服器上運作相同的查詢可能是以而傳回不同的結果。我們說後備伺服器上的資料與主伺服器是最終一緻的。一旦一個事務的送出記錄在後備伺服器上被重播,那個事務所作的修改将對後備伺服器上所有新取得的快照可見。快照可以在每個查詢或每個事務的開始時取得,這取決于目前的事務隔離級别。

在熱備期間開始的事務可能發出下列指令:

查詢通路 - 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

在熱備期間開始的事務将不會被配置設定一個事務 id 并且不能被寫入到系統的預寫式日志。是以,下列動作将産生錯誤消息:

資料操縱語言(dml) - insert、 update、delete、copy from、 truncate。注意不允許在恢複期間導緻一個觸發器被執行的動作。這個限制甚至被應用到臨時表,因為不配置設定事務 id 表行就不能被讀或寫,而目前不可能在一個熱備環境中配置設定事務 id。

資料定義語言(ddl) - create、 drop、alter、comment。這個限制甚至被應用到臨時表,因為執行這些操作會要求更新系統目錄表。

select ... for share | update,因為不更新底層資料檔案就無法取得行鎖。

select語句上的能産生 dml 指令的規則。

顯式請求一個高于row exclusive mode的模式的lock。

預設短形式的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、unlisten、notify

在正常操作中,"隻讀"事務被允許更新序列并且使用listen、unlisten和notify,是以熱備會話在比普通隻讀會話更緊一點的限制下操作。這些限制中的某些可能會在一個未來的發行中被放松。

在熱備期間,參數transaction_read_only總是為真并且不可以被改變。但是隻要不嘗試修改資料庫,熱備期間的連接配接工作起來更像其他資料庫連接配接。如果發生故障轉移或切換,該資料庫将切換到正常處理模式。當伺服器改變模式時會話将保持連接配接。一旦熱備結束,它将可以發起讀寫事務(即使是一個在熱備期間啟動的會話)。

使用者将可以通過發出show transaction_read_only來了解他們的會話是不是隻讀的。此外,一組函數(table 9-79)允許使用者通路關于後備伺服器的資訊。這些允許你編寫關心資料庫目前狀态的程式。這些可以被用來監控恢複的進度,或者允許你編寫恢複資料庫到特定狀态的複雜程式。

5.2. 處理查詢沖突

主伺服器和後備伺服器在多方面都松散地連接配接在一起。主伺服器上的動作将在後備伺服器上産生效果。結果是在它們之間有潛在的負作用或沖突。最容易了解的沖突是性能:如果在主伺服器上發生一次大資料量的載入,那麼着将在後備伺服器上産生一個相似的 wal 記錄流,因而後備伺服器查詢可能要競争系統資源(例如 i/o)。

随着熱備發生的還可能有其他類型的沖突。對于可能需要被取消的查詢和(某些情況中)解決它們的已斷開會話來說,這些沖突是硬沖突。使用者可以用幾種方式來處理這種沖突。沖突情況包括:

在主伺服器上取得了通路排他鎖(包括顯式lock指令和多種ddl動作)與後備查詢中的表通路沖突。

在主伺服器上删除一個表空間與使用該表空間存儲臨時工作檔案的後備查詢沖突。

在主伺服器上删除一個資料庫與在後備伺服器上連接配接到該資料庫的會話沖突。

從 wal 清除記錄的應用與快照仍能"看見"任意要被移除的行的後備事務沖突。

從 wal 清除記錄的應用與在後備伺服器上通路該目标頁的查詢沖突,不管要被移除的資料是否為可見。

在主伺服器上,這些情況僅僅會導緻等待;并且使用者可以選擇取消這些沖突動作中間的一個。但是,在後備伺服器上則沒有選擇:已被 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 規則的正确的資料可見性。不過,這個規則隻能被應用于執行在主要機上的事務。是以有可能主要機上的清除會移除對一個後備伺服器事務還可見的行版本。

有經驗的使用者應當注意行版本清除和行版本當機都可能與後備查詢沖突。即便在一個沒有被更新或被删除行的表上運作一次手工vacuum freeze也可能導緻沖突。

使用者應當清楚,主伺服器上被正常和重度更新的表将快速地導緻後備伺服器上長時間運作的查詢被取消。在這樣的情況下,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 項導緻的快速取消。

另一個選項是增加主伺服器上的vacuum_defer_cleanup_age,這樣死亡行不會像平常那麼快地被清理。這将允許在後備伺服器上的查詢能在被取消前有更多時間執行,并且不需要設定一個很高的max_standby_streaming_delay。但是,這種方法很難保證任何指定的執行時間視窗,因為vacuum_defer_cleanup_age是用主伺服器上被執行的事務數來衡量的。

查詢取消的數量和原因可以使用後備伺服器上的pg_stat_database_conflicts系統視圖檢視。pg_stat_database系統視圖也包含彙總資訊。

5.3. 管理者概覽

如果hot_standby在postgresql.conf中被設定為on并且存在一個recovery.conf檔案,伺服器将運作在熱備模式。但是,可能需要一些時間來允許熱備連接配接,因為在伺服器完成足夠的恢複來為查詢提供一個一緻的狀态之前,它将不會接受連接配接。在此期間,嘗試連接配接的用戶端将被一個錯誤消息拒絕。要确認伺服器已經可連接配接,要麼循環地從應用嘗試連接配接,要麼在伺服器日志中查找這些消息:

在主伺服器上,一旦建立一個檢查點,一緻性資訊就被記錄下來。當讀取在特定時段(當在主伺服器上wal_level沒有被設定為replica或者logical的期間)産生的 wal 時無法啟用熱備。在同時存在這些條件時,到達一個一緻狀态也會被延遲:

一個寫事務有超過 64 個子事務

生存時間非常長的寫事務

如果你正在運作基于檔案的日志傳送(“溫備”),你可能需要等到下一個 wal 檔案到達,這可能和主伺服器上的archive_timeout設定一樣長。

如果後備伺服器上某些參數在主伺服器上已經被改變,它們的設定将需要重新配置。對這些參數,在後備伺服器上的值必須等于或者大于主伺服器上的值。如果這些參數沒有被設定得足夠高,後備伺服器将拒絕開始。較高的值被提供之後,伺服器重新啟動再次開始恢複。這些參數是:

max_connections

max_prepared_transactions

max_locks_per_transaction

max_worker_processes

管理者為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()将在使用者後端上工作,而不是執行恢複的 startup 程序。pg_stat_activity不會為 startup 程序顯示一個項,也不會把恢複事務顯示為活動。結果是在恢複期間pg_prepared_xacts總是為空。如果你希望解決不能确定的預備事務,檢視主伺服器上的pg_prepared_xacts并且發出指令來确定那裡的事務。

和平常一樣,pg_locks将顯示被後端持有的鎖。pg_locks也會顯示一個由 startup 程序管理的虛拟事務,它擁有被恢複重播的事務所持有的所有accessexclusivelocks。注意 startup 程序不請求鎖來做資料庫更改,并且是以對于 startup 程序除accessexclusivelocks之外的鎖不顯示在pg_locks中,它們僅被假定存在。

nagios的插件check_pgsql将可以工作,因為它檢查的簡單資訊是存在的。check_postgres監控腳本也将能工作,盡管某些被報告的值可能給出不同或者混亂的結果。例如,上一次清理時間将不會被維護,因為在後備伺服器上不會發生清理。在主伺服器上運作的清理仍會把它們的改變發送給後備伺服器。

wal 檔案控制指令在恢複期間将不會工作,如pg_start_backup、pg_switch_xlog等。

可動态載入的子產品可以工作,包括pg_stat_statements。

咨詢鎖在恢複期間工作正常,包括死鎖檢測。注意咨詢鎖從來都不會被 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不會使後備伺服器上的使用者斷開。

在恢複期間統計收集器是活動的。所有掃描、讀、阻塞、索引使用等将在後備伺服器上被正常的記錄。被重播的動作将不會重複它們在主伺服器上的效果,是以重播一個插入将不會導緻pg_stat_user_tables的 inserts 列上的遞增。在恢複的開始 stats 檔案會被删除,是以來自主伺服器和後備伺服器的 stats 将不同;這被認為是一種特性而不是缺陷。

在恢複期間自動清理不是活動的。它将在恢複末尾正常啟動。

背景寫入器在恢複期間是活動的并且将執行檢查點(與主伺服器上的檢查點相似)以及正常的塊清潔活動。這可以包括存儲在後備伺服器上的提示位資訊的更新。在恢複期間,checkpoint指令會被接受,然而它會執行一個重新開機點而不是一個新的檢查點。

5.4. 熱備參數參考

在主伺服器上,可以使用參數wal_level和vacuum_defer_cleanup_age。在主伺服器上設定max_standby_archive_delay和max_standby_streaming_delay不會産生效果。

在主伺服器上,可以使用參數hot_standby、max_standby_archive_delay和max_standby_streaming_delay。隻要伺服器保持在後備模式vacuum_defer_cleanup_age就沒有效果,然而當後備伺服器變成主伺服器時它将變得相關。

5.5. 警告

熱備有一些限制。這些限制很可能在未來的發行中被修複:

哈希索引上的操作目前是不被 wal 記錄的,是以重播将不會更新這些索引。

在能夠取得快照之前,需要正在運作的事務的完整知識。使用大量子事務(目前指超過 64 個)的事務将延遲隻讀連接配接的啟動,直到最長的運作着的寫事務完成。如果發生這種情況,說明消息将被發送到伺服器日志。

主伺服器上的每一個檢查點将産生用于後備查詢的可用啟動點。如果後備伺服器在主要機處于關閉狀态時被關閉,就沒有辦法在主伺服器啟動之前重新進入熱後備,是以它在 wal 日志中産生一個進一步啟動點。這種情況在它可能發生的大部分常見情況中不是一個問題。通常,如果主伺服器被關閉并且不再可用,這可能是由于某種嚴重錯誤要求後備伺服器被轉變成為一個新的主伺服器來操作。并且在主伺服器被故意關閉的情況下,協調保證後備伺服器平滑地過渡為新的主伺服器也是一種标準過程。

在恢複尾聲,由預備事務持有的accessexclusivelocks将要求兩倍的正常鎖表項。如果你計劃運作大量并發的通常要求accessexclusivelocks的預備事務,或者你計劃運作一個需要很多accessexclusivelocks的大型事務,我們建議你為max_locks_per_transaction選擇一個更大的值,也許是主伺服器上該參數值的兩倍。如果你的max_prepared_transactions設定為 0,你根本不需要考慮這個問題。

可序列化事務隔離級别目前在熱備中不可用。嘗試在熱備模式中将一個事務設定為可序列化隔離級别将産生一個錯誤。