七八年前,老馮手里維護著一百套大規模 PostgreSQL 集群,兩百多臺頂配物理機,開始做高可用方案選型。 那段時間我把市面上能叫得出名字的方案都翻了一遍:Patroni、Corosync + Pacemaker、repmgr、Stolon、pgpool-II……
最后選了 Patroni。基于它做 HA,上線后效果很穩:這些年碰到幾十次真實硬件故障,RTO 基本都在二三十秒區間。 最爽的是:。
回頭看,這個選擇屬于 “少走七年彎路”。今天無論你看傳統 Linux 發行版方案(Percona、AutoBase 等), 還是 K8S Operator(Crunchy PGO 等),主流 PG 發行版高可用幾乎都繞不開 Patroni。 Patroni 在 GitHub 上的 Star (8.1K) 也超過其他這些 HA 組件的總和。
那么,為什么是 Patroni 成為了事實標準?它到底好在哪里? PostgreSQL 高可用到底應該怎么做?今天我們就來聊聊這個話題。
可用性,RTO與RPO
可用性 (Availability)是一個服務指標,一般用 “服務可用時間/總時間窗口” 的百分比來計算,時間窗口一般是整年或者整月。 通常 99.99% 以上的可用性(4個9)被稱作高可用 —— 意味著年度故障預算 52 分鐘,或月度故障預算 4.3 分鐘。
但可用性是業務連續性指標,不是數據庫的 技術能力。一個經典誤區是:你完全可以單憑運氣做到 100% 的可用性,這很常見。 云廠商承諾幾個9的SLA,本質上也不是歷史戰績,而是代金券對賭協議。
真正重要的是,發生故障的頻率與恢復時間。對于數據庫來說,你控制不了故障發生的頻率(MTBF); 但你能控制的是:發生故障后最多丟多少數據,以及要多長時間恢復。這就是兩個核心可靠性指標 —— RPO 與 RTO:
RPO(Recovery Point Objective,恢復點目標) : 定義了在主庫發生故障時,允許丟失的最大數據量。
RTO(Recovery Time Objective,恢復時間目標) : 定義了在主庫發生故障時,系統恢復寫入能力所需的最長時間。
RTO 和 RPO 代表了真正 抗事的能力,也是我們考察高可用方案的關鍵所在。
那么 RPO / RTO 要多好才算好?這里有幾個相關的國際/國家標準,規定了各個行業要求的 RPO / RTO 水平。 比如 SHARE-78,GB/T 20988-2025,SOX / HIPPA / Basel III 都對 RTO/RPO 提出了合規要求。 于今年元旦開始實行的國內的 《網絡安全技術 信息系統災難恢復規范》將災難恢復劃分為六個等級:
![]()
![]()
最高等級的容災要求,通常要求 RTO 在分鐘級(幾十秒的量級),RPO = 0 不丟失數據。 十幾年前,你可能要花幾百萬上千萬采購專有軟硬件來滿足這樣的要求。 而在 2026 年的當下,有了 Patroni + PostgreSQL,實現這種容災水平的軟件成本已經無限接近于零。
但顯然,因為信息不對稱,很多人并不知道這件事。所以今天我就來給大家講講 PostgreSQL 高可用的 SOTA 事實標準 —— Patroni。
太長不看
Patroni 在合理配置的情況下,可以輕松做到 RTO < 30s,RPO = 0 的水平,這是經過理論推演與實戰檢驗的結果。 在 RPO 上,Patroni 可以實現 Oracle 最大性能/最大可用/最大保護模式,甚至提供了比 Oracle 最大保護模式更強的數據一致性選項。 在 RTO 上,Patroni 可以在常規硬件上實現端到端 RTO < 30s 的水平,包含從故障檢測,主從切換,到負載均衡器健康檢查的全鏈路耗時。 接下來,我們將詳細介紹高可用中 RPO 與 RTO 的利弊權衡。
RPO 利弊權衡
RPO 定義了主庫故障時允許丟失的最大數據量。對于金融交易這類數據完整性至關重要的場景,通常要求 RPO = 0,即不允許任何數據丟失。
然而更嚴格的 RPO 指標是有代價的:它會引入更高的寫入延遲,降低系統吞吐量,并且存在從庫故障導致主庫不可用的風險。 因此對于常規場景,通常可以接受一定量的數據丟失(例如不超過 1MB),以換取更高的可用性與性能。
在異步復制場景下,從庫和主庫之間會存在一定的復制延遲(取決于網絡和吞吐量,正常在 10KB~100KB / 100μs~10ms 的數量級)。 這意味著主庫故障時,從庫可能還沒有完全同步最新數據。此時如果發生故障切換,新主庫可能會丟失一些尚未復制的數據。
![]()
實現原理
Patroni 提供了一個參數 maximum_lag_on_failover,用于控制潛在數據丟失量的上限,默認為 1048576 (1MB)。 這意味著自動故障轉移時,最多可以容忍 1MB 的數據丟失。當主庫宕機時,如果有任何一個從庫的復制延遲在這個值以內,Patroni 將自動提升該從庫為新主庫。
然而當所有從庫的復制延遲都超出這個閾值時,Patroni 將拒絕進行自動故障切換以避免數據丟失。 此時需要人工介入決策:等待主庫恢復(可能永遠不會恢復),還是接受數據損失并強制提升一個從庫。
這就引入了第一項利弊權衡:你需要根據業務需求配置這個值,在 可用性 和 一致性 之間進行 利弊權衡。 增大這個值可以提高自動故障切換的成功率(降低不可用時長),但也會增加潛在的數據丟失量上限。
在不允許任何數據丟失的場景下,你可以使用 Patroni 的同步模式與嚴格同步模式,來確保 RPO = 0。
Oracle 類比
對于熟悉 Oracle 的用戶來說,Patroni 的復制模式可以類比 Oracle Data Guard 提供的三種數據保護模式:最大性能、最大可用、最大保護。
![]()
實際上,通過配置 Patroni 和 PostgreSQL,你甚至可以實現比 Oracle 最大保護模式更強的數據一致性選項。 例如 Oracle Data Guard 的最大保護模式只要求一個同步從庫確認寫入,而 Patroni 可以配置多個同步從庫確認寫入, 甚至確認重放完成(remote_apply),來進一步提高數據持久性與一致性。
![]()
JEPSEN 提供了一個非常罕見的例子,我們會有一篇專門的文章詳細介紹。
對于絕大多數業務來說,異步復制(最大性能)模式提供的 RPO 保證已經足夠。 對于對數據完整性要求極高的場景,可以使用最大可用 / 最大保護模式來確保 RPO = 0。
RTO 利弊權衡
RTO 定義了主庫故障時,系統恢復寫入能力所需的最長時間。
當主庫故障時,整個恢復流程涉及多個階段:檢測故障、DCS 鎖過期、新主選舉、執行 promote、負載均衡器感知新主庫。因此不同于 RPO,RTO 不可能等于零。
而且需要注意,RTO 并非越小越好。更短的 RTO 意味著縮短各階段的超時時間,這會使集群對網絡抖動更加敏感,從而增加誤切風險。 RTO 設置的太小,切換耗時雖然變短,但是誤切概率上升了,切換頻率增加,整體可用性反而下降了。
這就引出了第二項利弊權衡,你需要根據實際網絡條件選擇合適的配置,在 恢復耗時 與 誤切概率 之間取得平衡: 網絡質量越差,越應該選擇保守的配置;網絡質量越好,越可以選擇激進的配置。
關于 RTO 的營銷話術
因為 RPO 這個指標沒什么好吹的,RTO 已經淪為數據庫營銷吹牛的重災區。有時候是拿特例場景樂觀路徑來以點蓋面,或者在驅動 / 連接池層面排隊并用統計口徑做文章。因此討論 RTO 的時候,需要明確幾個因素:
故障域 :是計算節點故障,還是存儲故障、網絡故障?
測量口徑 :可用標準是數據庫可寫入,還是 LB,APP,連接池/驅動層可用?
統計量 :使用的是最優值、最差值,還是平均值與中位數?
網絡條件 :是同機柜、同機房、同城,還是跨大洲的全球復制?
通常來說,在同機柜網絡條件中,常見故障路徑下,RTO < 30s 算是業界頂級水平。 如果有人不帶場景、故障域、統計口徑說自己 RTO < 10 秒,通常可以判定為吹牛。
嚴肅的 RTO 的討論非常復雜,在下面,我們會討論四種典型網絡條件下的參數配置,兩種主要故障路徑下的 RTO 拆解,以及最優,平均,最劣三種情況; 并使用更為嚴格的 HAPRXOY 端側接受連接寫入作為 RTO 的測量口徑,如果沒有特別解釋,我們討論的是用于兜底的 最劣 情況,而非平均或最優情況。
架構原理
RTO 無法脫離架構,場景,環境,資源來討論,因此我們需要先來介紹一下基于 Patroni / Etcd / HAProxy 的經典高可用架構,在這個架構中:
![]()
?PostgreSQL 使?標準流復制搭建物理從庫,主庫故障時由從庫接管。?Patroni 負責管理 PostgreSQL 服務器進程,處理高可用相關事宜。?Etcd 提供分布式配置存儲(DCS)能力,并用于故障后的領導者選舉?Patroni 依賴 Etcd 達成集群領導者共識,并對外提供健康檢查接口。?HAProxy 對外暴露集群服務,并利? Patroni 健康檢查接口,自動分發流量至健康節點。
在這套架構中,高可用 RTO 主要取決于 Patroni 參數,次要取決于 Haproxy 參數。
參數配置
Patroni 中關于 RPO 的核心參數只有三個,但考慮 RTO 時,總共要納入的參數有 10 個: Patroni 5 個,HAProxy 健康檢查 5 個。這十個參數的組合決定了 RTO 的表現。
請注意,默認參數的表現并不是最優的。我在長期實踐中提出了四組不同網絡條件下的參數優化配置:fast、normal、slow、safe。
![]()
四種模式實際上對應著四組不同的參數配置,如下所示:
![]()
這四種模式下,RTO 的最壞,最好,平均表現水平如下圖所示。
![]()
我們以最壞口徑作為討論的基準, 在默認配置下 RTO < 45s,最優模式下 RTO < 30s。 更寬容的模式則設置有 90s / 150s 的 RTO 上線目標。
這里特別需要提到的是,市面上絕大多熟 PG 高可用方案幾乎都沒有修改 Patroni 默認參數, 盡管默認參數在常規被動故障切換中提供 RTO < 45 秒的表現,但默認 primary_start_timeout 的 300 秒配置, 會導致 PG 主庫崩潰重新拉起這個故障場景中,最劣表現高達 324 秒,違背常規的 RTO 目標。
如果你自己手搓 Patroni 高可用,這一點務必注意。
故障路徑
那么這個圖里的數據是怎么計算得到的呢?這里我們就要討論 故障路徑 了。
在 Patroni 這套高可用架構中,有 10 種典型故障:節點宕機 / 假活、PG 崩潰 / 拒絕連接 / 假活、Patroni 崩潰 / 假活、主庫 / DCS 網絡中斷、存儲故障等等。 這些故障總體可以劃分為五條 RTO 拆解路徑,在討論最壞情況時,歸并到兩條典型的故障路徑:
被動檢測 : Patroni 掛了或者網絡隔離,主庫無法續租,觸發集群選舉
主動檢測 : Patroni 活著,嘗試修復 PG 掛了這種問題,超時后觸發集群選舉
這兩種故障路徑殊途同歸,可以用下面的流程圖表示:
![]()
這兩條故障路徑的 RTO 計算方式有差異,下面會簡要介紹,詳細完整的分析報告請參閱下面的文檔: http://pigsty.cc/docs/concept/ha/failure/[1]
![]()
![]()
這里的 RTO 時序拆解,給出了 RTO 的下界和上界。 我們在設定的時候,以上界最悲觀的情況設置,確保滿足最嚴格的容災等級要求。
考慮 平均 情況的話 fast 檔位在 23-24 秒,默認 norm 檔位在 34-35 秒的水平。
![]()
![]()
關于 RAC 與分布式數據庫
有些數據庫承諾非常低的 RTO,甚至號稱秒級切換、RTO = 0。這些方案通常使用共享存儲 RAC 架構,或者分布式 Raft/Paxos 協議。 但仔細推敲就會發現,這些聲稱往往只針對特定故障域成立,而且會因為架構上的利弊權衡引入其他局限性。
以 Oracle RAC 為例,多個計算節點訪問同一個底層磁盤陣列。在實例故障時確實可以快速切換,但當底層存儲出現單點故障時,RTO 就直接炸了 —— 所有節點一起完蛋。 這本質上是把復雜度和風險下推到存儲層,逼著你購買價格高昂的企業級 SAN 存儲來兜底。 而且真要做跨區域容災,還是得靠 Data Guard 這類主從復制技術。然后 RTO 又回到幾十秒的量級了。 所以 Oracle RAC 的營銷宣傳在我看來極具誤導性。
一些 NewSQL 分布式數據庫稍微誠實一點。比如 CockroachDB 用 Raft 協議管理多節點集群,在主要故障場景下號稱 RPO = 0、RTO < 9s。 這個數字是可信的,但代價是什么?翻了幾倍的寫入延遲,幾分之一的性能吞吐,以及更高的架構/運維復雜度。 關于這一點,老馮在《》中詳細探討過(還有《DDIA 第六章:復制》)。 說到底一切都是利弊權衡,只要你不在乎代價,AWS 開源的 pgactive PG 擴展號稱能把 RTO 做到亞秒級。
相比之下,無共享架構(Shared Nothing)的思路就清爽得多:顯式管理多套存儲副本,每個節點都是自治的,沒有存儲單點。 共享存儲方案很難水平擴展,而無共享架構可以輕松拉出幾十個從庫 —— OpenAI 1 主 40 從 ,我們在探探1主32從的 PG 集群就是這么玩的。 這也是為什么過去二十年,無共享架構逐漸成為數據庫高可用的主流選擇。
老馮自己的看法是,這年頭鼓吹共享存儲高可用方案,有大概率是為了給硬件/云盤帶貨。 老馮對這種事向來不感冒,本文就進一步具體展開批判了。但后面也許會專門寫一篇,聊聊 RAC 與分布式數據庫的真實表現與實際代價, 順便講講 Corosync + Pacemaker 這種極其繁瑣的老古董 PG 高可用方案為什么該進博物館了。
關于實操
聊完原理,說說落地。我知道很多人看到這里會想:道理我都懂,但讓我自己一臺一臺去配 Etcd、Patroni、HAProxy,俺做不到啊。
放心,老馮自己也不會干這種傻事。
我把這套 PG 高可用方案做成了開源免費、一鍵部署的完整解決方案:Pigsty。
![]()
你也可以用別的 —— AutoBase,Percona,各種 K8S PG Operator 也大同小異。 反正高可用部分的核心架構基本都是一樣的 Patroni + etcd + Haproxy。
不過,很多用著 patroni 的方案幾乎都清一色用著默認參數。 看起來沒人認真優化過,也沒人做過精細的 RTO 時序分析,也許是放到“企業級”方案里去了吧。 而 Pigsty 在大規模生產環境中實戰打磨出來,針對不同網絡條件提供了多種 RTO/RPO 策略可選, 除此之外,還內置了連接池、自動故障切換、完整的監控告警體系 —— 開箱即用不操心。
另外提醒一句:光有高可用還不夠。硬件故障 Patroni 能扛,但誤刪數據、邏輯錯誤這類場景,還得靠 PITR 來兜底。 所以今天講的是 PostgreSQL 高可用的事實標準——Patroni,后面還會介紹備份恢復的事實標準 —— pgBackRest。
朋友們,別折騰手搓 PG 高可用了!土法自建對技術成長和業務發展都沒啥幫助 —— 把原理搞明白會用就行。 與其重復造輪子,不如折騰折騰怎么用好 PG 本身,這里能玩的擴展太多了,可比折騰什么 HA PITR 有意思多了。
小結
通過精細的參數調優,Patroni 的 RTO 上界可以被精確控制在不同檔位。 在常規網絡環境下,30 秒的 RTO 水平觸手可及。 這些年我在生產環境中經歷的幾十次真實故障切換,監控數據顯示 RTO 穩定在 20~30 秒,完全滿足最嚴苛的金融級容災要求。
七年前做這個選型時,Patroni 還是個小眾方案。當時不少人覺得它不夠"企業級",不如商業方案有保障。 現在再看,那些迷信復雜架構和昂貴軟件的團隊,要么還在為高可用焦頭爛額,要么早就悄悄換成了 Patroni。
技術選型這件事,從來不是看誰更復雜、誰更貴,而是看誰能真正把問題解決掉。 Patroni 用最簡潔的架構實現了最可靠的效果,這就是它成為事實標準的原因。
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.