天天看點

谷歌Borg論文閱讀筆記(二)——任務混部的解決

總算又往下讀了一部分。google的borg論文中,前面部分講的都是borg的架構。後面有講了一些資源隔離,安全隔離等的技術方案和政策。 主機層面的資源隔離,都是由是borglet來操縱的。

google幾乎所有的機器都是混部的,在一台機器上,可能運作着不同jobs的tasks。根據論文中所說,google的50%的機器運作了9個甚至更多的tasks。90%的機器運作着25個tasks,達到4500個線程。

是以,google有完善的隔離技術來保證task之間不互相影響。目前,google使用的隔離技術是chroot和cgroup。cgroup本來就是google最先送出到核心社群的,應該就是為了解決borg的隔離。

對于外部的軟體,比如gae和gce,google的做法是讓它們運作在虛拟機(kvm)上,kvm程序被作為borg的task運作。也就是說,borg是作為下層的,kvm運作在它之上。

資源共享帶來的問題主要就是兩個,一個是安全,一個是資源之間的性能影響。

系統采用了chroot隔離了檔案系統。對于程式的調試,全都通過borg來操作,borg會讓使用者的指令在和被操作的tasks同一個容器下的shell中運作。

對于性能的影響,google使用了很多技術來減少影響,這個是文章後面詳細講的。這裡主要講的是google對任務混部對cpu性能影響的研究。

google為了評估不同任務部署到同一個機器的cpu幹擾影響做了一個實驗。他們使用cpi(每條計算機指令執行所需的時鐘周期)來衡量性能幹擾。當cpi增加一倍,cpu密集型程式運作時間就會增加一倍,對應于即時相應的程式,可能就是延時增加了一倍。

實驗發現,cpi和2個相同時間間隔的測量成正相關:機器的整體cpu使用率,以及運作在機器上的tasks。

添加一個task到一台機器上,會增加别的任務0.3%的cpi(使用線性模拟合資料)。

增加10%的cpu使用率會增加2%的cpi。

這是cpu密集型的程式測量的結果,事實上幹擾存在于各種資源。

相對而言,專用的cells的cpi要低于混用的cells。據google的統計,共享cells的cpi平均值為1.58(σ = 0.35)。在專用cells中,cpi平均值為1.53(σ = 0.32),cpu性能在共享cells中有大約下降3%。

但這也表明,使用共享的cells并沒有大幅度增加程式運作的成本,而在機器需求方面,共享的cells更節約機器。另外。共享的優勢适用于所有資源,包括記憶體和磁盤,而不僅僅是cpu。當然,google還是有些特别的服務是放在專用的cell上的。

google也對cell的大小進行了評估,發現cell越大越節約機器。

google對jobs是分類為prod和non-prod的。prod指的是面向應用這類jobs,non-prod指的是批處理這類jobs。對于主機上的tasks,則是分為延遲敏感型(latency-sensitive)和批處理(rest)。因為non-prod的jobs中的master應該也是延遲敏感的,是以需要在task上進行分類。

個人了解:non-prod和prod是在borgmaster排程時看的,是一個全局的次元。而latency-sensitive和rest是borglet在主機的task層面上看的,是一個資源配置設定的次元。

另外,borg中,主機的資源其實是超賣的(不然怎麼節約資源),包括可壓縮和不可壓縮的資源。是以,可能會出現所有tasks都沒有超過限制值,而主機資源不足的情況。此時,就需要根據task的分類來進行取舍。

未作特殊說明,下面采用縮寫ls tasks來表示延遲敏感型的任務。

ls tasks用于面向使用者的應用,以及共享設施服務,它需要快速響應請求。高優先的ls tasks享受最好的待遇。能暫時讓批處理饑餓幾秒鐘。

用于離線計算的程序,用于利用那些再生資源。基本是說被kill就被kill。

混部的一大問題是某個資源不足的情形。但是,不同的資源有不同的特點,有的資源能快速調整,而有的則需要很大的代價來調整。是以,borg将資源分為兩大類:可壓縮資源(compressible resources)和不可壓縮資源(non-compressible resources)。

這種資源指的是cpu,磁盤io這類資源。它們是基于比例的,可以通過降低服務品質來調整資源配置設定,這種調整消耗的代價極少,幾乎可以忽略。

可用的方案:

cpu:cgroup中的cpu子系統,可以限流cpu執行周期,也可以調整排程權重。

io:cgroup中的disk子系統,可以在塊裝置層面限流iops和流量。也能在更底層的io排程層調整權重(權重調整隻支援cfq,但是注意cfq并不适合ssd)。

對ls tasks的優待:ls tasks可以保留完整的cpu核心,阻止其它ls tasks使用它們。批處理tasks可以運作在任何cpu核心下,但它被給予相對于ls tasks很小的排程份額。borglet動态調整ls tasks的資源限制,為了確定它不會把批處理tasks餓死幾分鐘,在需要的時候,選擇性的應用cfs控制帶寬。

cfs改進:cgroup中,cpu子系統是依賴于cfs排程算法,這是目前linux的預設任務排程算法。google為了減少排程延時和高使用率,調優了cfs排程程式。另外,google的程式多采用多線程模型,這能減輕持續負載失衡的影響。

允許對ls tasks搶占批處理的tasks。

在多個對ls tasks在一個cpu下運作時,減少排程量。

主機資源超配:如果機器用盡了可壓縮資源,borglet會對某些task進行限流處理(給對ls tasks足夠的資源)。這樣,短負載峰值就可以被處理,而不需要kill掉任何tasks。如果情況沒有改善,borgmaster會從這台機器上遷移掉一些tasks。

這種資源的典型代表就是記憶體,還有就是磁盤容量。此類資源的調整是很難的,比如記憶體,在記憶體不足的時候,linux會進行記憶體回收,該刷盤的刷盤,寫swap的寫swap。如果這還不行,就會進入oom-kill流程。這個代價是很大的。

是以,如果不可壓縮資源不足,就隻能kill掉程序來回收資源,google也是這麼幹的(作業系統也隻能這麼做)。

記憶體:cgroup的memory子系統可以支援限制記憶體使用。cgroup内的記憶體有自己的lru鍊,是以cgroup内部也會自動換頁。此外,在cgroup内的記憶體用盡之時,也會觸發cgroup内的oom-kill流程。另外,系統自身的oom-kill級别是高于cgroup的。

磁盤:這塊不清楚google是怎麼做的,cgroup也沒有支援這個。有的軟體是quota磁盤限額,可以限定檔案夾内使用磁盤空間的大小,超過了就禁止寫入。最早聽說這是間隔掃描的方式,覺得不靠譜,現在應該改進成用inotify了。

主機資源超配:當不可壓縮資源不足時,borglet會從優先級最低的task開始kill,直到資源足夠。

google的資源配置設定是由使用者申請的,使用者可以指定各種資源的所需大小。而不是類似售賣虛拟那樣有固定的規格。

google對此做過實驗,使用固定規格容器,根據cpu核心和記憶體兩個次元的限制,四舍五入到下一個大于等于資源需求的規格。最小規格為0.5個cpu核心,1g記憶體。實驗的結論是,這麼做會增加30%-50%的資源開銷。而且這還是在cell被壓實之前的,壓實後cell的資源開銷更低。此外,cell還能支援cpu和記憶體的獨立伸縮。

每個tasks和資源有3個相關的資料。分别是:申請值,估值,使用值。

申請值:也就是限制值,申請資源時,使用者填寫的值。

估值:borg對程式使用資源量的估計,也被稱為預定(reservation)。一般是使用值加上一定保護緩沖區。

使用值:目前task使用的資源值,是采集的資料。

估值是為了能回收利用那些沒被用到的資源。每過幾秒,borgmaster會進行一次計算。

最初的估值會等于申請值,300秒之後,允許啟動瞬變(startup transients),它會緩慢的向實際使用加上安全邊緣靠攏。如果使用量超過了估值,估值會迅速增加。

borg排程者使用申請值(限制值)來計劃prod tasks(配置設定時按照限制來算),是以它們從不依靠再生資源,也不會超額配置設定資源。對于non-prod tasks,它使用現有tasks的預定,是以新的任務能排程到再生資源(配置設定時按照現有估值來算)。

tasks允許使用資源量通常在限制值内。但隻要主機資源足夠,就可以使用超出限制值的資源。當然,這會增加tasks被kill掉的可能性。當borgmaster配置設定任務時發現資源不足時,它會優先回收超過限制值的tasks的資源。

大多數tasks允許使用可壓縮資源超過限制值。比如cpu,borg以此來利用未被利用的(松弛)資源。在google中,隻有5%的ls task禁止使用資源超過限制值,大概是為了獲得更好的可預測性。隻有少于1%的批處理tasks這麼做(禁止資源使用超過限制值)。

使用記憶體超過限制值預設是被禁止的,因為這增加了task被kill掉的機會。但即使如此,10%的ls tasks重寫了這個(允許記憶體使用超過限制值)。79%的批處理任務這麼做,因為這是mapreduce架構的預設設定。

總的來說,google節約資源其實就是在合理的情況下,對資源進行了超配置設定。因為很多任務其實并不是任何時刻都會用很多資源的。

另外,google對任務和資源進行了分類。總體上,以高優先的ls task為核心,批處理任務以一個填坑的角色來吃掉剩餘的資源。盡可能不kill掉tasks,萬不得已情況下先拿低優先級開刀。

這确實是個很成熟的資源隔離方案,值得借鑒。

繼續閱讀