天天看點

在Google使用Borg進行大規模叢集的管理 1-2

谷歌的borg系統群集管理器運作幾十萬個以上的jobs,來自幾千個不同的應用,跨多個叢集,每個叢集有上萬個機器。

它通過管理控制、高效的任務包裝、超售、和程序級别性能隔離實作了高使用率。它支援高可用性應用程式與運作時功能,最大限度地減少故障恢複時間,減少相關故障機率的排程政策。borg簡化了使用者生活,通過提供一個聲明性的工作規範語言,名稱服務內建,實時作業監控,和分析和模拟系統行為的工具。

我們将會展現borg系統架構和特點,重要的設計決策,定量分析它的一些政策,和十年以來的運維經驗和學到的東西。

叢集管理系統我們内部叫borg,它管理、排程、開始、重新開機和監控谷歌運作的應用程式的生命周期。本文介紹它是怎麼做到這些的。

borg提供了三個主要的好處:它(1)隐藏資源管理和故障處理細節,使其使用者可以專注于應用開發;(2)高可靠性和高可用性的操作,并支援應用程式做到高可靠高可用;(3)讓我們在跨數以萬計的機器上有效運作。borg不是第一個來解決這些問題的系統,但它是在這個規模,這種程度的彈性和完整性下運作的為數不多的幾個系統之一。

本文圍繞這些主題來編寫,包括了我們在生産環境運作十年的一些功力。

在Google使用Borg進行大規模叢集的管理 1-2

borg的使用者是谷歌開發人員和系統管理者(網站可靠性工程師 sre),他們運作谷歌應用與服務。使用者以job的方式送出他們的工作給borg,job由一個或多個task組成,每個task含有同樣的二進制程式。一個job在一個borg的cell裡面跑,一個cell是包括了多台機器的單元。這一節主要講使用者視角下的borg系統。

borg cell主要運作兩種異構的工作負載。第一種是長期的服務,應該“永遠”運作下去,并處理短時間的敏感請求(幾微秒到幾百毫秒)。這種服務是面向終端使用者的産品如gmail、google docs、網頁搜尋,内部基礎設施服務(例如,bigtable)。第二種是批處理任務,需要幾秒到幾天來完成,對短期性能波動不敏感。在一個cell上混合運作了這兩種負載,取決于他們的主要租戶(比如說,有些cell就是專門用來跑密集的批處理任務的)。工作負載也随着時間會産生變化:批處理任務做完就好,終端使用者服務的負載是以每天為周期的。borg需要把這兩種情況都處理好。

borg有一個2011年5月的負載資料[80],已經被廣泛的分析了[68,26,27,57,1]。

最近幾年,很多應用架構是搭建在borg上的,包括我們内部的mapreduce[23]、flumejava[18]、millwheel[3]、pregel[59]。這中間的大部分都是有一個控制器,可以送出job。前2個架構類似于yarn的應用管理器[76]。我們的分布式存儲系統,例如gfs[34]和他的後繼者cfs、bigtable[19]、megastore[8]都是跑在borg上的。

在這篇文章裡面,我們把高優先級的borg的jobs定義為生産(prod),剩下的是非生産的(non-prod)。大多長期服務是prod的,大部分批處理任務是non-prod的。在一個典型的cell裡面,prod job配置設定了70%的cpu資源然後實際用了60%;配置設定了55%的記憶體資源然後實際用了85%。在$5.5會展示配置設定和實際值的差是很重要的。

一個cell裡面的所有機器都屬于單個叢集,叢集是由高性能的資料中心級别的光纖網絡連接配接起來的。一個叢集安裝在資料中心的一座樓裡面,n座樓合在一起成為一個site。一個叢集通常包括一個大的cell還有一些小的或測試性質的cell。我們盡量避免任何單點故障。

在測試的cell之外,我們中等大小的cell大概包括10000台機器;一些cell還要大很多。一個cell中的機器在很多方面都是異構的:大小(cpu,ram,disk,network)、處理器類型、性能以及外部ip位址或flash存儲。borg隔離了這些差異,讓使用者單純的選擇用哪個cell來跑任務,配置設定資源、安裝程式和其它依賴、監控系統的健康并在故障時重新開機。

(譯者:cell其實就是邏輯上的叢集)

一個borg的job的屬性有:名字、擁有者和有多少個task。job可以有一些限制,來指定這個job跑在什麼架構的處理器、作業系統版本、是否有外部ip。限制可以是硬的或者軟的。一個job可以指定在另一個job跑完後再開始。一個job隻在一個cell裡面跑。

每個task包括了一組linux程序,跑在一台機器的一個容器内[62]。大部分borg的工作負載沒有跑在虛拟機(vm)裡面,因為我們不想付出虛拟化的代價。而且,borg在設計的時候還沒硬體虛拟化什麼事兒哪。

task也有一些屬性,包括資源用量,在job中的排序。大多task的屬性和job的通用task屬性是一樣的,也可以被覆寫 —— 例如,提供task專用的指令行參數,包括cpu核、記憶體、磁盤空間、磁盤通路速度、tcp端口等等,這些都是可以分别設定并按照一個好的粒度提供。我們不提供固定的資源的單元。borg程式都是靜态編譯的,這樣在跑的環境下就沒有依賴,這些程式都被打成一個包,包括二進制和資料檔案,能被borg安裝起來。

使用者通過rpc來操作borg的job,大多是從指令行工具,或者從我們的監控系統($2.6)。大多job描述檔案是用一種申明式配置檔案bcl -- gcl[12]的一個變種,會産生一個protobuf檔案[67]。bcl有一些自己的關鍵字。gcl提供了lambda表達式來允許計算,這樣就能讓應用在環境裡面調整自己的配置。上萬個bcl配置檔案超過一千行長,系統中累計跑了了千萬行bcl。borg的job配置很類似于aurora配置檔案[6]。

在Google使用Borg進行大規模叢集的管理 1-2

圖2展現了job的和task的狀态機和生命周期。

使用者可以在運作時改變一個job中的task的屬性,通過推送一個新的job配置給borg。這個新的配置指令borg更新task的規格。這就像是跑一個輕量級的,非原子性的事務,而且可以在送出後輕易再改回來。更新是滾動式的,在更新中可以限制task重新開機的數量,如果有太多task停掉,操作可以終止。

一些task更新,例如更新二進制程式,需要task重新開機;另外一些例如修改資源需求和限制會導緻這個機器不适合跑現有的task,需要停止task再重新排程到别的機器上;還有一些例如修改優先級是可以不用重新開機或者移動task的。

task需要能夠接受unix的sigterm信号,在他們被強制發送sigkill之前,這樣就有時間去做清理、儲存狀态、結束現有請求執行、拒絕新請求。實際的notice的delay bound。實踐中,80%的task能正常處理終止信号。

borg的alloc(allocation的縮寫)是在單台機器上的一組保留的資源配額,用來讓一個或更多的task跑;這些資源一直配置設定在那邊,無論有沒有被用。allocs可以被配置設定出來給未來的task,用來保持資源在停止一個task和重新開機這個task之間,用來聚集不同jobs的tasks到同一台機器上——例如一個web server執行個體和附加的,用于把serverurl日志發送到一個分布式檔案系統的日志搜集執行個體。一個alloc的資源管理方式和一台機器上的資源管理方式是類似的;多個tasks在一個alloc上跑并共享資源。如果一個alloc必須被重新定位到其他的機器上,那麼它的task也要跟着重新排程。

一個alloc set就像一個job:它是一組allocs保留了多台機器上的資源。一旦alloc set被建立,一個或多個jobs就可以被送出進去跑。簡而言之,我們會用task來表示一個alloc或者一個top-level task(一個alloc之外的),用job來表示一個job或者alloc set。

當有超量的工作負載在運作的時候會發生什麼事情?我們的解決方案是優先級和配額。

所有job都有優先級,一個小的正整數。高優先級的task可以優先擷取資源,即使後面被殺掉。borg定義了不重疊的優先級段給不同任務用,包括(優先級降序):監控、生産、批任務、高性能(測試或免費)。在這篇文章裡面,prod的jobs是在監控和生産段。

雖然一個降級的task總會在cell的其他地方找到一席之地。降級瀑布也有可能會發生,就是一個task降下來之後,把下面運作的task再擠到别的機器上,如此往複。為了避免這種情況,我們禁止了prod級task互相排擠。合理粒度的優先級在其他場景下也很有用——mapreduce的master跑的優先級比worker高一點,來保證他們的可用性。

優先級是jobs的相對重要性,決定了jobs在一個cell裡面是跑還是等(pending)。配額則是用來決定jobs是否運作被排程。配額就是一組資源(cpu, ram, disk)的數量在一個指定的優先級、一個指定的時間段(月這個量級)。數量決定了這個使用者的job可以用的最多資源(例子:20tb記憶體和prod優先級從現在到7月在xx cell内)。配額檢查是管理控制的一部分,不是排程層的:配額不足的任務在送出的時候就會被拒絕。

高優先級的配額總是花費的比低優先級要多。prod級的配額是被限制為一個cell裡面實際的資源量,是以使用者送出了prod級的job的配額時,可以期待這個job一定會跑,去掉一些碎片外。即使這樣,我們鼓勵使用者多買一點比自己需要多一點的配額,很多使用者超買是因為他們的應用程式的使用者數量增長後需要的配額就大了。對于超買,我們的應對方案是低優先級資源的超售:所有使用者在0優先級都可以用無限的配額,雖然在實際運作中這種情況很難跑起來。一個低優先級的job在資源不足時會保持等(pending)狀态。

配額配置設定在borg系統之外,和我們的實體資源計劃有關。這些資源計劃在不同的資料中心産生不同的價格和配額。使用者jobs隻在有足夠配額和足夠優先級之後才能啟動。配額的使用讓dominant resource fairness(drf)[29, 35, 36, 66]不是那麼必要了。

borg有一個容量系統給一些特殊權限給某些使用者,例如,允許管理者删除或修改cell裡面的job,或者允許使用者區通路特定的核心特性或者讓borg對自己的job不做資源估算($5.5)。

光是建立和部署task是不夠的:一個服務的用戶端和其他系統需要能找到它們,即使它換了個地方。為了搞定這一點,borg創造了一個穩定的“borg name service”(bns)名字給每個task,這個名字包括了cell名字,job名字,和task編号。borg把task的主機名和端口寫入到一個持久化高可用檔案裡,以bns名為檔案名,放在chubby[14]上。這個檔案被我們的rpc系統使用,用來發現task的終端位址。bns名稱也是task的dns名的基礎構成部分,是以,cc cell的ubar使用者的jfoo job的第50個task的dns名稱會是50.jfoo.ubar.cc.borg.google.com。borg同時還會把job的大小和task的健康資訊寫入到chubby在任何情況改變時,這樣負載均衡就能知道怎麼去路由請求了。

幾乎所有的borg的task都會包含一個内置的http服務,用來釋出健康資訊和幾千個性能名額(例如rpc延時)。borg監控這些健康檢查url,把其中響應逾時的和error的task重新開機。其他資料也被監控工具追蹤并在dashboards上展示,當服務級别對象(slo)出問題時就會報警。

使用者可以使用一個名叫sigma的web ui,用來檢查他們所有的job狀态,一個特殊的cell,或者深入到某個job的某個task的資源用率,詳細日志,操作曆史,和最終命運。我們的應用産生大量的日志,都會被自動的滾動來避免塞滿硬碟,會在一個task結束後保留一小段時間用來debug。如果一個job沒有被跑起來,borg會提供一個為什麼挂起的解釋,指導使用者怎麼修改這個job的資源需求來符合目前這個cell的情況。我們釋出資源的使用方針,按照這個方針來做就容易被排程起來。

borg記錄所有的job送出和task時間,以及每task的資源使用細節在基礎存儲服務裡面。這個存儲服務有一個分布式的隻讀的sql-like的互動式接口,通過dremel[61]提供出來。這些資料在實時使用、debug、系統查錯和長期容量規劃上都很有用。這些資料也是google叢集負載追蹤的資料來源之一[80].

所有這些特性幫助使用者了解和debug borg的行為和管理他們的job,并且幫助我們的sre每個人管理超過上萬台機器。

繼續閱讀