Google大規模集羣管理系統Borg的解讀

0 背景

        0.1 Borg簡介

        Borg是Google內部的大規模集羣管理系統,已經延續十餘年的時間,大體上與MapReduce、GFS、BigTable、Chubby是同時代的產物,但一直被雪藏,直至今年才發表論文,披露其實現細節。論文鏈接(http://research.google.com/pubs/pub43438.html)。

        Kubernetes被認爲是Borg的開源版本(研發團隊部分重合、功能簡化聚焦、架構類似)。許多研發Borg的工程師現在正投身於Kubernetes系統,並從Borg中汲取經驗,不斷打磨Kubernetes。這也是我將此篇博客歸類到“Docker& k8s”的原因。

       0.2 筆者與Borg

       筆者所在團隊的前輩曾經聯合騰訊公司研發過集羣管理系統T-Borg(公司內部代號),即Torca的原型。從名字上看,不難推測T-Borg也是類似Borg的集羣管理系統。筆者本人從碩士階段就一直從事雲平臺/集羣管理系統的研發,期間也曾從T-Borg中汲取經驗。可以說我一直在關注和學習Borg系統,因此Borg公開發表論文,我也在第一時間關注。

 

1 Abstract & Introduction

       Borg系統爲Google進行集羣管理,其上運行着十萬級別的作業(Job)、數千級別的應用(App)、管理着數萬級別的機器(Machine)。

       Borg的三大優勢:

     (1)隱藏資源管理和錯誤處理的細節,使得用戶可以聚焦應用開發;

     (2)高可靠性和高可用性,同時支持應用的高可靠和高可用;

     (3)在數萬節點上有效運行工作負載。

       個人解讀:這三條優勢說的已經比較明確了,如果再總結一下,可以歸結爲(1)易用性(解決分佈式共性問題,屏蔽細節);(2)高可用性;(3)可擴展性(數萬節點)和高利用率(有效運行)。這些都是雲平臺需要解決的核心問題。

       Borg不是第一個關注這些問題的系統,卻是僅有的幾個如此大規模的系統之一。個人解讀:這句話說得較爲低調,Borg有可能是這個世界上規模最大的集羣管理系統。

 

2 用戶視角 The user perspective

       Borg的用戶是Google的開發人員和系統管理員。用戶以作業(Job)的形式向Borg提交工作,其中每個作業(Job)包含着一個或者多個運行相同程序的任務(task)。每個作業(Job)運行在同一個Borg單元(Cell)中,單元(Cell)是一組機器的集合。

       2.1 工作負載

       Borg Cell中運行着異構的工作負載,主要包括兩個部分:服務和批處理作業。服務長時間運行,幾乎不會停止,處理短期的、延遲敏感的請求,服務通常是面向終端用戶的產品(如Gmail、Google Docs、web search)和一些內部基礎設施服務(BigTable,即HBase的Google版本)。批處理作業運行時間在幾秒到幾天不等;它們對短期性能波動並不敏感。工作負載會在Cell上混合部署。

       大部分應用框架已經運行在Borg上多年,包括內部的MapReduce、FlumeJava、Millwhell、Pregel。Google的分佈式存儲系統也都運行在Borg之上,包括GFS、BigTable、Megastore等。

       論文將高優先級的作業成爲“生產型作業”(prod),將其他稱爲“非生產型作業”(non-prod)。大部分長時間運行的服務都是生產型作業,生產型作業被分配了大約70%的CPU資源並佔用了大約60%的利用率;同時被分配了大約55%的內存資源並佔用了大約85%的內存利用率。

       個人解讀:可以發現,在Google內部,無論是服務型還是批處理型,絕大多數作業都運行在Borg之上,包括其核心產品和非常重要的基礎設施。

       2.2 集羣和單元Cluster and cells

       一個集羣Cluster通常包括一個大規模的單元Cell和若干個小規模的用於測試和特殊目的的單元Cell。Cell的規模大約是10k節點,且機器是異構的。

       個人解讀:集羣Cluster包含若干個單元Cell,單元Cell又包含大量的機器Machine。三者關係示意圖如下圖所示。相比於Cluster和Machine,Cell的概念較爲少見。但其實Cell的概念在工程實踐中比較常見,很多項目在上線之初將Cluster作爲一個整體使用,後來出於某種目的(絕大多數時候是就是爲了測試)又將集羣分爲兩部分使用,這樣集羣就被劃分成爲一個主體Cell和一個用於測試的小Cell,與論文描述一致。可以說,Cell的概念脫胎於實踐,而不是Google拍腦袋想出來的。

wKiom1Ym7N3DkPdpAAGhC9Q7NIA298.jpg

       2.3 作業和任務Jobs and tasks

       一個Borg作業Job具有屬性,包括name、owner、task數量等。Job具有約束(constraint)來強制其任務運行在具有特定屬性的機器上,例如處理器架構、OS版本、IP地址等。約束可以分爲硬約束和軟約束,前者是需求,必須滿足;後者是偏好,儘量滿足。

       個人解讀:文中提到了約束constraint的概念,在集羣調度領域提出約束主要是爲了解決任務和集羣的異構性挑戰。本人在研究和實踐中也一直關注約束,並在工程中應用了自己的相關研究成果。這裏不做過多展開,如果要進一步瞭解約束的概念以及軟硬約束的區別,可以研讀下面兩篇論文:Modelingand Synthesizing Task Placement Constraints in Google Compute Cluster(http://research.google.com/pubs/pub36953.html)和Alsched: Algebraic Scheduling of Mixed Workloads in Heterogeneous Clouds(http://www.pdlNaNu.edu/PDL-FTP/CloudComputing/alsched-socc2012.pdf)。

       每個任務,可以映射爲一個container中的一組Linux程序。Borg絕大部分工作負載不運行在虛擬機中,這主要是由於虛擬機性能開銷較大,此外一些硬件不支持虛擬化。

一個任務也具有屬性,例如資源需求和task index。Borg程序採用靜態鏈接庫,以減少對運行環境的依賴,軟件包中主要包括二進制程序和數據文件。

       個人解讀:在雲平臺工程實踐中,打包和部署是一個難以忽視的重要挑戰。Docker基本上就是憑藉解決部署問題而風靡開源界的。在Docker出現之前,傳統虛擬機(例如KVM、Xen)雖然支持鏡像部署,但是性能開銷較大;輕量級虛擬化(例如LXC和更底層的cgroups)雖然性能開銷小,但是自身不具備鏡像,打包部署瑣碎繁雜。Docker兼具二者優勢,解決了這個問題。

       用戶向Borg發送RPC用以操作作業。用戶可以提交作業、查詢作業,也可以改變作業、任務屬性。作業Job和任務task的狀態圖如下圖所示。用戶可以觸發submit、kill和update事務。

wKiom1Ym7QjDcRz0AADNbwKJWfY464.jpg

       個人解讀:作業Job和任務task的生命週期管理要基於這個狀態圖來實現,特別是錯誤處理,要在狀態圖的基礎上基於事件觸發來實現。例如,在我實現的系統中,當任務finish、fail、kill、lost時,系統會根據特定事件進行專門處理。

       任務Task在被搶佔之前,會收到通知,二者都是通過Unix信號,搶佔通過SIGKILL信號,程序直接退出;通知通過SIGTERM信號,可以被處理。這樣做主要是爲了讓程序關閉前清理環境、保存狀態、完成當前請求等。

       個人解讀:雲平臺需要支持任務“優雅”的退出,Borg不是個例,LXC和Docker也有類似功能。例如,docker stop命令就是優雅退出,其機制與Borg類似;而docker kill則是直接退出。

       2.4 Allocs

       一個Borg alloc是一臺machine上預留資源的集合,可以用於一個或多個任務運行。Alloc被用於爲未來的task預留資源,用來在停止和再次啓動任務之間保持資源,或者將不同作業Job的任務task聚合在一起運行(例如一個web服務器實例和一個相關的logsaver)。

       一個Alloc集合類似一個job:它是在多個機器上預留資源的一組alloc。一旦一個alloc集合被創建,一個或者多個作業Job就可以被提交在其中運行。簡而言之,一個task與一個alloc對應,一個job與一個alloc集合對應。

       個人解讀:Alloc是allocation的簡稱,應該可以理解爲資源分配對應的邏輯單元,或者直接理解爲資源單元。初讀覺得alloc類似container,但是由於一個alloc可以支持一個或多個task運行,因此alloc實際上更類似Kubernetes中的pod(一個pod中包含若干個container)。另外,Kubernetes中沒有Job和Task的概念,我個人感覺Kubernetes中的Service類似於Borg中Job(僅限於服務型Job)的概念,Kubernetes中container類似於Borg中task的概念。當然,僅是類似,說完全相同是不準確的。

       2.5 優先級,配額和准入控制 Priority, quota, and admission control

       每個作業都有一個優先級,具體形式是一個小的正整數。Borg定義非重疊優先級,包括:monitoring, production, batch, and best effort (also known as testing or free),生產型作業(prod job)包含前兩種優先級。

       爲了避免“搶佔洪流”,Borg不允許一個生產型作業區搶佔另一個,只允許生產型作業搶佔非生產型作業。

       資源配額Quota是一組資源量化表達式(CPU、RAM、Disk等),它與一個優先級和一個時間段對應。如果Quota不足,作業提交會被拒絕。

       個人解讀:在我們的工程實踐中,Quota設置沒有如此細粒度,但是基本思路一致。有一點不同需要說明一下,在Borg中如果Quota不足會立即拒絕作業提交;但是在我們的系統中,Quota不足並不影響作業提交,作業會進入等待隊列,待前序作業運行完畢、Quota充足後,系統再自動調度和運行該作業。起初,我對於Borg的設計不是很理解,拒絕提交不是更“麻煩”嗎?後來我思考,我的系統的用戶多是不太熟悉分佈式的應用開發人員,希望我們儘可能的爲他們屏蔽細節,所以我們自動化的進行提交、調度和運行;Borg的用戶是Google開發人員,是高水平的程序員,我猜測他們需要了解一些必要的“細節”來進行後續操作。前者更需要便利,後者更需要靈活,用戶的不同導致系統設計機制的不同。

       2.6 名字服務和監控 Naming and monitoring

       僅僅是創建和放置任務是不夠的,一個服務的客戶端或者其他系統需要找到服務,當服務被重新定位到新機器之後也是如此。爲此,Borg創建了一個穩定的Borg名字服務(BNS),用於爲每個任務命名。任務名字包括cell name、job name和task number這個三元組。Borg將任務的主機名和端口號寫入Chubby中的一致性、高可用文件。Borg也會將作業規模和任務健康信息寫入Chubby,負載均衡器LoadBalancer據此來進行路由。

       個人解讀:名字服務也被稱爲服務發現,通常使用高可用存儲系統(例如Chubby,可以視爲Google內部的Zookeeper,當然現在開源界etcd似乎更火)存儲任務名字與訪問方式endpoint的映射關係。在Borg中,任務名字包括cell name、job name和task number三元組;訪問方式endpoint則是hostname和port二元組。客戶端或其他系統需要訪問服務時,就訪問BNS根據任務名字查詢訪問方式endpoint,以此來“發現”服務。

       每個任務會構建HTTP server來發布其健康信息和性能指標,Borg根據URL來監控任務,並重啓異常任務。

       個人解讀:在我們的工程實踐中,每個任務(更準確說其實是虛擬機)中都會包含一個代理agent,這個代理開機自啓,定時上傳心跳,內含健康信息和性能指標。可以說上傳內容是類似的,但是通信方式是不同的。我們是虛擬機代理定時主動上傳心跳,不過最近感覺“發佈信息,由需要該信息的組件來查詢”這種服務化的通信方式更爲優雅和主流。

 

3 Borg架構 Borg architecture

       一個Borg cell包含一組機器集合、一個邏輯中央控制器Borgmaster、每臺機器上都運行的代理進程Borglet。Borg的所有組件都使用C++開發。

       個人解讀:我們的雲平臺組件也都使用C++開發,基本屬於雲平臺慣例。不過,由於Docker、Kubernetes、etcd等開源系統都是基於Golang開發,我最近正在學習Golang。

wKioL1Ym7X2jx0HpAAL6ddaVgJo719.jpg

       3.1 Borgmaster

       Borgmaster包含兩類進程:主Borgmaster進程和分離的調度器進程。主Borgmaster進程處理客戶端RPC;管理系統中所有對象Object的狀態機,包括machines、tasks、allocs;與Borglet通信;提供webUI。

       Borgmaster邏輯上一個進程,但是擁有5個副本。每個Borgmaster副本維護cell狀態的一份內存副本,cell狀態同時在高可用、分佈式、基於Paxos的存儲系統中做本地磁盤持久化存儲。一個單一的被選舉的master既是Paxos leader,也是狀態管理者。當cell啓動或者被選舉master掛掉時,系統會選舉Borgmaster,選舉機制按照Paxos算法流程進行。

       個人解讀:Borgmaster基於高可用、分佈式、基於Paxos的存儲系統進行元數據持久化和熱Borgmaster備份,以此實現Borg系統的高可用。關於這個基於Paxos的存儲系統,在Google內部應該就是Chubby,不過不知道爲何這裏沒有提及,難道還有新的系統?開源界etcd最近比較火,但是etcd沒有采用Paxos算法,而是使用更爲簡單且易於理解的raft。這裏還是採用Paxos算法,本人暫時還認識不到替代Chubby的必要性。

       Borgmaster的狀態會定時設置checkpoint,具體形式就是在Paxos store中存儲週期性的鏡像snapshot和增量更改日誌。

       3.2 調度Scheduling

       當作業被提交,Borgmaster將其記錄到Paxos store中,並將作業的任務增加到等待隊列中。調度器異步瀏覽該隊列,並將任務分配給機器。調度算法包括兩個部分:可行性檢查和打分。

       可行性檢查,用於找到滿足任務約束、具備足夠可用資源的一組機器;打分,則是在“可行機器”中根據用戶偏好,爲機器打分。用戶偏好主要是系統內置的標準,例如挑選具有任務軟件包的機器、分散任務到不同的失敗域中(出於容錯考慮)。

       個人解讀:在我們的學術研究和工程實踐中,調度也分爲這兩個部分。我們也將這個調度流程和約束有機結合起來,可行性檢查用於處理硬約束,其中具備足夠可用資源也可以看作一種特殊的硬約束;打分用於處理軟約束,符合“儘量滿足軟約束”的原則。

       Borg使用不同的策略進行打分。實踐中,E-PVN(worst fit)會將任務分散到不同的機器上;best fit,會盡量“緊湊”的使用機器,以減少資源碎片。Borg目前使用一種混合模型,儘量減少“受困資源”。

       3.3 Borglet

       Borglet是運行在每臺machine上的本地Borg代理,管理本地的任務和資源。Borgmaster會週期性地向每一個Borglet拉取當前狀態。這樣做更易於Borgmaster控制通信速度,避免“恢復風暴”。

       爲了性能可擴展性,每個Borgmaster副本會運行一個無狀態的link shard去處理與部分Borglet通信。當Borgmaster重新選舉時,會重新分區。Borgmaster副本會聚合和壓縮信息,僅僅向被選舉master報告狀態機的不同部分,以此減少更新負載。

       如果Borglet多輪沒有響應資源查詢,則會被標記爲down。運行其上的任務會被重新調度到其他機器。如果恢復通信,則Borgmaster會通知Borglet殺死已經重新調度的任務,以此保證一致性。

       3.4 規模可擴展性Scalability

       我們不確定Borg中心化架構的可擴展性極限在哪裏;不過到目前爲止,每次接近極限,我們都能設法消除它。一個Borgmaster可以管理數千臺機器,任務到達率約爲每分鐘10K個任務。一個忙碌的Borgmaster使用10-14個CPUcore和50GB內存。

       個人解讀:這句話有點牛啊!對於分佈式領域的關鍵挑戰——可擴展性,Google人員說還沒有真正遇到過極限。這句話的霸氣程度不亞於在酒桌上說“我從來沒醉過”(哈哈哈哈),當然最關鍵的是人家不是嘴炮,人家真的做到了。

       爲了提升可擴展性,我們將調度器分割爲獨立進程,這樣它可以與Borgmaster並行進行操作。調度器具備多個副本,每個調度器在cell狀態的副本上進行操作。它重複以下操作:從被選舉master中檢索狀態變更;更新本地狀態副本;進行調度、分配任務;將分配通知被選舉master。Master會檢查調度器的調度操作,如果發生調度衝突則再下一輪重新調度,否則接受並應用該調度結果。這套機制與Omega一文中的樂觀併發控制高度相似。此外,Borg最近支持爲不同負載類型使用不同調度器。

       個人解讀:Omega的核心思想就是採用樂觀併發控制,使得調度並行化,解決調度器可能成爲集羣系統性能瓶頸的問題,提高系統的可擴展性。根據上述描述,Borg多調度器併發調度採用了這種機制。

       爲了提高系統可擴展性,Borg調度器還作了幾種優化,分別是得分緩存(可以將可行性檢查和打分結果緩存下來)、等價類(同一job中的task通常具有類似的約束,因此可以將多個任務視爲一個等價類)、輕鬆隨機化(在大規模cell中計算所有機器的可行性和得分代價太高,可以隨機遍歷直到找到一個“足夠好”的機器)。


4 可用性 Availability

       失敗在大規模系統中非常常見。本文列舉了Borg提高可用性的例子:

      (1)自動重新調度器被驅逐的任務;

      (2)爲了降低相關失敗,將任務分散到不同的失敗域中;

      (3)限制一個作業中任務的個數和中斷率;

      (4)限制任務重新調度的速率,因爲不能區分大規模機器故障和網絡分區;

      (5)避免引發錯誤的任務-機器匹配對;

      (6)關鍵數據持久化,寫入磁盤。


5 利用率 Utilization

        本節首先通過實驗證明,混合部署(prod負載和non-prod負載)比獨立部署具有更高的利用率。實驗結果下圖。 

wKiom1Y1d0exfwQIAADhj6qvbrA158.jpg      

        隨後,結合實驗說明,幾種方法可以提高集羣利用率,具體包括Cell sharing、Large cell、Fine-grained resource requests和Resource reclamation。前幾種方法都比較直觀,不做展開。Resource reclamation比較有意思,重點闡述。

       一個作業(job)可以定義一個資源上限(resource limit),資源上限用於Borg決定用戶是否具有足夠的資源配額(quota)來提交作業(job),並且用於決定是否具有足夠的空閒資源來調度任務。因爲Borg會kill掉一個嘗試使用更多RAM和disk空間資源(相比於其申請的資源)的task,或者節流CPU資源(相比於其要求的),所以用戶總是申請更多的資源(相比其實際所有的)。此外,一些任務偶爾會使用其所有資源,但大部分時間沒有。

       個人解讀:用戶總是會處於“心理安全”和負載高峯波動等原因,申請較多的資源,但大部分時候,任務不會真正使用如此之多的資源。這就造成了資源浪費。

       對於可以容忍低質量資源的工作(例如批處理作業),Borg會評估任務將使用的資源,並回收空閒資源。這個整個過程稱爲資源回收(resource reclamation)。評估過程稱爲任務預留(task reservation)。最初的預留值與其資源請求一致,然後300秒之後,會慢慢降低到實際使用率外加一個安全邊緣。如果利用率超過資源預留值,預留值會快速增長。

       這裏引用華爲鍾誠的圖片,直觀的表明實際使用資源、預留資源、資源上限的關係。


wKiom1Y1gGTiK89uAAgWfJ4iDG0958.jpg

6 隔離 Isolation

       包括安全隔離和性能隔離,這裏不做展開。


7 相關工作 Related work

        資源調度是熱點研究問題,具有許多相關研究。論文介紹了許多相關係統,我這裏找幾個重點系統進行簡要分析。

        7.1 Mesos

        Mesos通過resourceoffer機制,將資源管理和放置功能分開。Mesos的中央資源管理器(Mesos master)負責資源管理,多個框架(例如Hadoop、Spark)負責具體的任務放置(即任務調度)。Borg採用基於請求(request-offer)的機制,而非基於offer的機制,更易於系統擴展。

        7.2 YARN

        YARN是Hadoop中心化的集羣管理器。每個應用都有一個管理器(AM)用於向中央資源管理器(RM)協商請求資源。這種機制類似於2008年以前Borg爲Google MapReduce分配資源的機制。

        7.3 阿里巴巴Fuxi

        Fuxi不是像Borg那樣把task調度到合適的machine上,而是“反向調度”,爲最近可用的machine匹配任務task。

        7.4 Omega

        Omega支持併發調度,其機制在前文3.4節已經介紹.

        7.5 Kubernetes

        建設Borg的許多工程師正在研發Kubernetes,並將Borg的經驗應用到Kubernetes之中。


8 經驗以及未來工作 Lessons and futurework

       介紹了一些經驗教訓。最後提到Google將繼續改進Borg,並將其中的經驗應用到Kubernetes之中。

       個人解讀:Borg是我一直關注和學習的系統,本文介紹了Borg的許多內容,涉及集羣管理的方方面面,可以說信息量很大。比如,併發調度在本文中僅用了半節來描述,但是本身卻產出了Omega一篇完整的論文。

       另外,Google似乎不喜歡對於其核心繫統進行開源,比如當年的MapReduce、GFS、BigTable、Chubby等都不是Google自行開源,只是開源社區根據其發表論文自己造的“大輪子”。而且大家推測開源版本在實現上可能與Google版本存在不同程度的差距。目前來看,Google也完全沒有開源Borg的苗頭,但是Google開源了Kubernetes(同一撥人搞的,並汲取多年經驗),所以我們在研讀Borg論文之餘,也要投身於Kubernetes的實踐當中啊!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章