一、背景與使用場景
隨着Kubernetes平臺在容器雲計算領域的一統天下,雲原生 (Cloud Native) 一詞也被提的越來越頻繁。各類應用紛紛走上了容器化、雲原生化的道路,無狀態服務應用在Kubernetes平臺上的運行,已經得到了大規模生產級別的實踐認可。
相比之下,有狀態應用就沒有那麼順利了,特別是那些十分重要卻又"歷史悠久"、不是按照分佈式架構理念設計的有狀態服務,尤其困難。MySQL就是其中的代表,爲此我們做了諸多嘗試,從一開始的MySQL單實例容器化使用本地存儲,到計算存儲分離的方案,走了一些彎路。最終在開發測試場景下找了一個合適的切入點,實現了一套計算和存儲分離,以Kubernetes Operator爲核心,以CEPH RBD爲後端存儲,以數據庫版本化管理爲特性的可行方案。
我們典型的使用場景是這樣的:測試人員需要構造一個生產環境批量訂單數據異常的測試場景, 他使用安全工具從生產環境拉取大量脫敏後的數據寫入測試數據庫,但只運行一次測試用例, 數據庫就"髒了"。特別是每次上新功能還要回歸測試一次這種場景,又要重複耗時在構造新數據庫,真的是“構造2小時,運行5分鐘”。
而有了這一套完整的MySQL實例服務後,可以快速啓動任意版本的數據庫實例,前面所述的痛點就徹底消失了。同時有了MySQL實例服務,對CPU 內存資源的使用也可以節省一大筆,畢竟大量的測試數據庫都只要以快照的形式存儲在集羣中即可,實際使用時可以在一兩分鐘內快速啓動。
二、可行性方案分析和性能評估
首先要解決的是計算和存儲分離的問題,如果使用容器宿主機本地磁盤存儲的話,MySQL實例必須和宿主機綁定,這就喪失了資源的靈活性,而且使用本地存儲, 對於磁盤容量的規劃會是個不小的問題。
我們團隊早在2015就開始使用CEPH存儲服務,主要是對象存儲和塊存儲,運維經驗和集羣穩定性方面相對有保證。結合這一實際情況,我們選擇使用了CEPH塊存儲服務作爲MySQL容器實例的存儲。
另一個考量則是受益於Kubernetes這個強大的平臺基座,社區已經定義好了容器存儲接口 (CSI),且實現了CSI driver for CEPH (https://github.com/ceph/ceph-csi),其中RBD 部分早已GA,還有提供了snapshot,resize等功能,完全滿足我們的使用場景。
爲了驗證MySQL實例後端掛載CEPH塊存儲服務能否滿足開發測試環境的數據庫基本使用需求,我們基於已有的硬件情況, 做了兩個場景的性能壓測。主要是對比使用本地SAS磁盤存儲的MySQL實例和使用CEPHRBD的MySQL實例,在性能方面是否有明顯差異。其次則是測試MySQL實例後端掛載CEPH RDB存儲的性能上限。
基本硬件信息如下 :
使用本地磁盤的容器宿主機 | CEPH 集羣所用物理機 | |
---|---|---|
CPU | 2Socket / 32Core / 64Thread Intel® Xeon® CPU E5-2650 v3 @ 2。30GHz | 2Socket / 32Core / 64Thread Intel® Xeon® Gold 6130 CPU @ 2。10GHz |
Memory | 188GB | 256GB |
Disk | 2*300G,10K(1) 8*900G,10K(10) |
2*240G,SSD(10) 12*8T,7。2K(JBOD) |
構造了兩個測試場景,使用sysbench執行壓測:
sysbench參數如下:
參數名 | 參數值 | 備註 |
---|---|---|
oltp-tables-count | 64 | 測試表的個數64張 |
oltp-table-size | 1000000 | 單表數據量100W |
num-threads | [8,16,32,64,128,256] | 測試線程數 |
times of test | 3 | 每個線程下的測試次數 |
warmup time | 120 | 預熱時間,避免冷數據對測試結果的影響 |
max-time | 120 | 每次壓測耗時120s,重複3次 |
測試場景A:分別壓測MySQL docker with CEPH RBD 和MySQL docker with local disk,併發數threads從低到高,8→256,對比QPS。
測試場景B:同時壓測五個MySQL docker with CEPH RBD,保持併發數恆定在256,觀察CEPH集羣IOPS和最終MySQL QPS。
測試場景A結果:
OLTP模式壓測MySQL,對於磁盤主要是隨機讀寫操作,CEPH RBD使用了SSD作爲緩存盤,隨機寫速度約110MB/s,而本地機械磁盤隨機寫速度只有48.6MB/s,所以最終性能指標QPS,使用了CEPH RBD的容器實例反而更好。
測試場景B結果:
壓測CEPH RBD集羣的磁盤IO上限,約算測試環境的集羣能提供的QPS上限爲80K。
結論是在開發測試環境使用CEPH RBD爲後端存儲的MySQL實例服務,不會比使用本地磁盤更差,可以滿足應用功能測試的性能需求。
三、MySQL容器化實例方案及實現細節
介紹一下這套方案的簡單架構設計和基本工作原理,如下圖:
所有相關服務都部署在Kubernetes集羣上,這裏只重點描述我們開發的MySQL-Operator和自定義資源CRD。關於CSI driver 以及provisioner,attacher, snapshotter等組件都是使用原生官方鏡像,在這裏不做詳細表述,可以參考文檔(https://kubernetes-csi.github.io/docs/)。
MySQL-Operator作爲自定義的控制器,管理兩種自定義資源(CRD),通過Kube-api爲上層的PAAS平臺和CI等系統提供MySQL實例服務。兩個CRD分別是MySQLInstance和DatabaseSnapshot。其中MySQLInstance是基於StatefulSet的一層封裝,添加了一些metadata,MySQL-Operator只需要根據MySQLInstance的聲明來創建對應的StatefulSet和PVC即可, 所以MySQLInstance暴露出來的spec並不多,大致如下:
根據spec.init的類型,MySQLInstance既可以是基於生產數據庫Schema生成的空數據庫實例,也可以是基於已有的DatabaseSnapshot生成的帶有基準數據的實例。
在創建的過程中,MySQL-Operator會爲這個MySQLInstance申請域名,同步賬戶密碼以及Schema等。一個MySQLInstance的整個生命週期在有限的七個狀態之間跳轉。需要特別提一下Paused狀態,當基於該實例的DatabaseSnapshot創建時,MySQLInstance會進入Paused狀態。狀態機如下:
另一個CRD,DatabaseSnapshot則是基於VolumeSnapshot的封裝,其中VolumeSnapshot是Kubernetes官方定義的持久卷快照聲明(https://kubernetes.io/zh/docs/concepts/storage/volume-snapshots/)。MySQL-Operator根據它的聲明來關聯MySQLInstance和PVC即可。
由於CEPH RBD 的讀寫獨佔模式 RWO(read write once), 我們爲DatabaseSnapshot定義了兩個常態InUse和Ready。簡單來講就是一個數據庫快照同一時間只允許一個數據庫實例使用,並且DatabaseSnapshot在創建過程中需要暫停對應的MySQLInstance,狀態機如下:
四、小結與展望
在有了MySQLIntance服務之後,數據庫的版本管理變得和代碼版本管理一樣靈活。特別是重複構造測試數據的場景,節省了大量的時間和管理成本。另外用戶也不再需要長期佔用計算資源,僅在有使用需求時即可快速創建 MySQLInstance,有效提高了整體容器宿主機資源的使用率。除此之外,上層CI/CD平臺服務也可以通過Kube API調用的方式來管理這兩種CRD,進一步提升測試自動化程度。
一般來說,應用雲原生化完成後最重要的是獲得兩個能力:彈性和分佈式,目前我們的這套方案落地於Kubernetes平臺,釋放出了一部分平臺計算和存儲的彈性,讓用戶對於數據庫實例有了更多的選擇和靈活管理的能力。
何謂雲原生(Cloud Native), 字面上早已經有了明確的定義(https://github.com/cncf/toc/blob/master/DEFINITION.md),但是在工程實踐中,基於Kubernetes這個巨大的平臺,仍然有大量的寶藏等着我們去持續探索挖掘。
作者介紹:
Alex,專注於雲計算領域數年,目前主要從事容器雲平臺的建設,推進各類基礎設施服務的雲原生化。
小石川,目前主要從事容器雲平臺監控系統建設,對分佈式、性能以及優化感興趣。
本文轉載自公衆號攜程技術(ID:ctriptech)。
原文鏈接: