Borg的一個主要目的就是有效的利用Google的機器艦隊,這但是一大筆財務投資:讓效率提高几個百分點就能省下幾百萬美圓。這一節討論了和計算了一些Borg使用的技術和策略。shell
咱們的job部署是有資源約束的,並且不多碰到負載高峯,咱們的機器是異構的,咱們從service job回收利用的資源跑batch job。因此,爲了測量咱們須要一個比「平均利用率」更抽象的標準。在作了一些實驗後咱們選擇了cell密度(cell compaction):給定一個負載,咱們不斷的從零開始(這樣能夠避免被一個倒黴的配置卡住),部署到儘量小的Cell裏面去,直到不再能從這個cell裏面抽機器出來。這提供了一個清晰的終止條件,並促進了無陷阱的自動化比較,這裏的陷阱指的是綜合化的工做負載和建模[31]。一個定量的比較和估算技術能夠看[78],有很多微妙的細節。緩存
咱們不可能在線上的cell作性能實驗,因此咱們用了Fauxmaster來達到高保真的模擬效果,使用了真的在線cell的負載數據包括全部的約束、實際限制、保留和經常使用數據($5.5)。這些數據從2014-10-1 14:00 PDT的Borg快照(checkpoints)裏面提取出來。(其餘快照也產生相似的結論)。咱們選取了15個Borg cell來出報告,先排除了特殊目的的、測試的、小的(<5000機器)的cell,而後從剩下的各類量級大小的cell中平均取樣。安全
在壓縮cell實驗中爲了保持機器異構性,咱們隨機選擇去掉的機器。爲了保持工做負載的異構性,咱們保留了全部負載,除了那些對服務和存儲須要有特定需求的。咱們把那些須要超過一半cell的job的硬限制改爲軟的,容許不超過0.2%的task持續的pending若是它們過於挑剔機器;普遍的測試代表這些結果是可重複的。若是咱們須要一個大的cell,就把原cell複製擴大;若是咱們須要更多的cell,就複製幾份cell。app
全部的實驗都每一個cell重複11次,用不一樣的隨機數發生器。在圖上,咱們用一個橫線來表示最少和最多須要的機器,而後選擇90%這個位置做爲結果,平均或者居中的結論不會表明一個系統管理員會作的最優選擇。咱們相信cell壓縮提供了一個公平一致的方式去比較調度策略:好的策略只須要更少的機器來跑相同的負載。框架
咱們的實驗聚焦在調度(打包)某個時間點的一個負載,而不是重放一段長期的工做蹤影。這部分是由於複製一個開放和關閉的隊列模型比較困難,部分是由於傳統的一段時間內跑完的指標和咱們環境的長期跑服務不同,部分是由於這樣比較起來比較明確,部分是由於咱們相信怎麼整都差很少,部分是由於咱們在消費20萬個Borg CPU來作測試——即便在Google的量級,這也不是一個小數目(譯者:就你丫理由多!)ssh
在生產環境下,咱們謹慎的留下了一些頂部空間給負載的增長,好比一些「黑天鵝」時間,負載高峯,機器故障,硬件升級,以及大範圍故障(供電進灰)。圖4顯示了咱們在現實世界中能夠把cell壓縮到多小。上面的基線是用來表示壓縮大小的。工具
幾乎咱們全部的機器都同時跑prod和non-prod的task:在共享Borg cell裏有98%的機器同時跑這2種task,在全部Borg管理的機器裏面有83%同時跑這2種task(咱們有一些專用的Cell跑特定任務)。性能
鑑於不少其餘的組織把面向用戶應用和批處理應用在不一樣的集羣上運行,咱們設想一下若是咱們也這麼幹會發生什麼狀況。圖5展示了在一箇中等大小的Cell上分開跑咱們prod和non-prod的工做負載將須要20-30%多的機器。這是由於prod的job一般會保留一些資源來應對極少發生的負載高峯,但實際上在大多狀況下不會用這些資源。Borg把這批資源回收利用了($5.5)來跑不少non-prod的工做,因此最終咱們只須要更少的機器。測試
大部分Borg cell被幾千個用戶共享使用。圖6展示了爲何。對這個測試,若是一個用戶消費超過了10TiB內存(或100TiB),咱們就把這個用戶的工做負載分離到一個單獨的Cell裏面去。咱們目前的策略展示了它的威力:即便咱們設置了這麼高的閾值(來分離),也須要2-16倍多的Cell,和20-150%多的機器。資源池的方案再次有效地節省了開銷。操作系統
可是,或許把不少不相關的用戶和job類型打包放到一臺機器上,會形成CPU衝突,而後就須要更多的機器進行補償?爲了驗證這一點,咱們看一下在同一臺機器,鎖定時鐘週期,每指令循環數CPI(cycles per instruction)在不一樣環境的task下是怎麼變化的。在這種狀況下,CPI是一個可比較的指標並且能夠表明衝突度量,由於2倍的CPI意味着CPU密集型程序要跑2倍的時間。這些數據是從一週內12000個隨機的prod的task中獲取的,用硬件測量工具[83]取的,而且對採樣作了權重,這樣每秒CPU都是平等的。測試結果不是很是明顯。
咱們發現CPI在同一個時間段內和下面兩個量正相關:這臺機器上總的CPU使用量,以及(強相關)這個機器上同時跑的task數量;每往一臺機器上增長1個task,就會增長0.3%的CPI(線性模型過濾數據);增長一臺10%的CPU使用率,就會增長小於2%的CPI。即便這已是一個統計意義顯著的正相關性,也只是解釋了咱們在CPI度量上看到的5%的變化,還有其餘的因素支配着這個變化,例如應用程序固有的差異和特殊的干涉圖案[24,83]。
比較咱們從共享Cell和少數只跑幾種應用的專用Cell獲取的CPI採樣,咱們看到共享Cell裏面的CPI平均值爲1.58(σ=0.35,方差),專用Cell的CPI平均值是1.53(σ=0.32,方差).也就是說,共享Cell的性能差3%。
爲了搞定不一樣Cell的應用會有不一樣的工做負載,或者會有幸存者誤差(或許對衝突更敏感的程序會被挪到專用Cell裏面去),咱們觀察了Borglet的CPI,在全部Cell的全部機器上都會被運行。咱們發現專用Cell的CPI平均值是1.20(σ=0.29,方差),而共享Cell裏面的CPI平均值爲1.43(σ=0.45,方差),暗示了在專用Cell上運行程序會比在共享Cell上快1.19倍,這就超過了CPU使用量輕負載的這個因素,輕微的有利於專用Cell。
這些實驗肯定了倉庫級別的性能測試是比較微妙的,增強了[51]中的觀察,而且得出了共享並無顯著的增長程序運行的開銷。
不過,就算咱們假設用了咱們結果中最很差的數據,共享仍是有益的:比起CPU的降速,在各個方案裏面減小機器更重要,這會帶來減小全部資源的開銷,包括內存和硬盤,不只僅是CPU。
Google創建了大Cell,爲了容許大的任務運行,也是爲了下降資源碎片。咱們經過把負載從一個cell分到多個小cell上來測試後面那個效應(下降碎片效應),隨機的把job用round-robin方式分配出去。圖7展現了用不少小cell會明顯的須要更多機器。
Borg用戶請求的CPU單位是千分之一核,內存和硬盤單位是byte。(1核是一個CPU的超線程,在不一樣機器類型中的一個通用單位)。圖8展示了這個粒度的好處:CPU核和內存只有少數的「最佳擊球點」,以及這些資源不多的相關性。這個分佈和[68]裏面的基本差很少,除了咱們看到大內存的請求在90%這個線上。
提供一個固定尺寸的容器和虛擬機,在IaaS(infrastructure-as-a-service)提供商裏面或許是比較流行的,但不符合咱們的需求。爲了展示這一點,咱們把CPU核和內存限制作成一個個尺寸,而後把prod的job按照大一點最近的尺寸去跑(取這2個維度的平方值之和最近,也就是2維圖上的直線),0.5核的CPU,1G的內存爲差值。圖9顯示了通常狀況下咱們須要30-50%多的資源來運行。上限來自於把大的task跑在一整臺機器上,這些task即便擴大四倍也沒辦法在原有Cell上壓縮跑。下限是容許這些task等待(pending)。(這比[37]裏面的數據要大100%,由於咱們支持超過4中尺寸並且容許CPU和內存無限擴張)。
一個job能夠聲明一個限制資源,是每一個task能強制保證的資源上限。Borg會先檢查這個限制是否是在用戶的配額內,而後檢查具體的機器是否有那麼多資源來調度這個task。有的用戶會買超過他們須要的配額,也有用戶會的task實際須要更多的資源去跑,由於Borg會殺掉那些須要更多的內存和硬盤空間的task,或者卡住CPU使用率不上去。另外,一些task偶爾須要使用他們的全部資源(例如,在一天的高峯期或者受到了一個拒絕服務攻擊),大多時候用不上那麼多資源。
比起把那些分出來但不用的資源浪費掉,咱們估計了一個task會用多少資源而後把其餘的資源回收再利用給那些能夠忍受低質量資源的工做,例如批處理job。這整個過程被叫作資源再利用(resource reclamation)。這個估值叫作task自留地資源(reservation),被Borgmaster每過幾秒就計算一次,是Borglet抓取的細粒度資源消費用率。最初的自留地資源被設置的和資源限制同樣大;在300s以後,也就是啓動那個階段,自留地資源會緩慢的降低到實際用量加上一個安全值。自留地資源在實際用量超過它的時候會迅速上升。
Borg調度器(scheduler)使用限制資源來計算prod task的可用性($3.2),因此這些task歷來不依賴於回收的資源,也不提供超售的資源;對於non-prod的task,使用了目前運行task的自留地資源,這麼新的task能夠被調度到回收資源。
一臺機器有可能由於自留地預估錯度而致使運行時資源不足 —— 即便全部的task都在限制資源以內跑。若是這種狀況發生了,咱們殺掉或者限制non-prod task,歷來不對prod task下手。
圖10展現了若是沒有資源再利用會須要更多的機器。在一箇中等大小的Cell上大概有20%的工做負載跑在回收資源上。
圖11能夠看到更多的細節,包括回收資源、實際使用資源和限制資源的比例。一個超內存限制的task首先會被從新調度,無論優先級有多高,因此這樣就不多有task會超過內存限制。另外一方面,CPU使用率是能夠輕易被卡住的,因此短時間的超過自留地資源的高峯時沒什麼損害的。
圖11暗示了資源再利用多是不必的保守:在自留地和實際使用中間有一大片差距。爲了測試這一點,咱們選擇了一個生產cell而後調試它的預估參數到一個激進策略上,把安全區劃小點,而後作了一個介於激進和基本之間的中庸策略跑,而後恢復到基本策略。
圖12展示告終果。第二週自留地資源和實際資源的差值是最小的,比第三週要小,最大的是第一和第四周。和預期的同樣,周2和周3的OOM率有一個輕微的提高。在複查了這個結果後,咱們以爲利大於弊,因而把中庸策略的參數放到其餘cell上部署運行。
50%的機器跑9個以上的task;最忙的10%的機器大概跑25個task,4500個線程[83]。雖然在應用間共享機器會增長使用率,也須要一個比較好的機制來保證task之間不互相沖突。包括安全和性能都不能互相沖突。
咱們使用Linux chroot監獄做爲同一臺機器不一樣task之間主要的安全隔離機制。爲了容許遠程debug,咱們之前會分發ssh key來自動給用戶權限去訪問跑他們task的機器,如今不這麼幹了。對大多數用戶來講,如今提供的是borgssh命令,這個程序和Borglet協同,來構建一個ssh shell,這個shell和task運行在一樣的chroot和cgroup下,這樣限制就更加嚴格了。
VM和安全沙箱技術被使用在外部的軟件上,在Google’s AppEngine (GAE) [38]和Google Compute Engine (GCE)環境下。咱們把KVM進程中的每一個hosted VM按照一個Borg task運行。
早期的Borglet使用了一種相對原始粗暴的資源隔離措施:過後內存、硬盤、CPU使用率檢查,而後終止使用過多內存和硬盤的task,或者把用太多CPU的激進task經過Linux CPU優先級降下來。不過,不少粗暴的task仍是很輕易的能影響同臺機器上其餘task的性能,而後不少用戶就會多申請資源來讓Borg減小調度的task數量,而後會致使系統資源利用率下降。資源回收能夠彌補一些損失,但不是所有,由於要保證資源安全紅線。在極端狀況下,用戶請求使用專用的機器或者cell。
目前,全部Borg task都跑在Linux cgroup-based資源容器[17,58,62]裏面,Borglet操做這些容器的設置,這樣就加強了控制由於操做系統內核在起做用。即便這樣,偶爾仍是有低級別的資源衝突(例如內存帶寬和L3緩存污染)仍是會發生,見[60,83]
爲了搞定超負荷和超請求,Borg task有一個應用階級(appclass)。最主要的區分在於延遲敏感latency-sensitive (LS)的應用和其餘應用的區別,其餘應用咱們在文章裏面叫batch。LS task是包括面向用戶的應用和須要快速響應的共享基礎設施。高優先級的LS task獲得最高有待,能夠爲了這個把batch task一次餓個幾秒種。
第二個區分在於可壓縮資源(例如CPU循環,disk I/O帶寬)都是速率性的能夠被回收的,對於一個task能夠下降這些資源的量而不去殺掉task;和不可壓縮資源(例如內存、硬盤空間)這些通常來講不殺掉task就無法回收的。若是一個機器用光了不可壓縮資源,Borglet立刻就會殺掉task,從低優先級開始殺,直到剩下的自留地資源夠用。若是機器用完了可壓縮資源,Borglet會卡住使用率這樣當短時間高峯來到時不用殺掉任何task。若是狀況沒有改善,Borgmaster會從這個機器上去除一個或多個task。
Borglet的用戶空間控制循環在將來預期的基礎上給prod task分配內存,在內存壓力基礎上給non-prod task分配內存;從內核事件來處理Out-of-Memory (OOM);殺掉那些想獲取超過自身限制內存的task,或者在一個超負載的機器上實際超過負載時。Linux的積極文件緩存策略讓咱們的實現更負載一點,由於精確計算內存用量會麻煩不少。
爲了加強性能隔離,LS task能夠獨佔整個物理CPU核,不讓別的LS task來用他們。batch task能夠在任何核上面跑,不過他們只被分配了不多的和LS task共享的資源。Borglet動態的調整貪婪LS task的資源限制來保證他們不會把batch task餓上幾分鐘,有選擇的在須要時使用CFS帶寬控制[75];光有共享是不行的,咱們有多個優先級。
就像Leverich [56],咱們發現標準的Linux CPU調度(CFS)須要大幅調整來支持低延遲和高使用率。爲了減小調度延遲,咱們版本的CFS使用了額外的每cgroup歷史[16],容許LS task驅逐batch task,而且避免多個LS task跑在一個CPU上的調度量子效應(scheduling quantum,譯者:或許指的是互相沖突?)。幸運的是,大多咱們的應用使用的每一個線程處理一個請求模型,這樣就緩和了持久負載不均衡。咱們節儉地使用cpusets來分配CPU核給有特殊延遲需求的應用。這些措施的一部分結果展示在圖13裏面。咱們持續在這方面投入,增長了線程部署和CPU管理包括NUMA超線程、能源覺察(例如[81]),增長Borglet的控制精確度。
Task被容許在他們的限制範圍內消費資源。其中大部分task甚至被容許去使用更多的可壓縮資源例如CPU,充分利用沒有被使用的資源。大概5%的LS task禁止這麼作,主要是爲了增長可預測性;小於1%的batch task也禁止。使用超量內存默認是被禁止的,由於這會增長task被殺的機率,不過即便這樣,10%的LS task打開了這個限制,79%的batch task也開了由於這事MapReduce框架默認的。這事對資源再回收($5.5)的一個補償。Batch task很樂意使用沒有被用起來的內存,也樂意不時的釋放一些可回收的內存:大多狀況下這跑的很好,即便有時候batch task會被急需資源的LS task殺掉。