1. 程式人生 > >一次DB故障引起的反思和MySQL Operator選型

一次DB故障引起的反思和MySQL Operator選型

前言

在一次資料庫故障後,我們發現業務庫會根據業務的等級會劃分多個 MySQL 例項,許多業務庫會同時屬於一個 MySQL 例項,當一個庫引發問題後整個例項的狀態是不可控的。從而導致這個例項上的所有業務不穩定甚至造成中斷。

故障反思

微服務架構

微服務架構在公司已經採用並堅持了近十年,我們也從傳統的 VM 部署架構轉身至當下的“容器+K8S”,無論是軟體架構還是部署架構,我們都朝著高可用,可伸縮,快速迭代的目標演進。

通過上述技術,我們將應用的可用性提升到了一個新的高度,不幸的是我們還是遇見了故障。

木桶效應

木桶效應是講一隻水桶能裝多少水取決於它最短的那塊木板。一隻木桶想盛滿水,必須每塊木板都一樣平齊且無破損,如果這隻桶的木板中有一塊不齊或者某塊木板下面有破洞,這隻桶就無法盛滿水。

墨菲定律

墨菲定律不是一種心理學效應,是一種數學推理。

如果有兩種或兩種以上的方式去做某件事情,而其中一種選擇方式將導致災難,則必定有人會做出這種選擇。根本內容是:如果事情有變壞的可能,不管這種可能性有多小,它總會發生。

總結

任何事情都有發生的概率,當短板缺陷暴露後會造成毀滅性打擊。

找到短板

可以看到,我們這次故障是因為一個業務庫發生了問題,從而影響了這個業務庫所在資料庫例項上的所有業務庫。
為什麼不是那個業務庫的具體問題呢?我們永遠無法避免一個庫永遠不會出現問題,但我們應該要儘量保障在單個庫故障的時候其它的庫和業務儘量不被影響。

現代軟體架構中可以發現,我們的應用架構一般是朝微服務架構的演講,但我們的基礎設施、中介軟體層(資料庫、MQ 等)確遲遲沒有進行“微”化。

我的方案

核心資料庫按現狀進行管理,由 DBA 進行悉心照顧。
邊緣資料庫則進行拆庫、隔離。

“微資料庫”?

通過上訴的問題,我們可以做的一件事情是拆分資料庫,將各個業務庫拆分出不同的例項。通過資源限制策略(VM、容器?)將資料庫所使用的資源進行隔離。
這樣當一個庫引起故障(節點故障,CPU 跑滿、IO 跑滿、記憶體溢位)時只要整體計算資源足夠,其它業務庫就不會有影響。

如何“微資料庫”?

經過這次事件後,我得出的結論是拆庫,降低故障影響面,但如何拆庫呢?
從最低保障來說,我們至少要保障 1 節點故障的可用度,也就是說一個數據庫例項至少有一個從庫,也就說 2 個數據庫例項(2 個計算節點)。

如果按傳統的方式來管理,一個業務一個庫(2 個例項、2 個節點)按照公司上百個資料庫來帶來的硬體成本和維護成本是巨大的。

業務現狀

公司雖然業務繁雜,有著非常多業務線和其衍生出的軟體工程,但核心業務其實非常少,核心庫就更少了。

容器 + K8S

好在我們在 2018 年後全部步入了“容器+K8S 模式”,有著豐富的容器和 K8S 使用和運維經驗,我們開啟了資料庫容器化的探索。

方案選型

如果使用容器 + K8S 進行資料庫運維,目前有兩種方案可以選:

  1. 直接使用 StatefulSet 執行 MySQL 映象
  2. 使用 MySQL Operator 進行管理(Operator 是 K8S 中的一種對外提供擴充套件的能力)

我們選擇了方案 2。
原因是 Operator 維護成本更低,更為簡單。缺點是不如直接使用 StatefulSet 靈活,但對於非資料庫專業人員來說,絕大多數情況 MySQL Operator 會比我們考慮的更周到。

MySQL Operator 選型

關於 MySQL Operator,選擇性其實很少,目前看來還能進行選擇的只有兩個,一個是 oracle 工作人員開源的,還有一個是社群的,兩個專案整體活躍度都不高。

先說結論:我們選擇了 presslabs/mysql-operator。
為什麼我們沒用選用以 oracle 官方明義釋出的 operator 呢?
主要是因為官方的庫除了資料上活躍一些,其實它並不活躍,而且比較老舊,也只支援 MySQL 8.0+,現狀大多數 MySQL 應該還是在 5.7+。
下面可以看下具體的分析。

oracle/mysql-operator

https://github.com/oracle/mysql-operator

專案情況:
652 star
303 issues (64 open)
151 commits

特點

  1. 使用 oracle 官方釋出的 MGR 高可用架構
  2. 自動、按需備份
  3. 自動故障檢測和恢復
  4. 從備份還原

不足

  1. 版本老舊
    不支援 k8s 1.16+的版本,因為使用了過時的 k8s api,在較新的 k8s 叢集上現狀需要修改原始碼。我們在調研的時候也修改了原始碼以支援新版本的 k8s。
  2. 只支援 MySQL8.0+版本
  3. 不夠活躍,最後有用的提交在一年前
  4. 是 oracle 工作人員利用空閒時間維護的
  5. 備份不支援備份到 pv,只能備份到谷歌雲、S3 相容的環境上

presslabs/mysql-operator

https://github.com/presslabs/mysql-operator

專案情況:
289 star
245 issues (74 open)
568 commits

特點

  1. 使用 Orchestrator 完成高可用(github 在用開源的專案)
  2. 自動、按需備份
  3. 自動故障檢測和恢復
  4. 從備份還原
  5. 整合 mysql prometheus 指標匯出
  6. Orchestrator 有提供 WebUI,可以方便的進行叢集管理
  7. 支援非同步、半同步、同步複製

不足

  1. 非官方支援
  2. 目前不支援 MySQL8+
  3. 不支援 Helm3 方式安裝(這個我們有找到解決方案)
  4. 備份不支援備份到 pv,只能備份到谷歌雲、Azure 或 S3 相容的環境上
  5. 最多支援雙主

思考

為什麼資料庫等基礎設施很少執行在容器中?

這個問題我有在很多線上社群和線下跟很多人討論過,中間也產生過非常激烈的探討。

支援執行在容器中

  1. 容器是未來的趨勢
  2. 容器帶來的效能損耗是有限的,絕大多數資料庫不需要那麼極端的效能

反對執行在容器中

  1. 容器不穩定
  2. 容器效能低
  3. 容器的未知性可能會造成不可逆的故障(資料丟失等)
  4. 資料持久化有問題

我的看法

資料庫容器化是趨勢,是必然的,只是當下並不能全部容器化。
這邊涉及到的內容會比較多,如果有不太瞭解的可以搜尋引擎一下。
首先這個問題有幾個解讀:

  1. 資料庫就單隻 MySQL 嗎?
  2. 資料庫能不能放進 K8S?
  3. K8S 跟容器的關係?
  4. 容器就是 Docker 嗎?
  5. 資料庫能不能用 Docker 執行?
  6. MySQL 能不能用容器執行?
  7. MySQL 能不能用 Docker 執行?

資料庫就單隻 MySQL 嗎?

這個答案當然是否定的,Redis、MongoDB、Etcd、MySQL、Oracle、SQLServer 等都算作資料庫。

資料庫能不能放進 K8S?

需要討論的本質是容器與資料庫,跟 K8S 並沒有關係,如果抱著這個問題大家可以直接排除,不用帶入 K8S。

K8S 跟容器的關係?

K8S 是排程平臺,容器的執行跟他沒任何關係,當 K8S 不可用容器不會發生任何變化,除非容器內的程式自己改變自己的狀態(異常退出等)。

容器就是 Docker 嗎?

否,容器當下最熱的實現是 Docker(在細分裡面還有 containerd 等不細分了,這邊就指通過 cgroups 技術實現的容器解決方案),還有像 Kata、gVisor 這樣非 cgroups 技術的實現。簡單來說一個容器可以是一個極度精簡後的虛擬機器。

資料庫能不能用 Docker 執行?

有些可以有些不行,Redis 等通過 Docker 執行業界已經有很多大廠案例了,Oracle 肯定是不能容器化的了。

MySQL 能不能用容器執行?

上面說了,容器不單隻 cgroups 技術的實現,這個問題大家可以理解成 MySQL 能不能執行在虛擬機器中?如果你們現有的 MySQL 執行在裸金屬物理機上才需要考慮,否則那麼一定是可以的。

MySQL 能不能用 Docker 執行?

其實這個才是大家最常見的理解方式,MySQL 能否執行在以 cgroups 技術實現的容器中。
阿里很早就開始將 cgroups 運用在 MySQL 中了。
Docker 封裝了 cgroups 的複雜度,提供了實際使用所需的許多內容,我覺得是可以使用 Docker 執行的。

常見誤區

  1. 在 K8S 中資料持久化非常麻煩,Pod 重啟資料會丟失,除非使用共享儲存,但共享儲存效能又很低。
    K8S 中可以將 Pod 中的路徑直接對映到本地磁碟,同時還可以使用 PV、PVC 的概念,Local Persistent Volume。相當於直接讀寫 Node 所在的磁碟。
  2. 容器中會丟失資料
    以 cgroups 實現的容器技術,其實還是 Node 上的一個程序,許可權和待遇跟其他程序並沒有太多區別,如果丟失資料那麼普通程序也會存在這樣的問題,大多數資料丟失並不是容器的鍋,而是架構或使用不當引起的。

確實存在的問題

  1. 效能下降
    容器效能下降主要來源於網路 IO。
    磁碟、記憶體、CPU 等損失幾乎沒有。
    網路 IO 造成的效能損失幅度還會跟 CNI 選型有關,現在基於 3 層網路轉發的 CNI 外掛(Calico、Flannel host-gw 等)來說損失度非常有限。
    任何包裝和封裝都會對效能造成影響,這邊大家需要評估的是這些損失的效能有沒有造成很大影響?對比於帶來的優勢來說值不值得?
  2. 不穩定
    任何新的嘗試都沒有人能保證 100%沒有問題,現階段確實沒有人敢將資料庫放入容器中在核心業務中使用(在邊緣業務中也有許多公司嘗試)

資料庫容器化總結

我覺得可以嘗試邊緣業務的資料庫進行容器化,這也是未來的趨勢。
核心資料庫(公司命脈)除非你有很大的把握,否則不要去動。

其實可以發現除傳統資料庫外,新起的分散式資料庫都將 K8S、容器當成一等公民(TiDB 等)

寫在最後

由於篇幅原因,將 “presslabs/mysql-operator” 部署和使用的內容放到後續的文章中,將會涉及 Local Persistent Volume 等內容