容器集羣管理mysql
在設計理念方面,k8s 只有 APIServer 與 etcd (存儲) 通訊,其餘組件在內存中維護狀態,經過 APIServer 持久化數據。管理組件動做的觸發是 level-based 而非 edge-based,並根據資源「當前狀態」和「指望狀態」進行相應動做。k8s 採用分層設計,基於各種抽象接口、由不一樣的插件知足不一樣的需求。git
在抽象方面,不一樣的 workload 服務於不一樣的應用,如針對無狀態應用的 Deployment、針對有狀態應用的 StatefulSet 等。在訪問管理方面,Service 解耦了集羣內部服務訪問方和提供者,Ingress 提供了集羣外部到集羣內部的訪問管理。github
k8s 雖然有良好的設計理念和抽象,但陡峭的學習曲線和不完善的開發資料極大增長了應用開發的難度。sql
本次分享將基於筆者的開發實踐,以 MySQL on k8s 爲例,描述如何基於 k8s 開發高可靠應用,儘量抽象出最佳實踐,下降基於 k8s 開發高可靠應用的成本。docker
應用的設計和開發不能脫離業務需求,對 MySQL 應用的需求以下:網絡
爲了實現上述需求,須要依靠 k8s 和應用兩方面協同工做,即開發基於 k8s 高可靠應用,既須要 k8s 相關的知識,也須要應用領域內的知識。架構
下述將根據上述需求來分析相應的解決方案。併發
1.數據高可靠負載均衡
數據的高可靠通常依賴於這幾方面:框架
咱們使用 Percona XtraDB Cluster 做爲 MySQL 集羣方案,它是 multi-master 的 MySQL 架構,實例間基於 Galera Replication 技術實現數據的實時同步。這種集羣方案能夠避免 master-slave 架構的集羣在主從切換時可能出現的數據丟失現象,進一步提高數據的可靠性。
備份方面,咱們使用 xtrabackup 做爲備份/恢復方案,實現數據的熱備份,在備份期間不影響用戶對集羣的正常訪問。
提供「定時備份」的同時,咱們也提供「手動備份」,以知足業務對備份數據的需求。
2.服務高可用
這裏從「數據鏈路」和「控制鏈路」兩個角度來分析。
「數據鏈路」是用戶訪問 MySQL 服務的鏈路,咱們使用 3 主節點的 MySQL 集羣方案,經過 TLB (七牛自研的四層負載均衡服務) 對用戶提供訪問入口。TLB 既實現了訪問層面對 MySQL 實例的負載均衡,又實現了對服務的健康檢測,自動摘除異常的節點,同時在節點恢復時自動加入該節點。以下圖:
基於上述 MySQL 集羣方案和 TLB,一個或兩個節點的異常不會影響用戶對 MySQL 集羣的正常訪問,確保 MySQL 服務的高可用。
「控制鏈路」是 MySQL 集羣的管理鏈路,分爲兩個層面:
這種拆解將每一個集羣的管理工做下放到每一個集羣中,下降了集羣間控制鏈路的相互干擾,同時又減輕了全局控制器的壓力。 以下圖:
這裏簡單介紹下 Operator 的理念和實現。
Operator 是 CoreOS 公司提出的一個概念,用來建立、配置、管理複雜應用,由兩部分構成: Resource
工做流程以下圖所示:
即:
咱們根據實踐,對開發 Operator 作了以下抽象:
CR 抽象爲這樣的結構體: 對 CR ADD/UPDATE/DELETE events 的操做,抽象爲以下接口:在上述抽象的基礎上,七牛提供了一個簡單的 Operator 框架,透明化了建立 CR、監聽 CR events 等的操做,將開發 Operator 的工做變的更爲簡單。
咱們開發了 MySQL Operator 和 MySQL Data Operator,分別用來負責「建立/刪除集羣」和「手動備份/恢復」工做。
因爲每一個 MySQL 集羣會有多種類型的任務邏輯,如「數據備份」「數據恢復」「健康檢測」「故障自動處理」等,這些邏輯的併發執行可能會引起異常,故須要任務調度器來協調任務的執行,Controller 起到的就是這方面的做用:
經過 Controller 和各種 Worker,每一個 MySQL 集羣實現了自運維。
在「健康檢測」方面,咱們實現了兩種機制:
對於健康檢測的數據,Controller 和 Operator 均會使用,以下圖所示:
Controller 使用健康檢測數據是爲了及時發現 MySQL 集羣的異常,並作相應的故障處理,故須要準確、及時的健康狀態信息。它在內存中維護全部 MySQL 實例的狀態,根據「主動檢測」和「被動檢測」的結果更新實例狀態並作相應的處理。
Operator 使用健康檢測數據是爲了向外界反映 MySQL 集羣的運行狀況,並在 Controller 異常時介入到 MySQL 集羣的故障處理中。
在實踐中,因爲健康檢測的頻率相對較高,會產生大量的健康狀態,若每一個健康狀態都被持久化,那麼 Operator 和 APIServer 均會承受巨大的訪問壓力。因爲這些健康狀態僅最新的數據有意義,故在 Controller 層面將待向 Operator 彙報的健康狀態插入到一個有限容量的 Queue 中,當 Queue 滿時,舊的健康狀態將被丟棄。
當 Controller 檢測到 MySQL 集羣異常時,將會進行故障自動處理。
先定義故障處理原則:
Green
同時針對每一個 mysqld 節點,定義了以下狀態:
Green
Controller 收集到全部 MySQL 節點狀態後,會根據這些節點的狀態推算 MySQL 集羣的狀態。當檢測到 MySQL 集羣狀態不是 Green 時,會觸發「故障處理」邏輯,該邏輯會根據已知的故障處理方案進行處理。若該故障類型未知,人工介入處理。整個流程以下圖:
因爲每種應用的故障場景和處理方案不一樣,這裏再也不敘述具體的處理方法。
3.易使用
咱們基於 Operator 的理念實現了高可靠的 MySQL 服務,爲用戶定義了兩類資源,即 QiniuMySQL 和 QiniuMySQLData。前者描述用戶對 MySQL 集羣的配置,後者描述手動備份/恢復數據的任務,這裏以 QiniuMySQL 爲例。
用戶可經過以下簡單的 yaml 文件觸發建立 MySQL 集羣的操做:
在集羣建立好後,用戶可經過該 CR object 的 status 字段獲取集羣狀態:
這裏再引入一個概念:Helm。
Helm 是爲 k8s 提供的包管理工具,經過將應用打包爲 Chart,標準化了 k8s 應用的交付、部署和使用流程。
Chart 本質上是 k8s yaml 文件和參數文件的集合,這樣能夠經過一個 Chart 文件進行應用的交付。Helm 經過操做 Chart,可一鍵部署、升級應用。
因爲篇幅緣由及 Helm 操做的通用性,這裏再也不描述具體的使用過程。
4.易運維
除了上述實現的「健康檢測」「故障自動處理」以及經過 Helm 管理應用的交付、部署,在運維過程當中還有以下問題須要考慮:
咱們經過 prometheus + grafana 作監控/告警服務,服務將 metric 數據以 HTTP API 暴露給 prometheus,由 prometheus server 定時拉取。開發人員在 grafana 上將 prometheus 中的監控數據可視化,根據對監控圖表和應用的把握,在監控圖中設置告警線,由 grafana 實現告警。
這種先可視化監控後告警的方式,極大程度上加強了咱們對應用運行特徵的把握,明確須要關注的指標和告警線,下降無效告警的產生量。
在開發中,咱們經過 gRPC 實現服務間的通訊。在 gRPC 生態系統中,有個名爲 go-grpc-prometheus 的開源項目,經過在服務中插入幾行簡單的代碼,就能夠實現對 gRPC server 全部 rpc 請求的監控打點。
對於容器化服務,日誌管理包括「日誌收集」和「日誌滾動」兩方面維度。
咱們將服務日誌打到 syslog 中,再經過某種手段將 syslog 日誌轉入到容器的 stdout/stderr 中,方便外部採用常規的方式進行日誌收集。同時,在 syslog 中配置了 logrotate 功能,自動進行日誌的滾動操做,避免日誌佔滿容器磁盤空間引起服務異常。
爲了提高開發效率,咱們使用 https://github.com/phusion/baseimage-docker 做爲基礎鏡像,其中內置了 syslog 和 lograte 服務,應用只關心把日誌打入 syslog 便可,不用關心日誌的收集和日誌滾動問題。
經過上述描述,完整的 MySQL 應用架構以下:
在開發基於 k8s 的高可靠 MySQL 應用過程當中,隨着對 k8s 和 MySQL 理解的深刻,咱們不斷進行抽象,逐步將以下通用的邏輯和最佳實踐以模塊的方式實現:
牛人說專欄致力於技術人思想的發現,其中包括技術實踐、技術乾貨、技術看法、成長心得,還有一切值得被發現的技術內容。咱們但願集合最優秀的技術人,挖掘獨到、犀利、具備時代感的聲音。