說明: 下文的部分內容節選自《PostgreSQL實戰》
PG的延遲複製
參數: recovery_min_apply_delay
某些情況下,一個後備服務器會盡快恢復來自於主服務器的 WAL 記錄。有一份數據的延時拷貝是有用的,它能提供機會糾正數據丟失錯誤。這個參數允許你將恢復延遲一段固定的時間,如果沒有指定單位則以毫秒爲單位。例如,如果你設置這個參數爲5min,對於一個事務提交,只有當後備機上的系統時鐘超過主服務器報告的提交時間至少 5分鐘時,後備機纔會重放該事務。
有可能服務器之間的複製延遲會超過這個參數的值,在這種情況下則不會增加延遲。注意延遲是根據主服務器上寫 WAL 的時間戳以及後備機上的當前時間來計算。由於網絡延遲或者級聯複製配置導致的傳輸延遲可能會顯著地減少實際等待時間。如果主服務器和後備機上的系統時鐘不同步,這會導致恢復比預期的更早應用記錄。但這不是一個主要問題,因爲這個參數有用的設置比服務器之間的典型事件偏差要大得多。
只有在事務提交的 WAL 記錄上纔會發生延遲。其他記錄還是會被儘可能快地重放,這不會成爲問題,因爲 MVCC 可見性規則確保了在對應的提交記錄被應用之前它們的效果不會被看到。
一旦恢復中的數據庫已經達到一致狀態,延遲就會產生,直到後備機被提升或者觸發。在那之後,後備機將會結束恢復並且不再等待。
這個參數的目的是和流複製部署一起使用,但是,如果指定了該參數,所有的情況下都會遵守它。使用這個特性也會讓hot_standby_feedback被延遲,這可能導致主服務器的膨脹,兩者一起使用時要小心。
延遲備庫的搭建很簡單, 只要在 recovery.conf 裏面增加個配置項即可
recovery_min_apply_delay = 1min # 這裏我測試就設置1分鐘的延遲
## 默認的支持時間單位爲 ms 、s、min、h、d 即 毫秒 秒 分鐘 小時 天
注意:修改後,需要重啓 standby節點才能生效。
然後,在主庫創建表並插入一條測試數據:
postgres=# create table test_delay(id int4,create_time timestamp(0) without time zone);
postgres=# insert into test_delay (id,create_time) values (1,now());
然後,等一分鐘左右到延遲standby節點去查看下數據是否同步過去
延遲複製場景下 recovery_min_apply_delay 參數對同步複製的影響
同步複製情況下, 通常要 synchronous_commit 配置爲 on 或 remote_apply
on 表示 standby將wal接收到 --> 寫入wal日誌文件 --> 向客戶端返回成功。
standby表示 standby將wal接收到 --> 寫入wal日誌文件 --> 並應用到standby --> 纔會向客戶端返回成功。
下面對 synchronous_commit 不同參數下,並且設置了延遲複製的測試:
場景1: synchronous_commit=on 並且 recovery_min_apply_delay = 1min
注意:
synchronous_commit是設置在主庫的postgresql.conf中的(支持會話級別設置,也可以修改配置文件reload後全局生效)。
recovery_min_apply_delay 是設置在standby的recovery.conf中的。
這種場景下, 我們在主庫上插入一條數據,主庫會立即返回執行成功or失敗的結果。 然後我們到延遲複製的standby去查詢,發現還是會需要1min後才能查到這條數據。
也就是說, 延遲備庫場景下, synchronous_commit 配置爲on時 和 異步流複製是一致的。
場景2: synchronous_commit=remote_apply 並且 recovery_min_apply_delay = 1min
注意:
synchronous_commit是設置在主庫的postgresql.conf中的(支持會話級別設置,也可以修改配置文件reload後全局生效)。
recovery_min_apply_delay 是設置在standby的recovery.conf中的。
這種場景下, 我們在主庫上插入一條數據,主庫會hang住等待1min(等待從庫完成apply操作)後,然後才能返回執行成功or失敗的結果。
然後我們到延遲複製的standby去查詢,發現立即就能查到這條數據。
也就是說, 延遲備庫場景下, synchronous_commit 配置爲 remote_apply時,會造成主庫上面的事務的提交的阻塞。
生產環境用到延遲從庫的場景下,一定要避免設置 synchronous_commit=remote_apply (當然從性能角度考慮也很少會設置爲remote_apply的)