PostgreSQL 雙節點流複製如何同時保證可用性、可靠性(rpo,rto) - (半同步,自動降級方法實踐)
作者
digoal
日期
2019-01-27
標籤
PostgreSQL , 同步 , 半同步 , 流複製
背景
兩節點HA架構,如何做到跨機房RPO=0(可靠性維度)?同時RTO可控(可用性維度)?
半同步是一個不錯的選擇。
1、當只掛掉一個節點時,可以保證RPO=0。如下:
主 -> 從(掛)
主(掛) -> 從
2、當一個節點掛掉後,在另一個節點恢復並開啟同步模式前,如果在此期間(當前)主節點也掛掉,(雖然此時從庫活了(但由於還未開啟同步模式)),則RPO>0。 如下:
主(掛) -> 從(OPEN,但是之前從掛過,並且還還未轉換為同步模式)
與兩個節點同時掛掉一樣,RPO>0
3、如何保證RTO時間可控?
我們知道,在同步模式下,事務提交時需要等待sync STANDBY的WAL複製反饋,確保事務wal落多個副本再反饋客戶端(從動作上來說,先持久化主,然後同步給sync從,並等待sync從的WAL 同步位點的反饋),當STANDBY掛掉時,等待是無限期的,所以兩節點的同步複製,無法兼顧可用性(RTO)。那麼怎麼兼顧可用性呢?
可以對(pg_stat_activity)等待事件的狀態進行監測,如果發現同步事務等待超過一定閾值(RTO閾值),則降級為異步模式。
降級不需要重啟數據庫。
3.1 改配置
3.2 reload (對已有連接和新建連接都會立即生效)。
3.3 cancel 等待信號(針對當前處於等待中的進程)。
4、降級後,什麼情況下恢復為同步模式?(升級)
同樣可以對(pg_stat_replication)狀態進行監測,當sync standby處於streaming狀態時,則可以轉換為同步模式。
升級不需要重啟數據庫。
4.1 改配置
4.2 reload。立即生效 (對已有連接和新建連接都會立即生效)。
涉及技術點
1、事務提交參數
synchronous_commit
on, remote_apply, remote_write, local
2、同步配置參數
synchronous_standby_names
[FIRST] num_sync ( standby_name [, ...] )
ANY num_sync ( standby_name [, ...] )
standby_name [, ...]
ANY 3 (s1, s2, s3, s4)
FIRST 3 (s1, s2, s3, s4)
* 表示所有節點
3、活躍會話,查看事務提交時,等待事件狀態
pg_stat_activity
等待事件
https://www.postgresql.org/docs/11/monitoring-stats.html#MONITORING-STATS-VIEWS
wait_event='SyncRep'
4、流狀態,pg_stat_replication
sync_state='sync'
state
text
Current WAL sender state. Possible values are:
startup: This WAL sender is starting up.
catchup: This WAL sender's connected standby is catching up with the primary.
streaming: This WAL sender is streaming changes after its connected standby server has caught up with the primary.
backup: This WAL sender is sending a backup.
stopping: This WAL sender is stopping.
實踐
環境
1、主
postgresql.conf
synchronous_commit = remote_write
wal_level = replica
max_wal_senders = 8
synchronous_standby_names = '*'
2、從
recovery.conf
restore_command = 'cp /data01/digoal/wal/%f %p'
primary_conninfo = 'host=localhost port=8001 user=postgres'
同步降級、升級 - 實踐
關閉standby,模擬備庫異常。看如何實現半同步。
模擬STANDBY恢復,看如何模擬升級為同步模式。
1、監測 pg_stat_activity,如果發現事務提交等待超過一定閾值(RTO保障),降級
select max(now()-query_start) from pg_stat_activity where wait_event='SyncRep';
2、查看以上結果等待時間(RTO保障)
當大於某個閾值時,開始降級。
注意NULL保護,NULL表示沒有事務處於 SyncRep 等待狀態。
3、降級步驟1,修改synchronous_commit參數。改成WAL本地持久化(異步流複製)。
alter system set synchronous_commit=local;
4、降級步驟2,生效參數,RELOAD
select pg_reload_conf();
5、降級步驟3,清空當前等待隊列(處於SyncRep等待狀態的進程在收到CANCEL信號後,從隊列清空,並提示客戶端,當前事務本地WAL已持久化,事務正常結束。)
select pg_cancel_backend(pid) from pg_stat_activity where wait_event='SyncRep';
6、收到清空信號的客戶端返回正常(客戶端可以看到事務正常提交)
postgres=# end;
WARNING: 01000: canceling wait for synchronous replication due to user request
DETAIL: The transaction has already committed locally, but might not have been replicated to the standby.
LOCATION: SyncRepWaitForLSN, syncrep.c:264
COMMIT
事務的redo信息已在本地WAL持久化,提交狀態正常。
當前會話後續的請求會變成異步流複製模式(WAL本地持久化模式(synchronous_commit=local))。
如何升級?:
7、升級步驟1,監測standby狀態,sync_state='sync'狀態的standby進入streaming狀態後,表示該standby與primary的wal已完全同步。
select * from pg_stat_replication where sync_state='sync' and state='streaming';
有結果返回,表示standby已經接收完primary的wal,可以進入同步模式。
8、升級步驟2,將事務提交模式改回同步模式( synchronous_commit=remote_write ,事務提交時,等sync standby接收到wal,並write。)
alter system set synchronous_commit=remote_write;
9、升級步驟3,生效參數,RELOAD (所有會話重置synchronous_commit=remote_write,包括已有連接,新建的連接)
select pg_reload_conf();
小結
1、在不修改PG內核的情況下,通過外部輔助監測和操縱(例如5秒監控間隔)),實現了兩節點的半同步模式,在雙節點或單節點正常的情況下,保證RPO=0,同時RTO可控(例如最長wait_event='SyncRep'等待時間超過10秒)。
2、內核修改建議,
降級:可以在等待隊列中加HOOK,wait_event='SyncRep'等待超時後降級為異步。
升級:在wal_sender代碼中加hook,監測到standby恢復後,改回同步模式。
參考
《PostgreSQL 一主多從(多副本,強同步)簡明手冊 - 配置、壓測、監控、切換、防腦裂、修復、0丟失 - 珍藏級》
https://www.postgresql.org/docs/11/monitoring-stats.html#MONITORING-STATS-VIEWS