容器化RDS|排程策略
沃趣科技·熊中哲
導 語
前文資料庫容器化|未來已來我們介紹了基於Kubernetes實現的下一代私有 RDS。其中,排程策略是具體實現時至關重要的一環,它關係到RDS 叢集的服務質量和部署密度。那麼,RDS 需要怎樣的排程策略呢?本文透過資料庫的視角結合Kubernetes的原始碼,分享一下我的理解。
It was the best of times, it was the worst of times。
—by Dickens.
人類從爬行到直立用了幾百萬年,但是我們這些碼農從Bare Metal到 Container只花了幾萬分之一的時間。
我有個朋友是維護Mainframe的,他還在使用40年前的系統。
排程策略很重要
看看巨人們在幹什麼,有助於我們更好的理解這個世界。
-
Google Borg
先看看Google是如何看待Borg (Kubernetes 的前身)的核心價值。在Google paper <Large-scale cluster management at Google with Borg>中,開篇就定義了 Borg :
It achieves high utilization by combining admission control, efficient task-packing,over-commitment, and machine sharing with process-level performance isolation.
裡面還專門介紹了基於 CPI (Cycles Per Instruction)測量資源利用率的方式。
-
AWS RDS
再看看公有云的領頭羊, AWS是這樣描述其RDS產品的:
不管是Google Borg還是AWS,除了提供更靈活,更開放,更相容,更安全,可用性更高的系統,都將cost-efficient,high utilization放到了更重要的位置。
提高部署密度,減少硬體的需求量,最終達到降低硬體投入的目標。
同時,
必須滿足業務需求。
本文嘗試以資料庫的視角,從多個角度闡述RDS場景需要怎樣的排程策略。
說明:
-
為了實現更精細化的排程策略,Kubernetes(版本1.7) 排程器提供了17個排程演算法。這些演算法分為兩類Predicate和Priority,通俗的描述是過濾和打分。設計思路大致如下:
1.透過過濾演算法,從叢集中出滿足條件的節點;
2.透過打分演算法,對過濾出來的節點打分並排名;
3.挑出分數最高的節點,如果有分數相同的,隨機挑一個。
-
本文將基於Kubernetes的實現,結合RDS場景展開,並不會把所有的演算法流水賬似的寫一遍,相關資料很多,有興趣的同學可以去看文件。具體實現見:
① kubernetes/plugin/pkg/scheduler/algorithm/priorities
②kubernetes/plugin/pkg/scheduler/algorithm/predicates
下面進入主題。
排程策略
視角一 : 計算資源排程策略
這裡討論的計算資源僅包含 CPU,Memory:
看上去很簡單,挑選出一個滿足資源要求的節點即可,但是考慮到整合密度和資料庫的業務特點並不簡單,我們還需要考慮到以下幾點:
-
峰值和均值:
資料庫的負載隨著業務、時間、週期不斷變化,到底是基於峰值排程還是均值排程呢?這是一個有關部署密度的問題,最好的辦法就像Linux裡面限定資源的方式,讓我們設定Soft Limit 和Hard Limit,以Soft Limit分配資源,同時Hard Limit又能限定使用的最大資源。Kubernetes也是這麼做的,它會透過 Request 和 Limit 兩個閾值來進行管理容器的資源使用。
Requst作為Pod初始分配值,Limit 限定了Pod能使用的最大值。分配時採用Requst值進行排程,這裡有個假設:
同一節點上執行的容器不會同時達到 Limit 閾值
有效的實現了計算資源利用率的high utilization,非常適合資料庫開發或測試場景。
如果假設不成立,
當某節點執行的所有容器同時接近Limit,並有將節點資源用完的趨勢或者事實(在執行的過程中,排程器會定期收集所有節點的資源使用情況,“蒐集”用詞不太準確,但便於理解),建立 Pod的請求也不會再排程到該節點。
同時,基於優先順序,部分容器將會被驅逐到其他節點(例如透過重啟 Pod 的方式),所以並不適合生產環境。
-
資源的平衡:
對於長期執行的叢集,在滿足資源的同時還要考慮到叢集中各節點資源分配的平衡性。
類似Linux Buddy System,僅僅分配程式需要的記憶體是不夠的,還要保障作業系統記憶體的連續性。
舉個例子,RDS叢集有兩個節點,使用者向RDS申請 2顆CPU和4GB記憶體 以建立 MySQL例項,兩節點資源使用情況如下:
在資源同時滿足的情況下,排程會透過兩個公式對節點打分。
基於已使用資源比率(Balanced Resource)打分,實現如下:
將節點資源輸入公式,可簡化成:
NodeA 分數 = int(1-math.Abs(8/16 - 8/32)) * float64(10) = 30/4
NodeB 分數 = int(1-math.Abs(8/32 - 16/64)) * float64(10) = 10
基於該演算法Node B的分數更高。
再透過未使用資源(calculateUnused)持續打分。
該演算法可簡化成:
cpu((capacity - sum(requested)) * 10 / capacity) + memory((capacity - sum(requested)) * 10 / capacity) / 2
有興趣的同學可以算一下,不再贅述。
資料庫會被排程到綜合打分最高的節點。
視角二 : 儲存資源排程策略
儲存資源是有狀態服務中至關重要的一環,也讓有狀態服務的實現難度遠超無狀態服務。
除了滿足請求資料庫的儲存資源的容量要求,排程策略必須要能夠識別底層的儲存架構和儲存負載,在提供儲存資源的同時,滿足資料庫的業務需求(比如資料零丟失和高可用)。
從2017年年初開始,基於分散式儲存技術,我們的RDS已經實現了計算和儲存分離的架構。
在實現資料庫的資料零丟失,高可用的同時,架構變得更通用,更簡單。但對企業級使用者,還遠遠不夠,cost-efficient 是考量產品成熟度的重要因素。
所以從一開始,我們就以3種維度的儲存QoS來思考這個問題:
-
從功能角度 :
儲存資源分成兩大類
distribution,基於分散式儲存技術實現,對 Flash 裝置做了專門的 最佳化,提供資料冗餘和彈性擴容功能;
local,使用計算節點本地儲存。
對於生產環境,我們會申請distribution資源。而那些不太重要的或者臨時性的,譬如有的客戶需要經常生成臨時性的克隆庫進行測試,或者擴充套件臨時備庫以應對突發的業務高峰,我們會申請 local資源。
-
從效能角度:
我們又將distribution分成了兩類high和medium,以應業務不同的IOPS,Through put,Latency需求。
IO密集型業務,我們會分配high型別。對於計算密集型或者重要值很高的備庫,我們會分配medium型別。
-
從資料庫角度:
比如, 不同的資料庫物理卷的掛載引數也不同;
如果排程器能夠實現, 將極大的提高儲存資源的 cost-efficient。
這些特性帶有明顯的資料庫業務特性,原生的Kubernetes排程器並不支援。但是,我們透過二次開發,Out of Cluster的方式實現了外接的Kubernetes storage provisoner,並透過自定義的引數和程式碼實現和排程器的互動。
這樣Kubernetes的排程器就可以基於RDS的業務需求,感知底層儲存架構,提供滿足業務需求的排程服務。
除去需要的容量資訊,需要傳遞給排程器如下資訊(就像請CPU,Memory資源一樣):
volume.beta.kubernetes.io/mount-options: sync
volume.orain.com/storage-type: "distribution"
volume.orain.com/storage-qos: "high"
volume.orain.com/dc-id: "278"
透過這四個引數將會告知。
-
從功能角度:
volume.orain.com/storage-type: "distribution", 使用 distribution 型別儲存資源。
-
從效能角度:
volume.orain.com/storage-qos: "high", 從高效能儲存池獲取 Volume
-
從資料庫角度:
volume.beta.kubernetes.io/mount-options: sync, 使用特定 mount 引數
volume.orain.com/dc-id: "278", 使用編號為278的 Volume
視角三 : 關係型資料庫
關係型資料庫是有狀態服務,但要求更加複雜。比如我們提供了MySQL的Read Write Cluster (讀寫分離叢集) 和Sharding Cluster (分庫分表叢集),每個資料庫例項都有自己的角色。排程器必須感知叢集角色以實現業務特點:
比如, 基於資料庫角色, 我們有如下排程需求:
-
ReadWrite Cluster的Master和Slave不能排程到同一節點
-
Master的多個Slave不能排程到同一節點
-
Sharding Cluster的每個分片不能排程到同一節點
-
某些備份任務須排程到指定Slave所在的節點
-
…..
帶有明顯的業務(RDS)特點,原生Kuberentes的排程策略並不能識別這些角色和關係。
與此同時,容器的執行狀態和RDS叢集還在動態變化:
以上具體的問題抽象成:
親和性(Affinity), 反親和性(Anti-Affinity)和分佈度(Spread Width)
再透過我們的二次開發,將資料庫的角色和業務流程整合到排程器中,以滿足全部需求。
-
親和性(Affinity)
排程需求4可以歸納到這裡
需求4 : 某些備份任務須排程到指定 Slave 所在的節點
在所有節點中找到指定 Slave 所在節點, 以確定待排程備份任務排程到哪個節點. 該需求必須滿足, 不然備份任務無法成功.
建立已執行資料庫和節點的關係,在透過Affinity和Anti-Affinity公式對所有節點打分,以此決定待排程資料庫是否要排程到該節點。
查詢該節點所有資料庫例項:
確定該節點是否有指定 Slave:
-
反親和性(Anti-Affinity)
需求1 : ReadWrite Cluster 的 Master 和 Slave 不能排程到同一節點
以待排程資料庫的角色為輸入,建立已執行資料庫和節點的關係,再透過 Anti-Affinity 公式對所有節點打分,以此決定待排程資料庫是否要排程到該節點。
以需求1為例,統計叢集成員的分佈情況,該節點上同一資料庫叢集的成員越多,分數越低。
反親和性(Anti-Affinity)公式
-
分佈度(Spread Width)
有種更時髦的叫法散射度(scatter width)
需求2,3可以歸納到這裡。
以需求2為例, 統計叢集成員的分佈情況, 該節點上同一資料庫叢集的成員越多, 分數越低。
然後對所有節點打分,公式如下:
float64(schedulerapi.MaxPriority) * ((maxCountByNodeName -countsByNodeName[node.Name]) / maxCountByNodeName)
需要特別說明的是, 在RDS進行排程時:
-
需求1,4必須滿足;
-
需求2,3儘量滿足既可以。
必須和儘量也需要作為排程引數,讓排程器知曉。
結 語
本文僅以RDS的視角,從三個層級講述了對排程器的要求。
真實的世界會更加複雜,比如針對Read Write Cluster,Slave 必須等待Master建立完畢,而Sharding Cluster,所有分片可以併發建立……
在設計產品和完成編碼的過程中,踩坑無數。不能否認的是,站在巨人的肩膀上可以讓我們看的更遠。不知道Ending怎麼寫, 就這樣吧。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28218939/viewspace-2147570/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Flink排程之排程器、排程策略、排程模式模式
- 有容雲AppSoar容器健康檢查與排程策略APP
- 實戰Docker容器排程Docker
- Linux程式排程策略Linux
- 排程器簡介,以及Linux的排程策略Linux
- Go runtime 排程器精講(五):排程策略Go
- haipproxy核心校驗和排程策略AI
- 容器化RDS—— 計算儲存分離 or 本地儲存
- 第三章 Goroutine排程策略(16)Go
- 【I/O scheduler】Linux的磁碟排程策略Linux
- 容器化RDS|計算儲存分離架構下的 IO 優化架構優化
- 容器化 RDS:藉助火焰圖定位Kubernetes效能問題
- Zeus-Master-週期性排程策略實現AST
- Go runtime 排程器精講(二):排程器初始化Go
- 容器化 RDS:藉助 CSI 擴充套件 Kubernetes 儲存能力套件
- Lua OpenResty容器化(考古歷程)REST
- K8s 容器的定向排程與親和性K8S
- Java設計模式——策略模式——方法多樣 排程靈活Java設計模式
- MySQL優化--IO排程演算法優化MySql優化演算法
- 容器化RDS—計算儲存分離架構下的“Split-Brain”架構AI
- Linux核心排程分析(程式排程)Linux
- Docker批量容器編排Docker
- 技術解讀 | SD-WAN的多樣性策略排程
- Spark中資源排程和任務排程Spark
- Go語言goroutine排程器初始化Go
- Python自定義阿里雲RDS備份策略Python阿里
- 實現一個分散式排程系統-LoadBalance和Ha策略分散式
- Linux排程策略及執行緒優先順序設定Linux執行緒
- Go語言排程器之主動排程(20)Go
- Go排程器系列(3)圖解排程原理Go圖解
- 42_Docker容器編排Docker
- Hadoop YARN:排程效能最佳化實踐HadoopYarn
- Go排程器系列(2)巨集觀看排程器Go
- Go語言排程器之排程main goroutine(14)GoAI
- 【Spark篇】---Spark資源排程和任務排程Spark
- Pod的排程是由排程器(kube-scheduler)
- docker筆記33-排程器、預選策略及優選函式Docker筆記函式
- 任務排程