Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

Patroni 的主要目標是為 PostgreSQL 提供高可用性。 但 Patroni 只是一個模板,而不是一個現成的工具(一般來說,在文檔中是這樣說的)。 乍一看,在測試實驗室中設置了 Patroni,您可以看到它是一個多麼棒的工具,以及它如何輕鬆地處理我們破壞集群的嘗試。 然而,在實踐中,在生產環境中,一切並不總是像在測試實驗室中那樣完美優雅地發生。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我會告訴你一些關於我自己的事。 我最初是一名系統管理員。 從事網絡開發工作。 自 2014 年以來,我一直在 Data Egret 工作。 該公司從事 Postgres 領域的諮詢。 而我們正是為 Postgres 服務的,我們每天都與 Postgres 打交道,所以我們在操作方面有不同的專業知識。

而在2018年底,我們開始慢慢使用Patroni。 並且積累了一些經驗。 我們以某種方式診斷它,調整它,得出我們的最​​佳實踐。 在這份報告中,我將談論它們。

除了 Postgres,我還喜歡 Linux。 我喜歡在裡面閒逛和探索,我喜歡收集核心。 我喜歡虛擬化、容器、docker、Kubernetes。 所有這些都讓我感興趣,因為舊的管理習慣正在影響。 我喜歡處理監控。 我喜歡 postgres 與管理相關的東西,即復制、備份。 在業餘時間,我用 Go 編寫。 我不是軟件工程師,我只是用 Go 為自己編寫代碼。 這讓我很高興。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

  • 我想你們中的許多人都知道 Postgres 沒有開箱即用的 HA(高可用性)。 要獲得 HA,您需要安裝一些東西,配置它,努力並獲得它。
  • 有幾種工具,Patroni 是其中之一,它非常酷地很好地解決了 HA。 但是通過將它全部放在測試實驗室並運行它,我們可以看到它一切正常,我們可以重現一些問題,看看 Patroni 如何為他們服務。 我們會看到一切都很好。
  • 但在實踐中,我們遇到了不同的問題。 我將談論這些問題。
  • 我會告訴你我們是如何診斷它的,我們做了什麼調整——它是否對我們有幫助。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

  • 我不會告訴你如何安裝 Patroni,因為你可以在互聯網上 google,你可以查看配置文件來了解它是如何啟動的,它是如何配置的。 您可以了解方案、體系結構,並在 Internet 上查找有關它的信息。
  • 別人的經歷我就不說了。 我只會談論我們面臨的問題。
  • 我不會談論 Patroni 和 PostgreSQL 之外的問題。 例如,如果有與平衡相關的問題,當我們的集群崩潰時,我不會談論它。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

在我們開始報告之前,還有一個小的免責聲明。

我們遇到的所有這些問題,都是在運營的前 6-7-8 個月內遇到的。 隨著時間的推移,我們得出了內部最佳實踐。 我們的問題消失了。 因此,這份報告大約是在六個月前發布的,當時我對它記憶猶新,並且記得很清楚。

在準備報告的過程中,我已經提出了舊的事後分析,查看了日誌。 而且在分析問題的過程中,可能會遺忘一些細節,或者有些細節沒有完全調查清楚,所以在某些時候看起來似乎沒有充分考慮到問題,或者缺少一些信息。 所以我現在請你原諒我。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

什麼是帕特羅尼?

  • 這是構建 HA 的模板。 這就是它在文檔中所說的。 在我看來,這是一個非常正確的澄清。 Patroni 並不是解決所有問題的靈丹妙藥,也就是說,您需要努力讓它發揮作用並帶來好處。
  • 這是安裝在每個數據庫服務上的代理服務,是 Postgres 的一種初始化系統。 它啟動 Postgres、停止、重新啟動、重新配置和更改集群的拓撲結構。
  • 因此,為了存儲集群的狀態,它的當前表示,就像它看起來的那樣,需要某種存儲。 而從這個角度來看,Patroni 走的是在外部系統中存儲狀態的路徑。 它是一個分佈式配置存儲系統。 它可以是 Etcd、Consul、ZooKeeper 或 kubernetes Etcd,即這些選項之一。
  • Patroni 的其中一個特點是您可以開箱即用自動歸檔器,只需對其進行設置即可。 如果我們拿 Repmgr 來比較,那麼 filer 就包含在那裡。 使用 Repmgr,我們可以進行切換,但如果我們想要自動文件管理器,則需要額外配置它。 Patroni 已經有一個開箱即用的自動歸檔器。
  • 還有很多其他的東西。 比如維護配置,倒新副本,備份等等。不過這個不在報告範圍內,我就不說了。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

一個小的結果是,Patroni 的主要任務是良好且可靠地執行自動歸檔,以便我們的集群保持運行並且應用程序不會注意到集群拓撲的變化。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

但是當我們開始使用 Patroni 時,我們的系統變得有點複雜。 如果早些時候我們有 Postgres,那麼當使用 Patroni 時,我們會得到 Patroni 本身,我們會得到存儲狀態的 DCS。 這一切都必須以某種方式起作用。 那麼會出什麼問題呢?

可能會中斷:

  • Postgres 可能會崩潰。 它可以是 master 也可以是 replica,其中一個可能會失敗。
  • Patroni 本身可能會破裂。
  • 存儲狀態的 DCS 可能會中斷。
  • 網絡可能會中斷。

我將在報告中考慮所有這些要點。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我會考慮案例,因為它們變得更加複雜,而不是從案例涉及許多組件的角度來看。 而且從主觀感受來看,這個case對我來說比較難,拆起來比較難……反之,有的case很輕,很容易拆。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

第一種情況是最簡單的。 當我們採用數據庫集群並將我們的 DCS 存儲部署在同一個集群上時就是這種情況。 這是最常見的錯誤。 這是構建體系結構的錯誤,即將不同的組件組合在一個地方。

於是,有一個立案人,我們去處理一下事情的經過。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

在這裡,我們對文件管理器發生的時間感興趣。 也就是說,我們對集群狀態發生變化的這個時刻感興趣。

但是歸檔器並不總是瞬時的,即它不佔用任何時間單位,它可以被延遲。 它可以持久。

因此,它有一個開始時間和一個結束時間,即它是一個連續的事件。 我們將所有事件分為三個時間段:我們有時間在申報者之前、申報者期間和申報者之後。 也就是說,我們考慮這個時間線中的所有事件。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

首先,當文件管理器發生時,我們會尋找發生的原因,導致文件管理器發生的原因。

如果我們查看日誌,它們將是經典的 Patroni 日誌。 他在他們裡面告訴我們,服務器變成了master,master的角色已經傳給了這個節點。 這裡突出顯示。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

接下來,我們需要了解 filer 發生的原因,即發生了什麼事件導致 master 角色從一個節點移動到另一個節點。 在這種情況下,一切都很簡單。 我們在與存儲系統交互時出錯。 大師意識到他無法與 DCS 一起工作,也就是說,交互存在某種問題。 他說他不能再當大師了,於是辭職了。 “貶身”這句台詞正是這麼說的。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

如果我們查看文件管理器之前的事件,我們可以在那裡看到導致嚮導繼續存在問題的原因。

如果我們查看 Patroni 日誌,我們會發現有很多錯誤、超時,即 Patroni 代理無法與 DCS 一起工作。 在這種情況下,這是在端口 8500 上通信的 Consul 代理。

而這裡的問題是 Patroni 和數據庫在同一台主機上運行。 Consul 服務器在同一節點上啟動。 通過在服務器上創建負載,我們也為 Consul 服務器創建了問題。 他們無法正常溝通。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

一段時間後,當負載消退時,我們的 Patroni 能夠再次與代理通信。 恢復正常工作。 並且同一台 Pgdb-2 服務器再次成為主服務器。 也就是說,有一個小的翻轉,由於這個節點放棄了主人的權力,然後又接管了他們,也就是說,一切都恢復原狀。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

而這也算是虛驚一場,或者也算是帕特羅尼做對了。 也就是他意識到自己無法維護集群的狀態而取消了他的權限。

由於 Consul 服務器與基地在同一硬件上,因此出現了問題。 相應地,任何負載:無論是磁盤負載還是處理器負載,都會影響與Consul集群的交互。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

而且我們決定它不應該住在一起,我們為 Consul 分配了一個單獨的集群。 而且 Patroni 已經在使用一個單獨的 Consul,也就是說,有一個單獨的 Postgres 集群,一個單獨的 Consul 集群。 這是關於如何攜帶和保存所有這些東西的基本說明,以免它們混在一起。

作為一個選項,您可以調整參數 ttl、loop_wait、retry_timeout,即嘗試通過增加這些參數來承受這些短期負載峰值。 但這不是最合適的選擇,因為這種加載時間可能會很長。 我們將簡單地超越這些參數的這些限制。 這可能並沒有什麼幫助。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

如您所知,第一個問題很簡單。 我們把 DCS 和基地放在一起,我們遇到了問題。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

第二個問題與第一個類似。 相似之處在於我們再次遇到與 DCS 系統的互操作性問題。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

如果我們查看日誌,我們將再次看到通信錯誤。 Patroni 說我無法與 DCS 交互,因此當前的主服務器進入副本模式。

老主人變成了複製品,帕特羅尼在這里工作,這是應該的。 它運行 pg_rewind 來倒回事務日誌,然後連接到新的 master 以趕上新的 master。 帕特羅尼在這裡鍛煉,他應該這樣做。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

在這裡,我們必須找到文件管理器之前的位置,即導致我們擁有文件管理器的那些錯誤。 在這方面,Patroni 日誌使用起來非常方便。 他在一定的時間間隔內寫相同的消息。 而如果我們開始快速滾動這些日誌,那麼我們會從日誌中看到日誌發生了變化,這意味著一些問題已經開始了。 我們趕緊回到這個地方,看看會發生什麼。

在正常情況下,日誌看起來像這樣。 檢查鎖的所有者。 例如,如果所有者發生變化,則可能會發生 Patroni 必須響應的某些事件。 但在這種情況下,我們很好。 我們正在尋找錯誤開始的地方。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

滾動到錯誤開始出現的位置後,我們看到我們進行了自動歸檔。 由於我們的錯誤與與 DCS 的交互有關,並且在我們的案例中我們使用了 Consul,因此我們還查看了 Consul 日誌,了解那裡發生了什麼。

粗略對比一下 filer 的時間和 Consul 日誌中的時間,我們看到我們在 Consul 集群中的鄰居開始懷疑 Consul 集群中其他成員的存在。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

如果您查看其他 Consul 代理的日誌,您還可以看到那裡發生了某種網絡崩潰。 而Consul集群的所有成員都在懷疑對方的存在。 這是提交人的動力。

如果你看看這些錯誤之前發生了什麼,你會發現有各種各樣的錯誤,例如 deadline,RPC falled,也就是說,Consul 集群成員之間的交互顯然存在某種問題.

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

最簡單的答案是修復網絡。 但對站在講台上的我來說,說這話很容易。 但在這種情況下,客戶並不總是能夠負擔得起維修網絡的費用。 他可能住在一個DC,可能無法修復網絡,影響設備。 因此需要一些其他選項。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

有以下選項:

  • 在我看來,即使在文檔中,最簡單的選項也是禁用 Consul 檢查,即簡單地傳遞一個空數組。 我們告訴領事代理不要使用任何支票。 通過這些檢查,我們可以忽略這些網絡風暴而不啟動文件管理器。
  • 另一種選擇是仔細檢查 raft_multiplier。 這是 Consul 服務器本身的一個參數。 默認情況下,它設置為 5。暫存環境的文檔建議使用此值。 事實上,這會影響 Consul 網絡成員之間的消息傳遞頻率。 實際上,這個參數影響的是Consul集群成員之間服務通信的速度。 對於生產,已經建議減少它以便節點更頻繁地交換消息。
  • 我們提出的另一個選擇是為操作系統的進程調度程序增加 Consul 進程在其他進程中的優先級。 有這樣一個“nice”參數,它只是決定了操作系統調度程序在調度時考慮的進程的優先級。 我們還降低了 Consul 代理的 nice 值,即增加了優先級,以便操作系統為 Consul 進程提供更多時間來工作和執行它們的代碼。 在我們的例子中,這解決了我們的問題。
  • 另一種選擇是不使用 Consul。 我有一個朋友是 Etcd 的大力支持者。 我們經常和他爭論 Etcd 和 Consul 哪個更好。 但就哪個更好而言,我們通常同意他的觀點,即 Consul 有一個代理,應該在每個節點上運行一個數據庫。 即Patroni與Consul集群的交互都是通過這個agent進行的。 而這個代理成為瓶頸。 如果代理出現問題,那麼 Patroni 將無法再使用 Consul 集群。 這就是問題所在。 Etcd 計劃中沒有代理。 Patroni 可以直接與 Etcd 服務器列表一起工作,並且已經與它們通信。 在這方面,如果你在公司使用 Etcd,那麼 Etcd 可能會是比 Consul 更好的選擇。 但是我們的客戶總是受到客戶選擇和使用的限制。 對於所有客戶,我們大部分時間都有領事。
  • 最後一點是修改參數值。 我們可以把這些參數調高,希望我們的短期網絡問題不會超出這些參數的範圍。 這樣,如果出現某些網絡問題,我們可以減少 Patroni 自動歸檔的積極性。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我想很多使用 Patroni 的人都熟悉這個命令。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

此命令顯示集群的當前狀態。 乍一看,這張照片似乎很正常。 我們有一個主人,我們有一個副本,沒有復制滯後。 但是這張圖是正常的,直到我們知道這個集群應該有三個節點,而不是兩個。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

因此,有一個自動歸檔。 在這個自動歸檔之後,我們的副本消失了。 我們需要找出她失踪的原因並將她帶回來,讓她恢復原狀。 我們再次查看日誌,看看為什麼我們有自動歸檔。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

在這種情況下,第二個副本成為主副本。 這裡沒問題。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我們需要查看掉落的副本以及不在集群中的副本。 我們打開Patroni日誌,發現在pg_rewind階段連接集群的過程中出現了問題。 連接集群需要倒帶事務日誌,向master請求需要的事務日誌,並用它來追趕master。

在這種情況下,我們沒有事務日誌,副本無法啟動。 因此,我們以錯誤停止 Postgres。 因此它不在集群中。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我們需要了解為什麼它不在集群中以及為什麼沒有日誌。 我們去找新主人,看看他在日誌中有什麼。 事實證明,當 pg_rewind 完成時,出現了一個檢查點。 一些舊的事務日誌只是簡單地重命名了。 當舊 master 試圖連接到新 master 並查詢這些日誌時,它們已經被重命名,它們只是不存在。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我比較了這些事件發生時的時間戳。 那裡的區別實際上是 150 毫秒,即檢查點在 369 毫秒內完成,WAL 段已重命名。 從字面上看,在 517 年,150 毫秒後,舊副本開始倒帶。 也就是說,從字面上看,150 毫秒對我們來說已經足夠了,以至於副本無法連接和賺錢。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

有什麼選擇?

我們最初使用複制槽。 我們認為這很好。 儘管在操作的第一階段我們關閉了插槽。 在我們看來,如果插槽積累了很多 WAL 段,我們就可以丟棄 master。 他會倒下的。 我們在沒有空位的情況下苦苦掙扎了一段時間。 我們意識到我們需要插槽,我們返回了插槽。

但是這裡有一個問題,當master去到replica的時候,它會刪除slots,並且把WAL段和slots一起刪除。 為了消除這個問題,我們決定提高 wal_keep_segments 參數。 它默認為 8 段。 我們將其提高到 1,然後查看我們有多少可用空間。 我們為 wal_keep_segments 捐贈了 000 GB。 也就是說,在切換時,我們始終在所有節點上保留 16 GB 的事務日誌。

而且 - 它仍然與長期維護任務相關。 假設我們需要更新其中一個副本。 我們想把它關掉。 我們需要更新軟件,也許是操作系統,或者其他東西。 當我們關閉副本時,該副本的插槽也會被刪除。 如果我們使用一個小的 wal_keep_segments,那麼在長時間沒有副本的情況下,事務日誌將會丟失。 我們將創建一個副本,它將請求它停止的那些事務日誌,但它們可能不在主服務器上。 副本也將無法連接。 因此,我們保留了大量雜誌。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我們有生產基地。 已經有項目在進行中。

有一個文件管理器。 我們進去看了看——一切都井井有條,副本就位,沒有復制滯後。 日誌中也沒有錯誤,一切都井井有條。

產品團隊說應該有一些數據,但我們從一個來源看到它,但我們沒有在數據庫中看到它。 我們需要了解發生在他們身上的事情。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

很明顯 pg_rewind 錯過了它們。 我們立即明白了這一點,但去看看發生了什麼。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

在日誌中,我們總能找到 filer 發生的時間,誰成為了 master,並且我們可以確定誰是舊的 master 以及他什麼時候想成為副本,即我們需要這些日誌來找出事務日誌的數量丟失了。

我們的老主人已經重新啟動。 Patroni 在 autorun 中註冊。 推出帕特羅尼。 然後他啟動了 Postgres。 更準確地說,在啟動 Postgres 之前並使其成為副本之前,Patroni 啟動了 pg_rewind 進程。 因此,他刪除了部分交易日誌,下載了新的交易日誌並進行了連接。 帕特羅尼在這裡巧妙地工作,正如預期的那樣。 群集已恢復。 我們有 3 個節點,在文件管理器 3 個節點之後 - 一切都很好。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我們丟失了一些數據。 我們需要了解我們失去了多少。 我們正在尋找倒帶的那一刻。 我們可以在這樣的日記條目中找到它。 倒帶開始,在那裡做了一些事情然後結束。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我們需要在事務日誌中找到老主人離開的位置。 在這種情況下,這就是標記。 而我們還需要第二個標記,也就是舊主人與新主人相差的距離。

我們採用通常的 pg_wal_lsn_diff 並比較這兩個標記。 在這種情況下,我們得到 17 兆字節。 很多或一點點,每個人自己決定。 因為對於某些人來說 17 兆字節並不多,對於某些人來說卻很多而且無法接受。 在這裡,每個人都根據業務需要自行決定。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

但是我們自己發現了什麼?

首先,我們必須自己決定——我們是否總是需要 Patroni 在系統重啟後自動啟動? 經常發生的情況是,我們必須去找老主人,看看他走了多遠。 也許檢查事務日誌的各個部分,看看那裡有什麼。 並了解我們是否會丟失這些數據,或者我們是否需要以獨立模式運行舊的 master 以提取這些數據。

只有在那之後,我們才必須決定我們是可以丟棄這些數據還是可以恢復它,將這個節點作為副本連接到我們的集群。

此外,還有一個“maximum_lag_on_failover”參數。 默認情況下,如果我沒記錯的話,此參數的值為 1 兆字節。

他是如何工作的? 如果我們的副本在復制延遲中落後 1 兆字節的數據,那麼該副本不會參與選舉。 如果突然發生文件轉移,Patroni 會查看哪些副本滯後。 如果他們落後於大量的事務日誌,他們就無法成為高手。 這是一項非常好的安全功能,可以防止您丟失大量數據。

但是存在一個問題,Patroni集群和DCS中的複制滯後是每隔一定時間更新一次。 我認為 30 秒是默認的 ttl 值。

因此,可能會出現一種情況,DCS中的replicas有一個replication lag,但實際上可能是完全不同的lag,也可能根本沒有lag,即這個東西不是實時的。 它並不總是反映真實情況。 而且不值得在上面做花哨的邏輯。

損失的風險始終存在。 在最壞的情況下,一個公式,在一般情況下,另一個公式。 也就是我們在規劃Patroni的實現,評估我們能丟失多少數據的時候,必須要依賴這些公式,粗略的想像一下我們能丟失多少數據。

有個好消息。 當老夫子先走了,由於有一些後台進程,他可以往前走。 也就是說,有某種 autovacuum,他寫入數據,將它們保存到事務日誌中。 而且我們很容易忽略並丟失這些數據。 這沒有問題。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

這就是如果設置了 maximum_lag_on_failover 並且發生了文件管理器並且您需要選擇一個新的主服務器時日誌的樣子。 副本評估自己無法參加選舉。 她拒絕參加領導者的比賽。 然後她等待選擇一個新的主人,這樣她就可以連接到它。 這是防止數據丟失的附加措施。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

在這裡,我們有一個產品團隊寫道,他們的產品與 Postgres 有問題。 同時,無法訪問 master 本身,因為它無法通過 SSH 訪問。 並且自動文件也不會發生。

此主機被迫重新啟動。 由於重新啟動,發生了自動歸檔,儘管可以進行手動自動歸檔,正如我現在所理解的那樣。 重新啟動後,我們已經可以看到當前 master 有什麼了。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

同時,我們提前知道我們的磁盤有問題,也就是說,我們已經通過監控知道在哪裡挖,要找什麼。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我們進入 postgres 日誌,開始查看那裡發生了什麼。 我們看到提交持續一、兩、三秒,這根本不正常。 我們看到我們的 autovacuum 啟動非常緩慢且奇怪。 我們在磁盤上看到了臨時文件。 也就是說,這些都是磁盤出現問題的指標。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我們查看了系統 dmesg(內核日誌)。 我們看到其中一個磁盤有問題。 磁盤子系統是軟件 Raid。 我們查看了 /proc/mdstat,發現缺少一個驅動器。 也就是有8塊盤的Raid,我們少了一塊。 如果您仔細查看幻燈片,那麼在輸出中您可以看到我們那裡沒有 sde。 在我們這裡,有條件的說,磁盤掉了。 這引發了磁盤問題,並且應用程序在使用 Postgres 集群時也遇到了問題。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

在這種情況下,Patroni 不會以任何方式幫助我們,因為 Patroni 沒有監控服務器狀態、磁盤狀態的任務。 我們必須通過外部監控來監控這種情況。 我們很快將磁盤監控添加到外部監控中。

有這樣一個想法——圍欄或看門狗軟件可以幫助我們嗎? 我們認為他在這種情況下幾乎不會幫助我們,因為在出現問題期間,Patroni 繼續與 DCS 集群交互並且沒有發現任何問題。 也就是說,從 DCS 和 Patroni 的角度來看,集群的一切都很好,儘管實際上磁盤有問題,數據庫的可用性也有問題。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

在我看來,這是我研究了很長時間的最奇怪的問題之一,我閱讀了很多日誌,重新挑選並稱之為集群模擬器。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

問題是舊的 master 不能成為一個正常的副本,即 Patroni 啟動它,Patroni 表明這個節點作為一個副本存在,但同時它不是一個正常的副本。 現在你會明白為什麼了。 這是我在分析該問題時保留下來的內容。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

這一切是如何開始的? 與上一個問題一樣,它開始於盤式製動器。 我們提交了一秒鐘,兩次。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

連接中斷,即客戶被撕毀。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

有不同程度的阻塞。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

並且,相應地,磁盤子系統不是很靈敏。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

對我來說最神秘的是收到的立即關閉請求。 Postgres 具有三種關閉模式:

  • 當我們等待所有客戶端自行斷開連接時,這是優雅的。
  • 當我們因為要關閉而強制客戶端斷開連接時,速度很快。
  • 並且立即。 在這種情況下,immediate 甚至不告訴客戶端關閉,它只是在沒有警告的情況下關閉。 並且對於所有客戶端,操作系統已經發送了一個 RST 消息(一個 TCP 消息,表明連接被中斷,客戶端沒有什麼可以捕獲的了)。

這個信號是誰發出的? Postgres 後台進程不會相互發送此類信號,即 kill-9。 他們不會互相發送這樣的東西,他們只會對這樣的事情做出反應,即這是 Postgres 的緊急重啟。 誰送的,不知道。

我看了看“最後”命令,我看到一個人也和我們一起登錄了這個服務器,但我太害羞了,不敢問問題。 也許是 kill -9。 我會在日誌中看到 kill -9,因為Postgres 說它需要 kill -9,但我沒有在日誌中看到它。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

進一步看,我看到 Patroni 很長時間沒有寫入日誌 - 54 秒。 如果我們比較兩個時間戳,大約有 54 秒沒有消息。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

在此期間有一個自動文件。 帕特羅尼再次在這裡做得很好。 我們的老主人不在,他出事了。 新主人的選舉開始了。 這裡的一切都很順利。 我們的 pgsql01 已成為新的領導者。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我們有一個已經成為大師的副本。 還有第二個回應。 第二個副本有問題。 她試圖重新配置。 據我了解,她試圖更改 recovery.conf,重新啟動 Postgres 並連接到新的主服務器。 她嘗試每 10 秒寫一次消息,但沒有成功。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

在這些嘗試過程中,一個立即關閉信號到達了舊主人。 主人重新啟動。 恢復也停止了,因為舊的主人進入重啟。 也就是說,副本無法連接到它,因為它處於關閉模式。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

在某些時候,它起作用了,但複製沒有開始。

我唯一的猜測是 recovery.conf 中有一個舊的主地址。 而當一個新的master出現時,第二個replica仍然試圖連接到舊的master。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

當 Patroni 在第二個副本上啟動時,節點啟動但無法複製。 並且形成了複製滯後,看起來像這樣。 也就是說,三個節點都到位了,但是第二個節點落後了。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

同時,如果查看寫入的日誌,您會發現複製無法啟動,因為事務日誌不同。 master 提供的那些在 recovery.conf 中指定的事務日誌根本不適合我們當前的節點。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

在這裡我犯了一個錯誤。 我不得不來看看 recovery.conf 中的內容,以檢驗我們連接到錯誤主機的假設。 但是後來我只是在處理這個,我沒有想到,或者我看到副本落後了,必須重新填充,也就是說,我不知何故粗心大意。 這是我的關節。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

30 分鐘後,管理員已經來了,即我在副本上重新啟動了 Patroni。 我已經結束了它,我認為它必須重新填充。 我想 - 我會重新啟動 Patroni,也許會有好結果。 恢復開始了。 甚至基地也開放了,它已經準備好接受連接了。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

複製已開始。 但一分鐘後,她因交易日誌不適合她的錯誤而倒下了。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我以為我會重新開始。 我又重啟了Patroni,並沒有重啟Postgres,而是重啟了Patroni,希望它能神奇的啟動數據庫。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

複製再次開始,但事務日誌中的標記不同,它們與之前的啟動嘗試不同。 複製再次停止。 消息已經略有不同。 這對我來說不是很有用。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

然後它發生在我身上 - 如果我重新啟動 Postgres 怎麼辦,此時我在當前主服務器上創建一個檢查點以將事務日誌中的點向前移動一點以便恢復從另一個時刻開始? 另外,我們還有 WAL 庫存。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我重新啟動了 Patroni,在主服務器上做了幾個檢查點,在副本打開時做了幾個重啟點。 它有所幫助。 我想了很長時間為什麼它有幫助以及它是如何工作的。 複製品開始了。 複製不再被撕裂。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

這樣的問題對我來說是比較神秘的問題之一,我仍然對那裡到底發生了什麼感到困惑。

這意味著什麼? Patroni 可以按預期工作,沒有任何錯誤。 但與此同時,這並不能 100% 保證我們一切都好。 副本可能啟動,但可能處於半工作狀態,應用程序無法使用這樣的副本,因為會有舊數據。

在文件管理器之後,您始終需要檢查集群是否一切正常,即是否存在所需數量的副本,沒有復制滯後。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

當我們解決這些問題時,我會提出建議。 我試圖將它們組合成兩張幻燈片。 也許,所有的故事都可以合併成兩張幻燈片,只講。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

當你使用 Patroni 時,你必須有監控。 您應該始終知道自動文件轉移何時發生,因為如果您不知道自己進行了自動文件轉移,就無法控制集群。 那很糟糕。

在每個文件管理器之後,我們總是必須手動檢查集群。 我們需要確保我們始終擁有最新數量的副本,沒有復制滯後,與流複製相關的日誌中沒有錯誤,使用 Patroni,使用 DCS 系統。

自動化可以成功工作,Patroni 是一個非常好的工具。 它可以工作,但這不會使集群達到所需的狀態。 如果我們不發現它,我們就會有麻煩。

而且 Patroni 不是靈丹妙藥。 我們仍然需要了解 Postgres 是如何工作的,複製是如何工作的,Patroni 如何與 Postgres 一起工作,以及如何提供節點之間的通信。 這是必要的,以便能夠用您的雙手解決問題。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我如何處理診斷問題? 恰好我們和不同的客戶端打交道,沒有一個有ELK stack,我們不得不打開6個控制台和2個選項卡來整理日誌。 在一個選項卡中,這些是每個節點的 Patroni 日誌,在另一個選項卡中,這些是 Consul 日誌,或 Postgres(如果需要)。 這很難診斷。

我採取了哪些方法? 首先,我總是查看歸檔器何時到達。 對我來說,這是一個分水嶺。 我查看了申報人之前、申報人期間和申報人之後發生的事情。 歸檔有兩個標記:這是開始時間和結束時間。

接下來,我在文件管理器之前的日誌中查找事件,即文件管理器之前發生的事件,即我尋找文件管理器發生的原因。

這提供了一幅了解發生了什麼以及將來可以做什麼的圖片,以便不會發生這種情況(因此,沒有文件管理器)。

我們通常在哪裡看? 我看:

  • 首先,到 Patroni 日誌。
  • 接下來,我查看 Postgres 日誌或 DCS 日誌,具體取決於在 Patroni 日誌中找到的內容。
  • 並且系統日誌有時還可以了解導致文件管理器的原因。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

我對帕特羅尼感覺如何? 我與帕特羅尼的關係非常好。 在我看來,這是當今最好的。 我知道很多其他產品。 它們是 Stolon、Repmgr、Pg_auto_failover、PAF。 4個工具。 我都試過了。 帕特羅尼是我的最愛。

如果他們問我:“我推薦 Patroni 嗎?”。 我會說是的,因為我喜歡Patroni。 我想我學會瞭如何做飯。

如果您有興趣了解除了我提到的問題之外 Patroni 還有哪些其他問題,您可以隨時查看頁面 問題 在 GitHub 上。 那裡有許多不同的故事,並討論了許多有趣的問題。 結果,引入並解決了一些錯誤,也就是說,這是一本有趣的書。

有一些關於人們搬起石頭砸自己腳的有趣故事。 非常翔實。 您閱讀並理解沒有必要這樣做。 我勾選了自己。

我想非常感謝 Zalando 開發這個項目,也就是 Alexander Kukushkin 和 Alexey Klyukin。 Aleksey Klyukin 是合著者之一,他不再在 Zalando 工作,但這兩個人開始使用該產品。

而且我認為 Patroni 是一件非常酷的事情。 我很高興她存在,這對她很有趣。 非常感謝所有為 Patroni 編寫補丁的貢獻者。 我希望帕特羅尼隨著年齡的增長變得更加成熟、冷靜和高效。 它已經可以使用了,但我希望它會變得更好。 因此,如果您打算使用 Patroni,請不要害怕。 這是一個很好的解決方案,可以實施和使用。

就這樣。 如有疑問,請提問。

Patroni 失敗案例或如何使您的 PostgreSQL 集群崩潰。 阿列克謝·列索夫斯基

問題

感謝您的報告! 如果在一個文件管理器之後你仍然需要非常仔細地查看那裡,那麼為什麼我們需要一個自動文件管理器?

因為是新東西。 我們只和她在一起一年。 最好是安全的。 我們想進來看看一切都按照它應該的方式進行。 這是成人不信任的程度——最好仔細檢查看看。

比如我們早上去看看,對不對?

不是在早上,我們通常幾乎立即就知道了自動歸檔。 我們收到通知,我們看到發生了自動歸檔。 我們幾乎立刻就去看了。 但是所有這些檢查都應該帶到監控級別。 如果您通過 REST API 訪問 Patroni,則有一段歷史記錄。 通過歷史記錄,您可以看到文件管理器發生時的時間戳。 基於此,可以進行監控。 你可以看到歷史,那裡有多少事件。 如果我們有更多事件,則會發生自動歸檔。 你可以去看看。 或者我們的監控自動化檢查所有副本是否就位,沒有滯後,一切都很好。

謝謝!

非常感謝精彩的故事! 如果我們將 DCS 集群移動到遠離 Postgres 集群的某個地方,那麼這個集群也需要定期維護嗎? 需要關閉 DCS 集群的某些部分的最佳實踐是什麼,要對它們做些什麼等等? 整個結構如何生存? 你如何做這些事情?

對於一家公司來說,有必要製作一個問題矩陣,如果一個組件或多個組件出現故障會發生什麼。 根據這個矩陣,我們依次遍歷所有組件並構建場景以防這些組件發生故障。 因此,對於每種故障情況,您都可以製定恢復行動計劃。 就 DCS 而言,它是標準基礎設施的一部分。 管理員管理它,我們已經依賴於管理它的管理員以及他們在發生事故時修復它的能力。 如果根本沒有DCS,那麼我們部署它,但同時我們不會特別監控它,因為我們不對基礎設施負責,但我們會就如何監控以及監控什麼給出建議。

也就是說,我是否正確理解我需要在對主機執行任何操作之前禁用 Patroni、禁用文件管理器、禁用所有內容?

這取決於我們在 DCS 集群中有多少個節點。 如果有很多節點,並且如果我們只禁用一個節點(副本),那麼集群會維持一個法定人數。 Patroni 仍在運營。 沒有任何東西被觸發。 如果我們有一些影響更多節點的複雜操作,缺少這些操作可能會破壞法定人數,那麼 - 是的,暫停 Patroni 可能是有意義的。 它有相應的命令——patronictl pause、patronictl resume。 我們只是暫停,autofiler 那時不工作。 我們在DCS集群上做維護,然後我們解除暫停,繼續生活。

非常感謝!

非常感謝您的報告! 產品團隊如何看待數據丟失?

產品團隊不在乎,團隊領導擔心。

有什麼保證?

保證非常困難。 Alexander Kukushkin 有一份報​​告“如何計算 RPO 和 RTO”,即恢復時間和我們可以丟失多少數據。 我認為我們需要找到這些幻燈片並研究它們。 據我記得,有關於如何計算這些東西的具體步驟。 我們可以丟失多少事務,我們可以丟失多少數據。 作為一種選擇,我們可以在 Patroni 級別使用同步複製,但這是一把雙刃劍:我們要么擁有數據可靠性,要么失去速度。 有同步複製,但也不能保證 100% 防止數據丟失。

阿列克謝,感謝您的精彩報告! 有使用 Patroni 進行零級保護的經驗嗎? 也就是配合同步備用? 這是第一個問題。 第二個問題。 您使用了不同的解決方案。 我們使用了 Repmgr,但沒有自動文件管理器,現在我們計劃包括自動文件管理器。 我們將 Patroni 視為替代解決方案。 與 Repmgr 相比,您有什麼優勢?

第一個問題是關於同步副本的。 這裡沒有人使用同步複製,因為大家都很害怕(幾個客戶端已經在使用它,原則上他們沒有註意到性能問題 - 講者註). 但是我們給自己制定了一個規則,一個同步複製集群至少要有三個節點,因為如果我們有兩個節點,如果master或者replica出現故障,那麼Patroni會把這個節點切換到Standalone模式,這樣應用才能繼續運行工作。 在這種情況下,存在數據丟失的風險。

關於第二個問題,我們用過Repmgr,由於歷史原因,現在還在用一些客戶端。 可以說什麼? Patroni 附帶了一個開箱即用的自動文件管理器,Repmgr 附帶了自動文件管理器作為需要啟用的附加功能。 我們需要在每個節點上運行 Repmgr 守護進程,然後我們可以配置自動文件管理器。

Repmgr 檢查 Postgres 節點是否存活。 Repmgr 進程檢查彼此的存在,這不是一種非常有效的方法。 可能存在復雜的網絡隔離情況,其中大型 Repmgr 集群可能會分裂成幾個較小的集群並繼續工作。 我已經很長時間沒有關注 Repmgr 了,也許它已經修復了……也可能沒有。 但是像 Stolon、Patroni 那樣,在 DCS 中移除關於集群狀態的信息是最可行的選擇。

阿列克謝,我有一個問題,也許是一個更簡單的問題。 在第一個示例中,您將 DCS 從本地計算機移動到遠程主機。 我們明白,網絡是一個有自己特點的東西,它是獨立存在的。 如果由於某種原因 DCS 集群變得不可用,會發生什麼情況? 原因我就不說了,可以有很多:從網絡人的歪手到真正的問題。

我沒有大聲說出來,但 DCS 集群也必須進行故障轉移,即節點數量為奇數,才能滿足法定人數。 如果 DCS 集群變得不可用,或者無法滿足法定人數,即某種網絡分裂或節點故障,會發生什麼情況? 在這種情況下,Patroni 集群進入只讀模式。 Patroni 集群無法確定集群的狀態以及要做什麼。 它無法聯繫 DCS 並在那裡存儲新的集群狀態,因此整個集群進入只讀狀態。 並等待操作員的手動干預或 DCS 恢復。

粗略地說,DCS對我們來說成為一種與基地本身一樣重要的服務?

是的是的。 在如此多的現代公司中,服務發現是基礎設施不可或缺的一部分。 它甚至在基礎設施中甚至沒有數據庫之前就已經實施了。 相對來說,基礎設施上線,部署在數據中心,我們馬上就有了Service Discovery。 如果是Consul,那麼DNS就可以建在上面。 如果這是 Etcd,那麼可能會有來自 Kubernetes 集群的一部分,其中將部署其他所有內容。 在我看來,服務發現已經是現代基礎設施不可或缺的一部分。 他們比數據庫更早地考慮它。

謝謝!

來源: www.habr.com

添加評論