爲了知足渲染、基因測序等計算密集型服務的需求,UCloud 推出了「計算工廠」產品,讓用戶能夠快速建立大量的計算資源(虛擬機)。該產品的背後,是一套基於 Mesos 的計算資源管理系統。本文簡要介紹該系統的結構、Mesos 在 UCloud 的使用、咱們的解決方案以及遇到的問題。算法
咱們的需求主要是兩方面:數據庫
簡單地說,咱們須要有一個平臺,統一封裝多個數據中心的計算資源,而且同時支持虛擬機、容器等多種形式的資源使用方式。安全
圖1:計算資源管理平臺的需求示意圖服務器
說到虛擬機,首先想到的就是 UCloud 本身的 UHost 和開源的 OpenStack,然而,這兩套系統都是針對大型公有云的場景,並且主要只針對於虛擬機這一種業務。它們功能豐富、模塊衆多,運維運營上都須要很大的成本。然而咱們的業務並不須要這麼多功能。網絡
最終,咱們選擇基於 Mesos 來實現這套平臺。架構
Mesos是Apache下的開源分佈式資源管理框架,它是一個分佈式系統的內核。框架
經過 Mesos,一個數據中心所提供的再也不是一臺臺服務器,而是一份份的資源。資源能夠是 CPU 核數、內存、存儲、GPU 等等。若是把一個數據中心當作一個操做系統的話,Mesos 就是這個操做系統的內核。運維
咱們選擇 Mesos 的緣由在於它擁有高度可擴展性,同時又足夠簡單。分佈式
做爲內核,Mesos 只提供最基礎的功能:資源管理、任務管理、調度等。而且每一種功能,都以模塊的方式實現,方便進行定製。架構上,Master 和 Agent 兩個模塊就實現了資源相關的全部工做,用戶只需根據本身的業務邏輯實現 Framework 和 Executor 便可。這樣就支持咱們可以把計算資源封裝成虛擬機、容器等各類形式。動畫
採用 Mesos 來進行容器編排的方案已經被不少廠商使用,相關的資料文檔也比較豐富。然而用 Mesos 來管理虛擬機,業內並無應用於生產環境的實踐。本文的餘下內容,主要向讀者分享一下 UCloud 用 Mesos 管理虛擬機的思路和實踐經驗。
Mesos 採用 Master-Agent 架構。Master 負責總體資源的調度並對外提供 API。Agent 部署在全部機器上,負責調用 Executor 執行任務、向 Master 彙報狀態等。
Mesos 提供了一個雙層調度模型:
總體架構以下圖:
圖2:Mesos 的雙層調度結構圖
在 Mesos 的雙層調度模型上,平臺的總體架構以下圖:
圖3:基於Mesos的資源管理平臺總體架構圖
結構以下:
系統內的全部通訊都基於 HTTP。
首先,Mesos 內部基於 libprocess 各組件之間的通訊都都依賴 libprocess 庫,該庫用 C++ 實現了 Actor 模式。每一個 Actor 會監聽 HTTP 請求,向 Actor 發消息的過程就是把消息體序列化後放在 HTTP 報文中,而後請求這個 Actor。
其次,業務相關的各個組件,API Server、Cluster Server 等也都經過 Restful 的 API 提供服務。
HTTP 的優勢在於簡單可靠、易於開發調試和擴展。
對於 Docker 容器,咱們採用 Marathon Framework 進行管理。而對於虛擬機,咱們則採用本身開發的 VM Scheduler Framework 。
VM Scheduler 從 Master 獲取一個個的資源 offer 。一個資源 offer 包含了某個 Agent 上可用的資源。當有虛擬機任務須要執行是,Cluster Server 會把任務的具體信息發送給 VM Scheduler。
任務分爲兩類:
Task 是 Mesos 中資源分配的最小單位。Master 會告訴 Agent 須要執行哪些 Task,Agent 也會把 Task 的狀態彙報給 Master。根據 Task 的信息,Agent 會下載並啓動所需的 Executor,而後把具體的 Task 描述傳給它。
VM Executor 是咱們開發的對虛擬機的生命週期進行管理的 Executor,實現了對虛擬機建立、刪除、開關機、鏡像製做等功能。
VM Executor 啓動後,根據 Task 的描述,動態生成虛擬機須要的配置文件,而後調用 libvirt 進行虛擬機建立。當收到來自 VM Scheduler 的 Framework Message 時,又調用 libvirt 進行開關機等操做。
狀態的管理是實現虛擬機管理的關鍵部分。經過 Mesos 咱們只能拿到 Task 的狀態,RUNING 表示虛擬機建立成功,FAILED 表示虛擬機失敗,FINISHED 表示虛擬機成功銷燬。然而除此以外,一個虛擬機還存在「開機中」、「關機中」、「關機」、「鏡像製做中」等其餘狀態。咱們經過在 VM Executor 和 VM Scheduler 之間進行心跳,把這些狀態同步給 VM Scheduler。後者對狀態進行判斷,若是發現狀態改變了,就發送一條狀態更新的消息給 Cluster Server,而後再轉發給 API Server,最終更新到數據庫。
首先看一下一個 Task 在 Mesos 中是怎麼調度的:
圖4:Mesos 資源調度過程示意圖
上面的示例中:
對應到虛擬機的狀況,調度分兩個部分:
服務器之間除了 CPU、內存、硬盤等可能不一樣外,還會存在其餘的差異。好比有時候業務要求必定要用某個型號的 CPU,有時候要求必定要擁有 SSD等等。爲了支持更多維度的調度,咱們利用了 Mesos 的 Resource 和 Attribute 來標識不一樣的資源。
Resource是 Mesos 中的一個概念,表示一切用戶須要使用的東西。Agent 默認會自動添加 cpus, gpus, mem, ports 和 disk 這5種資源。另外還能夠在 Agent 啓動時,經過參數指定其餘資源。
Attribute 以 Key-Value 形式的標籤,標識一個 Agent 擁有的屬性,一樣能夠在啓動時經過參數指定。
經過 Resource 和 Attribute 的靈活運用,能夠標識出更多的資源狀況,知足各類資源調度需求。好比經過 Resource 指定 SSD 大小、CPU型號,經過 Attribute 標識機架位、是否擁有外網 IP,是否支持超線程等等。Framework 收到一個 resource offer 後,與待執行的任務需求進行匹配,經過 resource 判斷資源是否夠用,再經過 Attribute 判斷是否知足其餘維度的需求,最終決定是否用這個 offer 來建立 Task。
平臺提供了一些基礎鏡像,另外用戶也能夠基於本身的虛擬機建立本身的鏡像。這些鏡像文件統一存儲在一個基於 GlusterFS 的分部署存儲服務中,該服務掛載在每臺物理機上。
有些業務場景須要部分虛擬機可以共享同一份存儲,因而咱們仍是基於 GlusterFS 開發了用戶存儲服務,可以根據用戶的配置,在虛擬機建立時自動掛載好。
網絡方面,每一個用戶能夠建立多個子網,各個子網之間作了網絡隔離。建立虛擬機時,須要指定使用哪一個子網。
在使用 Mesos 的過程當中,咱們也遇到了其餘一些問題。
當機器負載比較高,尤爲是 IO 較高時,咱們發現 Marathon 集羣有機率出現不能選主的狀況。
咱們懷疑是因爲Marathon節點和ZK的網絡不穩定,觸發了Marathon或Mesos的bug致使。因而經過iptables主動屏蔽Leader ZK端口的方式,成功復現出問題。
經過在Marathon的代碼中加上一些Leader選舉相關的最終日誌,成功定位到了問題,原來是因爲Mesos Driver的stop() 方法沒有成功引發 start() 方法退出阻塞致使。
因爲咱們的全部程序都是經過守護進程啓動的,因此咱們採用了一個最簡單的解決方案:修改Marathon代碼,當ZK異常發生時,直接自殺。自殺後守護進程會把程序再啓動起來。
咱們的服務採用 Golang 開發,使用 go-marathon 庫與 Marathon 進行交互。使用過程當中發現該庫有一些問題:
不支持多Marathon節點。因而咱們本身建立了一個分支,採用節點主動探測的方式,實現了多節點的支持。(原庫v5.0版本之後也支持了該功能)
使用設有 Timeout 的 http.Client 進行 go-marathon 的初始化時,訂閱 SSE 會產生超時問題。因而咱們作了修改,普通的 HTTP API 和 SSE 不使用同一個 http.Client,操做 SSE 的 http.Client 不設置 Timeout。
網絡異常時,go-marathon 的方法調用會 Hang 住。因而咱們全部對 go-marathon 方法的調用都加上超時控制。
Mesos 在 UCloud 有着普遍的應用,對外有「計算工廠」和 UDocker 等產品,對內則支撐着公司內網虛擬機管理平臺。伴隨着持續的實踐,咱們對 Mesos 的理解和掌控也愈來愈深刻。咱們會持續輸出咱們的使用經驗,期待獲得各位讀者的反饋。