前言
在一次數據庫故障后,我們發現業務庫會根據業務的等級會划分多個 MySQL 實例,許多業務庫會同時屬於一個 MySQL 實例,當一個庫引發問題后整個實例的狀態是不可控的。從而導致這個實例上的所有業務不穩定甚至造成中斷。
故障反思
微服務架構
微服務架構在公司已經采用並堅持了近十年,我們也從傳統的 VM 部署架構轉身至當下的“容器+K8S”,無論是軟件架構還是部署架構,我們都朝着高可用,可伸縮,快速迭代的目標演進。
通過上述技術,我們將應用的可用性提升到了一個新的高度,不幸的是我們還是遇見了故障。
木桶效應
木桶效應是講一只水桶能裝多少水取決於它最短的那塊木板。一只木桶想盛滿水,必須每塊木板都一樣平齊且無破損,如果這只桶的木板中有一塊不齊或者某塊木板下面有破洞,這只桶就無法盛滿水。
墨菲定律
墨菲定律不是一種心理學效應,是一種數學推理。
如果有兩種或兩種以上的方式去做某件事情,而其中一種選擇方式將導致災難,則必定有人會做出這種選擇。根本內容是:如果事情有變壞的可能,不管這種可能性有多小,它總會發生。
總結
任何事情都有發生的概率,當短板缺陷暴露后會造成毀滅性打擊。
找到短板
可以看到,我們這次故障是因為一個業務庫發生了問題,從而影響了這個業務庫所在數據庫實例上的所有業務庫。
為什么不是那個業務庫的具體問題呢?我們永遠無法避免一個庫永遠不會出現問題,但我們應該要盡量保障在單個庫故障的時候其它的庫和業務盡量不被影響。
現代軟件架構中可以發現,我們的應用架構一般是朝微服務架構的演講,但我們的基礎設施、中間件層(數據庫、MQ 等)確遲遲沒有進行“微”化。
我的方案
核心數據庫按現狀進行管理,由 DBA 進行悉心照顧。
邊緣數據庫則進行拆庫、隔離。
“微數據庫”?
通過上訴的問題,我們可以做的一件事情是拆分數據庫,將各個業務庫拆分出不同的實例。通過資源限制策略(VM、容器?)將數據庫所使用的資源進行隔離。
這樣當一個庫引起故障(節點故障,CPU 跑滿、IO 跑滿、內存溢出)時只要整體計算資源足夠,其它業務庫就不會有影響。
如何“微數據庫”?
經過這次事件后,我得出的結論是拆庫,降低故障影響面,但如何拆庫呢?
從最低保障來說,我們至少要保障 1 節點故障的可用度,也就是說一個數據庫實例至少有一個從庫,也就說 2 個數據庫實例(2 個計算節點)。
如果按傳統的方式來管理,一個業務一個庫(2 個實例、2 個節點)按照公司上百個數據庫來帶來的硬件成本和維護成本是巨大的。
業務現狀
公司雖然業務繁雜,有着非常多業務線和其衍生出的軟件工程,但核心業務其實非常少,核心庫就更少了。
容器 + K8S
好在我們在 2018 年后全部步入了“容器+K8S 模式”,有着豐富的容器和 K8S 使用和運維經驗,我們開啟了數據庫容器化的探索。
方案選型
如果使用容器 + K8S 進行數據庫運維,目前有兩種方案可以選:
- 直接使用 StatefulSet 運行 MySQL 鏡像
- 使用 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
項目情況:
652 star
303 issues (64 open)
151 commits
特點
- 使用 oracle 官方發布的 MGR 高可用架構
- 自動、按需備份
- 自動故障檢測和恢復
- 從備份還原
不足
- 版本老舊
不支持 k8s 1.16+的版本,因為使用了過時的 k8s api,在較新的 k8s 集群上現狀需要修改源碼。我們在調研的時候也修改了源碼以支持新版本的 k8s。 - 只支持 MySQL8.0+版本
- 不夠活躍,最后有用的提交在一年前
- 是 oracle 工作人員利用空閑時間維護的
- 備份不支持備份到 pv,只能備份到谷歌雲、S3 兼容的環境上
presslabs/mysql-operator
項目情況:
289 star
245 issues (74 open)
568 commits
特點
- 使用 Orchestrator 完成高可用(github 在用開源的項目)
- 自動、按需備份
- 自動故障檢測和恢復
- 從備份還原
- 集成 mysql prometheus 指標導出
- Orchestrator 有提供 WebUI,可以方便的進行集群管理
- 支持異步、半同步、同步復制
不足
- 非官方支持
- 目前不支持 MySQL8+
- 不支持 Helm3 方式安裝(這個我們有找到解決方案)
- 備份不支持備份到 pv,只能備份到谷歌雲、Azure 或 S3 兼容的環境上
- 最多支持雙主
思考
為什么數據庫等基礎設施很少運行在容器中?
這個問題我有在很多線上社群和線下跟很多人討論過,中間也產生過非常激烈的探討。
支持運行在容器中
- 容器是未來的趨勢
- 容器帶來的性能損耗是有限的,絕大多數數據庫不需要那么極端的性能
反對運行在容器中
- 容器不穩定
- 容器性能低
- 容器的未知性可能會造成不可逆的故障(數據丟失等)
- 數據持久化有問題
我的看法
數據庫容器化是趨勢,是必然的,只是當下並不能全部容器化。
這邊涉及到的內容會比較多,如果有不太了解的可以搜索引擎一下。
首先這個問題有幾個解讀:
- 數據庫就單只 MySQL 嗎?
- 數據庫能不能放進 K8S?
- K8S 跟容器的關系?
- 容器就是 Docker 嗎?
- 數據庫能不能用 Docker 運行?
- MySQL 能不能用容器運行?
- 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 運行的。
常見誤區
- 在 K8S 中數據持久化非常麻煩,Pod 重啟數據會丟失,除非使用共享存儲,但共享存儲性能又很低。
K8S 中可以將 Pod 中的路徑直接映射到本地磁盤,同時還可以使用 PV、PVC 的概念,Local Persistent Volume。相當於直接讀寫 Node 所在的磁盤。 - 容器中會丟失數據
以 cgroups 實現的容器技術,其實還是 Node 上的一個進程,權限和待遇跟其他進程並沒有太多區別,如果丟失數據那么普通進程也會存在這樣的問題,大多數數據丟失並不是容器的鍋,而是架構或使用不當引起的。
確實存在的問題
- 性能下降
容器性能下降主要來源於網絡 IO。
磁盤、內存、CPU 等損失幾乎沒有。
網絡 IO 造成的性能損失幅度還會跟 CNI 選型有關,現在基於 3 層網絡轉發的 CNI 插件(Calico、Flannel host-gw 等)來說損失度非常有限。
任何包裝和封裝都會對性能造成影響,這邊大家需要評估的是這些損失的性能有沒有造成很大影響?對比於帶來的優勢來說值不值得? - 不穩定
任何新的嘗試都沒有人能保證 100%沒有問題,現階段確實沒有人敢將數據庫放入容器中在核心業務中使用(在邊緣業務中也有許多公司嘗試)
數據庫容器化總結
我覺得可以嘗試邊緣業務的數據庫進行容器化,這也是未來的趨勢。
核心數據庫(公司命脈)除非你有很大的把握,否則不要去動。
其實可以發現除傳統數據庫外,新起的分布式數據庫都將 K8S、容器當成一等公民(TiDB 等)
寫在最后
由於篇幅原因,將 “presslabs/mysql-operator” 部署和使用的內容放到后續的文章中,將會涉及 Local Persistent Volume 等內容。