天天看點

PostgreSQL standby recover的源碼分析 (walreceiver喚醒時機? 為什麼standby crash後walreceiver不會立即被喚醒?)

postgresql , 流複制 , stream replication , wal receiver , 喚醒時機 , 狀态機

前段時間有位網友提的問題,

當postgresql資料庫的standby節點crash後再啟動,發現standby節點的wal receiver程序很久才啟動并開始從主節點接收wal。

這段時間是在等待standby節點恢複pg_xlog目錄中已有的xlog日志。

PostgreSQL standby recover的源碼分析 (walreceiver喚醒時機? 為什麼standby crash後walreceiver不會立即被喚醒?)

這是為什麼呢?

postgresql在crash後,需要從最近的一個檢查點開始恢複,因為在每次檢查點(如果是standby可能稱為restart ckpt)開始後,發生變更的塊都會記錄對應的full page到wal日志檔案中,從檢查點恢複,可以保證不會因為作業系統的partial write 導緻資料塊的不一緻。

PostgreSQL standby recover的源碼分析 (walreceiver喚醒時機? 為什麼standby crash後walreceiver不會立即被喚醒?)

對于standby節點也是一樣的,啟動時,從最近的一次檢查點開始恢複,它可以選擇ckpt或者restart ckpt開始恢複,選最近的即可。

在standby上也可以建立檢查點(稱為restart ckpt),後面會講到。

這裡隻解釋了一個問題,就是資料庫crash後從哪裡開始恢複,還有一個問題沒搞明白?

為什麼wal receiver程序很久才啟動并開始從主節點接收wal?

得先講講資料庫有幾種恢複來源:

3種恢複來源,

然後我們再分析一下,它如何選擇恢複來源的?

1. 首先會找pg_xlog目錄有沒有需要的日志(包括tli),如果有,會從日志目錄中直接讀取pg_xlog進行恢複,直到pg_xlog目錄中沒有需要的檔案,則會将source置為下一個可用的source。

2. 當source=stream時,并且wal receiver程序沒有啟動時,發信号啟動它。

3. 如果stream失敗,會重新掃描tli,然後等待wal_retrieve_retry_interval這個時間間隔,

循環往複。

PostgreSQL standby recover的源碼分析 (walreceiver喚醒時機? 為什麼standby crash後walreceiver不會立即被喚醒?)

代碼詳見

整理一下啟動wal receiver的流程如下

PostgreSQL standby recover的源碼分析 (walreceiver喚醒時機? 為什麼standby crash後walreceiver不會立即被喚醒?)

相關代碼

src/include/storage/pmsignal.h

src/backend/postmaster/postmaster.c

src/backend/replication/walreceiverfuncs.c

src/backend/access/transam/xlog.c

standby建立的檢查點稱為restart ckpt, 目的是防止正常的停止standby後,還要從正常的檢查點位置開始恢複。

建立了restart ckpt後,standby重新開機時,從restart ckpt開始恢複即可。

PostgreSQL standby recover的源碼分析 (walreceiver喚醒時機? 為什麼standby crash後walreceiver不會立即被喚醒?)

src/backend/postmaster/checkpointer.c

了解了原理,我們來想想現在的機制會存在什麼問題。

1. 如果備庫恢複速度較主慢,接收到的1024mb日志,隻恢複到了512mb,然後wal receiver程序突然挂了。

此時,standby會将恢複source切到pg_xlog或resotre_command,由于pg_xlog裡面還有512mb沒有恢複,那麼會等這512mb恢複完後,才會發生source的切換,再次喚醒wal receiver。

2. standby crash,沒有産生shutdown restart ckpt.

crash後重新開機,需要從最近的restart ckpt或者ckpt進行恢複,如果這之間有許多pg_xlog,那麼也需要恢複一段時間,進而wal receiver的喚醒時間也會被拖長。

帶來的問題就是:主庫和備庫的sender wal位點差異會受到一定的影響。如果正好此時主庫挂了,缺失的日志可能會比較多。

1. 備庫在接收xlog時,記錄xlog接收到的位點資訊,進而xlog不需要等apply位點來擷取狀态。

2. 并行接收,不要等apply請求喚醒wal receiver,使用獨立的程序receive。

但是可能引入另一個問題,比如備庫就是apply較慢,導緻沒有apply的xlog堆積在備庫的pg_xlog目錄。

3. 并行恢複,由于postgresql是實體的備庫,效率已經很高了,通常不需要并行恢複,首先要考慮的是備庫的iops能力。