国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Docker背后的容器集群管理


2015年4月,傳聞許久的Borg論文總算出現(xiàn)在了Google Research的頁面上。雖然傳言Borg作為G家的“老”項目一直是槽點滿滿,而且本身的知名度和影響力也應(yīng)該比不上當(dāng)年的“三大論文”,但是同很多好奇的小伙伴一樣,筆者還是饒有興趣地把這篇“非典型”論文拜讀了一番。

注:本文作者張磊將在8月28日~29日的CNUT全球容器技術(shù)峰會上分享題為《從0到1:Kubernetes實戰(zhàn)》的演講,演講中他將重點剖析Kubernetes的核心原理和實踐經(jīng)驗,并分享大規(guī)模容器集群管理所面臨的問題和解決思路。

1. Borg在講什么故事

其實,如果這篇論文發(fā)表在兩三年前,Borg的關(guān)注度恐怕真沒有今天這么高。作為一篇本質(zhì)上是關(guān)于數(shù)據(jù)中心利用率的半工程、半研究性的成果,這個領(lǐng)域的關(guān)注人群來自大廠的運維部以及系統(tǒng)部的技術(shù)同僚可能要占很大的比例。而對于絕大多數(shù)研究人員,普通開發(fā)者,甚至包括平臺開發(fā)者而言,Borg論文本身的吸引力應(yīng)該說都是比較有限的。

不過,一旦我們把Borg放到當(dāng)前這個時間點上來重新審視,這篇本該平淡的論文就擁有了眾多深層意義。當(dāng)然,這一切絕非偶然,從2013年末以Docker為代表的容器技術(shù)的迅速興起,2014年Google容器管理平臺Kubernetes和Container Engine的強勢擴張,再到如今由Mesos一手打造的DCOS(數(shù)據(jù)中心操作系統(tǒng))概念的炙手可熱。容器技術(shù)令人咋舌的進化速度很快就將一個曾經(jīng)并不需要被大多數(shù)開發(fā)人員關(guān)注的問題擺到了臺面:

我們應(yīng)該如何高效地抽象和管理一個頗具規(guī)模的服務(wù)集群?

這,正是Borg全力闡述的核心問題。

說得更確切一點,當(dāng)我們逐步接納了以容器為單位部署和運行應(yīng)用之后,運維人員終于可以從無休止的包管理,莫名其妙的環(huán)境差異,繁雜重復(fù)的批處理和任務(wù)作業(yè)的中稍微回過一點神來,開始重新審視自己手中的物理資源的組織和調(diào)度方式:即我們能不能將容器看作傳統(tǒng)操作系統(tǒng)的進程,把所有的服務(wù)器集群抽象成為統(tǒng)一的CPU、內(nèi)存、磁盤和網(wǎng)絡(luò)資源,然后按需分配給任務(wù)使用呢?

所以,作為《Docker背后的技術(shù)解析》系列文章的特別篇,筆者將和讀者一起從Borg出發(fā),結(jié)合它的同源項目Kubernetes中嘗試探索一下這個問題的答案。

2. Borg的核心概念

同大多數(shù)PaaS、云平臺類項目宣稱的口號一樣,Borg最基本的出發(fā)點還是“希望能讓開發(fā)者最大可能地把精力集中在業(yè)務(wù)開發(fā)上”,而不需要關(guān)心這些代碼制品的部署細節(jié)。不過,另一方面,Borg非常強調(diào)如何對一個大規(guī)模的服務(wù)器集群做出更合理的抽象,使得開發(fā)者可以像對待一臺PC一樣方便地管理自己的所有任務(wù)。這與Mesos現(xiàn)在主推的觀點是一致的,同時也是Borg同PaaS類項目比如Flynn、Deis、Cloud Foundry等區(qū)別開來的一個主要特征:即Borg,以及Kubernetes和Mesos等,都不是一個面向應(yīng)用的產(chǎn)物。

什么叫面向應(yīng)用?
就是以應(yīng)用為中心。系統(tǒng)原生為用戶提交的制品提供一系列的上傳、構(gòu)建、打包、運行、綁定訪問域名等接管運維過程的功能。這類系統(tǒng)一般會區(qū)分”應(yīng)用“和”服務(wù)“,并且以平臺自己定義的方式為”應(yīng)用“(比如Java程序)提供具體的”服務(wù)“(比如MySQL服務(wù))。面向應(yīng)用是PaaS的一個很重要的特點。

另一方面,Borg強調(diào)的是規(guī)模二字。文章通篇多次強調(diào)了Google內(nèi)部跑在Borg上的作業(yè)數(shù)量、以及被Borg托管的機器數(shù)量之龐大。比如我們傳統(tǒng)認(rèn)知上的“生產(chǎn)級別集群”在文章中基本上屬于Tiny的范疇,而Borg隨便一個Medium的計算單元拿出來都是一家中大型企業(yè)數(shù)據(jù)中心的規(guī)模(10K個機器)。這也應(yīng)證了淘寶畢玄老大曾經(jīng)說過的:“規(guī)模絕對是推動技術(shù)發(fā)展的最關(guān)鍵因素”。

Borg里服務(wù)器的劃分如下: Site = 一組數(shù)據(jù)中心(Cluster), Cluster = 一組計算單元(Cell), Cell = 一組機器。 其中計算單元(Cell)是最常用的集群類別。

2.1 Job,Task

既然Borg不關(guān)心“應(yīng)用”和“服務(wù)”的區(qū)別,也不以應(yīng)用為中心,那么它需要接管和運行的作業(yè)是什么?

Job。

Borg文章里對Job的定義很簡單,就是多個任務(wù)(Task)的集合,而所謂Task就是跑在Linux容器里的應(yīng)用進程了。這樣看起來Job是不是就等同于Kubernetes里的Pod(容器組)呢?

其實不然。Job映射到Kubernetes中的話,其實等同于用戶提交的“應(yīng)用”,至于這個應(yīng)用運行了幾個副本Pod,每個Pod里又運行著哪些容器,用戶并不需要關(guān)心。用戶只知道,我們訪問這個服務(wù),應(yīng)該返回某個結(jié)果,就夠了。

舉個例子,因為高可用等原因,用戶常常會在Kubernetes里創(chuàng)建并啟動若干個一模一樣的Pod(這個功能是通過Kubernetes的Replication Controller實現(xiàn)的)。這些一模一樣的Pod“副本”的各項配置和容器內(nèi)容等都完全相同,他們抽象成一個邏輯上的概念就是Job。

由于Job是一個邏輯上的概念,Borg實際上負責(zé)管理和調(diào)度的實體就是Task。用戶的submit、kill、update操作能夠觸發(fā)Task狀態(tài)機從Pending到Running再到Dead的的轉(zhuǎn)移,這一點論文里有詳細的圖解。值得一提的是,作者還強調(diào)了Task是通過先SIGTERM,一定時間后后再SIGKILL的方式來被殺死的,所以Task在被殺死前有一定時間來進行“清理,保存狀態(tài),結(jié)束正在處理的請求并且拒絕新的請求”的工作。

2.2 Alloc

Borg中,真正與Pod對應(yīng)的概念是Alloc。

Alloc的主要功能,就是在一臺機器上“劃”一塊資源出來,然后一組Task就可以運行在這部分資源上。這樣,“超親密”關(guān)系的Task就可以被分在同一個Alloc里,比如一個“Tomcat應(yīng)用”和它的“l(fā)ogstash服務(wù)”。

Kubernetes中Pod的設(shè)計與Alloc如出一轍:屬于同一個Pod的Docker容器共享Network Namepace和volume,這些容器使用localhost來進行通信,可以共享文件,任何時候都會被當(dāng)作一個整體來進行調(diào)度。

所以,Alloc和Pod的設(shè)計其實都是在遵循“一個容器一個進程”的模型。經(jīng)常有人問,我該如何在Docker容器里跑多個進程?其實,這種需求最好是通過類似Pod這種方法來解決:每個進程都跑在一個單獨的容器里,然后這些容器又同屬于一個Pod,共享網(wǎng)絡(luò)和指定的volume。這樣既能滿足這些進程之間的緊密協(xié)作(比如通過localhost互相訪問,直接進行文件交換),又能保證每個進程不會擠占其他進程的資源,它們還能作為一個整體進行管理和調(diào)度。如果沒有Kubernetes的話,Pod可以使用“Docker in Docker”的辦法來模擬,即使用一個Docker容器作為Pod,真正需要運行的進程作為Docker容器嵌套運行在這個Pod容器中,這樣它們之間互不干涉,又能作為整體進調(diào)度。

另外,Kubernetes實際上沒有Job這個說法,而是直接以Pod和Task來抽象用戶的任務(wù),然后使用相同的Label來標(biāo)記同質(zhì)的Pod副本。這很大程度是因為在Borg中Job Task Alloc的做法里,會出現(xiàn)“交叉”的情況,比如屬于不同Job的Task可能會因為“超親密”關(guān)系被劃分到同一個Alloc中,盡管此時Job只是個邏輯概念,這還是會給系統(tǒng)的管理帶來很多不方便。

2.3 Job的分類

Borg中的Job按照其運行特性劃分為兩類:LRS(Long Running Service)和batch jobs。

上述兩種劃分在傳統(tǒng)的PaaS中也很常見。LRS類服務(wù)就像一個“死循環(huán)”,比如一個Web服務(wù)。它往往需要服務(wù)于用戶或者其它組件,故對延時敏感。當(dāng)然論文里Google舉的LRS例子就要高大上不少,比如Gmail、Google Docs。

而batch jobs類任務(wù)最典型的就是Map-Reduce的job,或者其它類似的計算任務(wù)。它們的執(zhí)行往往需要持續(xù)一段時間,但是最終都會停止,用戶需要搜集并匯總這些job計算得到的結(jié)果或者是job出錯的原因。所以Borg在Google內(nèi)部起到了YARN和Mesos的角色,很多項目通過在Borg之上構(gòu)建framework來提交并執(zhí)行任務(wù)。Borg里面還指出,batch job對服務(wù)器瞬時的性能波動是不敏感的,因為它不會像LRS一樣需要立刻響應(yīng)用戶的請求,這一點可以理解。

比較有意思的是,Borg中大多數(shù)LRS都會被賦予高優(yōu)先級并劃分為生產(chǎn)環(huán)境級別的任務(wù)(prod),而batch job則會被賦予低優(yōu)先級(non-prod)。在實際環(huán)境中,prod任務(wù)會被分配和占用大部分的CPU和內(nèi)存資源。正是由于有了這樣的劃分,Borg的“資源搶占”模型才得以實現(xiàn),即prod任務(wù)可以占用non-prod任務(wù)的資源,這一點我們后面會專門說明。

對比Kubernetes,我們可以發(fā)現(xiàn)在LRS上定義上是與Borg類似的,但是目前Kubernetes卻不能支持batch job:因為對應(yīng)的Job Controller還沒有實現(xiàn)。這意味著當(dāng)前Kubernetes上一個容器中的任務(wù)執(zhí)行完成退出后,會被Replication Controller無條件重啟。Kubernetes尚不能按照用戶的需求去搜集和匯總這些任務(wù)執(zhí)行的結(jié)果。

2.4 優(yōu)先級和配額

前面已經(jīng)提到了Borg任務(wù)優(yōu)先級的存在,這里詳細介紹一下優(yōu)先級的劃分。

Borg中把優(yōu)先級分類為監(jiān)控級、生產(chǎn)級、批任務(wù)級、盡力級(也叫測試級)。其中監(jiān)控級和生產(chǎn)級的任務(wù)就是前面所說的prod任務(wù)。為了避免在搶占資源的過程中出現(xiàn)級聯(lián)的情況觸發(fā)連鎖反應(yīng)(A搶占B,B搶占C,C再搶占D),Borg規(guī)定prod任務(wù)不能互相搶占。

如果說優(yōu)先級決定了當(dāng)前集群里的任務(wù)的重要性,配額則決定了任務(wù)是否被允許運行在這個集群上。

盡管我們都知道,對于容器來說,CGroup中的配額只是一個限制而并非真正割據(jù)的資源量,但是我們必須為集群設(shè)定一個標(biāo)準(zhǔn)來保證提交來任務(wù)不會向集群索要過分多的資源。Borg中配額的描述方法是:該用戶的任務(wù)在一段時間內(nèi)在某一個計算單元上允許請求的最大資源量。需要再次重申,配額一定是任務(wù)提交時就需要驗證的,它是任務(wù)合法性的一部分。

既然是配額,就存在超賣的情況。在Borg中,允許被超賣的是non-prod的任務(wù),即它們在某個計算單元上請求的資源可能超出了允許的額度,但是在允許超賣的情況下它們?nèi)匀挥锌赡鼙幌到y(tǒng)接受(雖然很可能由于資源不足而暫時進入Pending狀態(tài))。而優(yōu)先級最高的任務(wù)則被Borg認(rèn)為是享有無限配額的。

與Kubernetes類似的是,Borg的配額也是管理員靜態(tài)分配的。Kubernetes通過用戶空間(namespace)來實現(xiàn)了一個簡單的多租戶模型,然后為每一個用戶空間指定一定的配額,比如:

apiVersion: v1beta3kind: ResourceQuotametadata:  name: quotaspec:  hard:    cpu: "20"    memory: 10Gi    pods: "10"    replicationcontrollers: "20"    resourcequotas: "1"    services: "5"

到這里,我們有必要多說一句。像Borg、Kubernetes以及Mesos這類項目,它們把系統(tǒng)中所有需要對象都抽象成了一種“資源”保存在各自的分布式鍵值存儲中,而管理員則使用如上所示的“資源描述文件”來進行這些對象的創(chuàng)建和更新。這樣,整個系統(tǒng)的運行都是圍繞著“資源”的增刪改查來完成的,各組件的主循環(huán)遵循著“檢查對象”、“對象變化”、“觸發(fā)事件”、“處理事件”這樣的周期來完成用戶的請求。這樣的系統(tǒng)有著一個明顯的特點就是它們一般都沒有引入一個消息系統(tǒng)來進行事件流的協(xié)作,而是使用“ectd”或者“Zookeeper”作為事件系統(tǒng)的核心部分。

2.5 名字服務(wù)和監(jiān)控

與Mesos等不同,Borg中使用的是自家的一致性存儲項目Chubby來作為分布式協(xié)調(diào)組件。這其中存儲的一個重要內(nèi)容就是為每一個Task保存了一個DNS名字,這樣當(dāng)Task的信息發(fā)生變化時,變更能夠通過Chubby及時更新到Task的負載均衡器。這同Kubernetes通過Watch監(jiān)視etcd中Pod的信息變化來更新服務(wù)代理的原理是一樣的,但是由于使用了名為“Service”的服務(wù)代理機制(Service可以理解為能夠自動更新的負載均衡組件),Kubernetes中默認(rèn)并沒有內(nèi)置名字服務(wù)來進行容器間通信(但是提供了插件式的DNS服務(wù)供管理員選用)。

在監(jiān)控方面,Borg中的所有任務(wù)都設(shè)置了一個健康檢查URL,一旦Borg定期訪問某個Task的URL時發(fā)現(xiàn)返回不符合預(yù)期,這個Task就會被重啟。這個過程同Kubernetes在Pod中設(shè)置health_check是一樣的,比如下面這個例子:

apiVersion: v1beta3kind: Podmetadata:  name: pod-with-healthcheckspec:  containers:    - name: nginx      image: nginx      # defines the health checking      livenessProbe:        # an http probe        httpGet:          path: /_status/healthz          port: 80        # length of time to wait for a pod to initialize        # after pod startup, before applying health checking        initialDelaySeconds: 30        timeoutSeconds: 1      ports:        - containerPort: 80

這種做法的一個小缺點是Task中服務(wù)的開發(fā)者需要自己定義好這些/healthzURL和對應(yīng)的響應(yīng)邏輯。當(dāng)然,另一種做法是可以在容器里內(nèi)置一些“探針”來完成很多健康檢查工作而做到對用戶的開發(fā)過程透明。

除了健康檢查,Borg對日志的處理也很值得借鑒。Borg中Task的日志會在Task退出后保留一段時間,方便用戶進行調(diào)試。相比之下目前大多數(shù)PaaS或者類似項目的容器退出后日志都會立即被刪除(除非用戶專門做了日志存儲服務(wù))。

最后,Borg輕描淡寫地帶過了保存event做審計的功能。這其實與Kubernetes的event功能也很類似,比如Kube的一條event的格式類似于:

發(fā)生時間 結(jié)束時間 重復(fù)次數(shù) 資源名稱 資源類型 子事件 發(fā)起原因 發(fā)起者 事件日志 

3. Borg的架構(gòu)與設(shè)計

Borg的架構(gòu)與Kubernetes的相似度很高,在每一個Cell(工作單元)里,運行著少量Master節(jié)點和大量Worker節(jié)點。其中,Borgmaster負責(zé)響應(yīng)用戶請求以及所有資源對象的調(diào)度管理;而每個工作節(jié)點上運行著一個稱為Borglet的Agent,用來處理來自Master的指令。這樣的設(shè)計與Kubernetes是一致的,Kubernetes這兩種節(jié)點上的工作進程分別是:

Master:apiserver, controller-manager, schedulerMinion:kube-proxy, kubelet

雖然我們不清楚Borg運行著的工作進程有哪些,但單從功能描述里面我們不難推測到至少在Master節(jié)點上兩者的工作進程應(yīng)該是類似的。不過,如果深入到論文中的細節(jié)的話,我們會發(fā)現(xiàn)Borg在Master節(jié)點上的工作要比Kubernetes完善很多。

3.1 Borgmaster

首先,Borgmaster由一個獨立的scheduler和主Borgmaster進程組成。其中,主進程負責(zé)響應(yīng)來自客戶端的RPC請求,并且將這些請求分為“變更類”和“只讀”類。

在這一點上Kubernetes的apiserver處理方法類似,kuber的API服務(wù)被分為“讀寫”(GET,POST,PUT,DELETE)和“只讀”(GET)兩種,分別由6443和7080兩個不同的端口負責(zé)響應(yīng),并且要求“讀寫”端口6443只能以HTTPS方式進行訪問。同樣,Kubernetes的scheduler也是一個單獨的進程。

但是,相比Kubernetes的單點Master,Borgmaster是一個由五個副本組成的集群。每一個副本都在內(nèi)存中都保存了整個Cell的工作狀態(tài),并且使用基于Paxos的Chubby項目來保存這些信息和保證信息的一致性。Borgmaster中的Leader是也是集群創(chuàng)建的時候由Paxos選舉出來的,一旦這個Leader失敗,Chubby將開始新一輪的選舉。論文中指出,這個重選舉到恢復(fù)正常的過程一般耗時10s,但是在比較大的Cell里的集群會由于數(shù)據(jù)量龐大而延長到一分鐘。

更有意思的是,Borgmaster還將某一時刻的狀態(tài)通過定時做快照的方式保存成了checkpoint文件,以便管理員回滾Borgmaster的狀態(tài),從而進行調(diào)試或者其他的分析工作?;谏鲜鰴C制,Borg還設(shè)計了一個稱為Fauxmaster的組件來加載checkpoint文件,從而直接進入某時刻Borgmaster的歷史狀態(tài)。再加上Fauxmaster本身為kubelet的接口實現(xiàn)了“樁”,所以管理員就可以向這個Fauxmaster發(fā)送請求來模擬該歷史狀態(tài)數(shù)據(jù)下Borgmaster的工作情況,重現(xiàn)當(dāng)時線上的系統(tǒng)狀況。這個對于系統(tǒng)調(diào)試來說真的是非常有用。此外,上述Fauxmaster還可以用來做容量規(guī)劃,測試Borg系統(tǒng)本身的變更等等。這個Fauxmaster也是論文中第一處另我們眼前一亮的地方。

上述些特性使得Borg在Master節(jié)點的企業(yè)級特性上明顯比Kubernetes要成熟得多。當(dāng)然,值得期待的是Kube的高可用版本的Master也已經(jīng)進入了最后階段,應(yīng)該很快就能發(fā)布了。

3.2 Borg的調(diào)度機制

用戶給Borg新提交的任務(wù)會被保存在基于Paxos的一致性存儲中并加入到等待隊列。Borg的scheduler會異步地掃描這個隊列中的任務(wù),并檢查當(dāng)前正在被掃描的這個任務(wù)是否可以運行在某臺機器上。上述掃描的順序按照任務(wù)優(yōu)先級從高到低來Round-Robin,這樣能夠保證高優(yōu)先級任務(wù)的可滿足性,避免“線頭阻塞”的發(fā)生(某個任務(wù)一直不能完成調(diào)度導(dǎo)致它后面的所有任務(wù)都必須進行等待)。每掃描到一個任務(wù),Borg即使用調(diào)度算法來考察當(dāng)前Cell中的所有機器,最終選擇一個合適的節(jié)點來運行這個任務(wù)。

此算法分兩階段:

第一,可行性檢查。這個檢查每個機器是所有符合任務(wù)資源需求和其它約束(比如指定的磁盤類型),所以得到的結(jié)果一般是個機器列表。需要注意的是在可行性檢查中,一臺機器“資源是否夠用”會考慮到搶占的情況,這一點我們后面會詳細介紹。

第二,打分。這個過程從上述可行的機器列表中通過打分選擇出分?jǐn)?shù)最高的一個。

這里重點看打分過程。Borg設(shè)計的打分標(biāo)準(zhǔn)有如下幾種:

  1. 盡量避免發(fā)生低優(yōu)先級任務(wù)的資源被搶占;如果避免不了,則讓被搶占的任務(wù)數(shù)量最少、優(yōu)先級最低;
  2. 挑選已經(jīng)安裝了任務(wù)運行所需依賴的機器;
  3. 使任務(wù)盡量分布在不同的高可用域當(dāng)中;
  4. 混合部署高優(yōu)先級和低優(yōu)先級任務(wù),這樣在流量峰值突然出現(xiàn)后,高優(yōu)先級可以搶占低優(yōu)先級的資源(這一點很有意思)。

此行文本用于列表編號,不因該出現(xiàn)在正文中。

Borg其實曾經(jīng)使用過E-PVM模型(簡單的說就是把所有打分規(guī)則按照一定算法綜合成一種規(guī)則)來進行打分的。但是這種調(diào)度的結(jié)果是任務(wù)最終被平均的分散到了所有機器上,并且每臺機器上留出了一定的空閑空間來應(yīng)對壓力峰值。這直接造成了整個集群資源的碎片化。

與上述做法的相反的是另一個極端,即盡量讓所有的機器都填滿。但是這將導(dǎo)致任務(wù)不能很好的應(yīng)對突發(fā)峰值。而且Borg或者用戶對于任務(wù)所需的資源配額的估計往往不是很準(zhǔn)確,尤其是對于batch job來說,它們所請求的資源量默認(rèn)是很少的(特別是CPU資源)。所以在這種調(diào)度策略下batch job會很容易被填充在狹小的資源縫隙中,這時一旦遇到壓力峰值,不僅batch job會出問題,與它運行在同一臺機器上的LRS也會遭殃。

而Borg采用的是“混部加搶占”的模式,這種做法集成了上述兩種模型的優(yōu)點:兼顧公平性和利用率。這其中,LRS和batch job的混部以及優(yōu)先級體系的存在為資源搶占提供了基礎(chǔ)。這樣,Borg在“可行性檢查”階段就可以考慮已經(jīng)在此機器上運行的任務(wù)的資源能被搶占多少。如果算上可以搶占的這部分資源后此機器可以滿足待調(diào)度任務(wù)的需求的話,任務(wù)就會被認(rèn)為“可行”。接下,Borg會按優(yōu)先級低到高“kill”這臺機器上的任務(wù)直到滿足待運行任務(wù)的需求,這就是搶占的具體實施過程。當(dāng)然,被“kill”的任務(wù)會重新進入了調(diào)度隊列,等待重新調(diào)度。

另一方面Borg也指出在任務(wù)調(diào)度并啟動的過程中,安裝依賴包的過程會構(gòu)成80%的啟動延時,所以調(diào)度器會優(yōu)先選擇已經(jīng)安裝好了這些依賴的機器。這讓我想起來以前使用VMware開發(fā)的編排系統(tǒng)BOSH時,它的每一個Job都會通過spec描述自己依賴哪些包,比如GCC。所以當(dāng)時為了節(jié)省時間,我們會在部署開始前使用腳本并發(fā)地在所有目標(biāo)機器上安裝好通用的依賴,比如Ruby、GCC這些,然后才開始真正的部署過程。 事實上,Borg也有一個類似的包分發(fā)的過程,而且使用的是類似BitTorrent的協(xié)議。

這時我們回到Kubernetes上來,不難發(fā)現(xiàn)它與Borg的調(diào)度機制還比較很類似的。這當(dāng)然也就意味著Kubernetes中沒有借鑒傳說中的Omega共享狀態(tài)調(diào)度(反倒是Mesos的Roadmap里出現(xiàn)了類似”樂觀并發(fā)控制“的概念)。

Kubernetes的調(diào)度算法也分為兩個階段:

  • “Predicates過程”:篩選出合格的Minion,類似Borg的“可行性檢查”。這一階段Kubernetes主要需要考察一個Minion的條件包括:
  • 容器申請的主機端口是否可用
  • 其資源是否滿足Pod里所有容器的需求(僅考慮CPU和Memory,且沒有搶占機制)
  • volume是否沖突
  • 是否匹配用戶指定的Label
  • 是不是指定的hostname

“Priorities過程”:對通過上述篩選的Minon打分,這個打分的標(biāo)準(zhǔn)目前很簡單:

  • 選擇資源空閑更多的機器
  • 屬于同一個任務(wù)的副本Pod盡量分布在不同機器上

從調(diào)度算法實現(xiàn)上差異中,我們可以看到Kubernetes與Borg的定位有著明顯的不同。Borg的調(diào)度算法中資源搶占和任務(wù)混部是兩個關(guān)鍵點,這應(yīng)是考慮到了這些策略在Google龐大的機器規(guī)模上所能帶來的巨大的成本削減。所以Borg在算法的設(shè)計上強調(diào)了混部狀態(tài)下對資源分配和任務(wù)分布的優(yōu)化。而Kubernetes明顯想把調(diào)度過程盡量簡化,其兩個階段的調(diào)度依據(jù)都采用了簡單粗暴的硬性資源標(biāo)準(zhǔn),而沒有支持任何搶占策略,也沒有優(yōu)先級的說法。當(dāng)然,有一部分原因是開源項目的用戶一般都喜歡定制自己的調(diào)度算法,從這一點上來說確實是“l(fā)ess is more”??傊罱K的結(jié)果是盡管保留了Borg的影子(畢竟作者很多都是一伙人),Kubernetes調(diào)度器的實現(xiàn)上卻完全是另外一條道路,確切的說更像Swarm這種偏向開發(fā)者的編排項目。

此外,還有一個非常重要的因素不得不提,那就是Docker的鏡像機制。Borg在Google服役期間所使用的Linux容器雖然應(yīng)用極廣且規(guī)模龐大,但核心功能還是LXC的變體或者強化版,強調(diào)的是隔離功能。這一點從它的開源版項目lmctfy的實現(xiàn),以及論文里提到需要考慮任務(wù)依賴包等細節(jié)上我們都可以推斷出來??墒荄ocker的厲害之處就在于直接封裝了整個Job的運行環(huán)境,這使得Kubernetes在調(diào)度時可以不必考慮依賴包的分布情況,并且可以使用Pod這樣的“原子容器組”而不是單個容器作為調(diào)度單位。當(dāng)然,這也提示了我們將來進行Docker容器調(diào)度時,其實也可以把鏡像的分布考慮在內(nèi):比如事先在所有工作節(jié)點上傳基礎(chǔ)鏡像;在打分階段優(yōu)先選擇任務(wù)所需基礎(chǔ)鏡像更完備的節(jié)點。

如果讀者想感受一下沒有鏡像的Docker容器是什么手感,不妨去試用一下DockerCon上剛剛官宣的runc項目(https://github.com/opencontainers/runc)。runc完全是一個libcontainer的直接封裝,提供所有的Docker容器必備功能,但是沒有鏡像的概念(即用戶需要自己指定rootfs環(huán)境),這十分貼近lmctfy等僅專注于隔離環(huán)境的容器項目。

3.3 Borglet

離開了Borgmaster節(jié)點,我們接下來看一下工作節(jié)點上的Borglet組件,它的主要工作包括:

啟停容器,進行容器失敗恢復(fù),通過kernel參數(shù)操作和管理OS資源,清理系統(tǒng)日志,收集機器狀態(tài)供Borgmaster及其他監(jiān)控方使用。

這個過程中,Borgmaster會通過定期輪詢來檢查機器的狀態(tài)。這種主動poll的做法好處是能夠大量Borglet主動匯報狀態(tài)造成流量擁塞,并且能防止“恢復(fù)風(fēng)暴”(比如大量失敗后恢復(fù)過來的機器會在同段一時間不停地向Borgmaster發(fā)送大量的恢復(fù)數(shù)據(jù)和請求,如果沒有合理的擁塞控制手段,者很可能會阻塞整個網(wǎng)絡(luò)或者直接把master拖垮掉)。一旦收到匯報信息后,充當(dāng)leader的Borgmaster會根據(jù)這些信息更新自己持有的Cell狀態(tài)數(shù)據(jù)。

這個過程里,集群Borgmaster的“優(yōu)越性”再次得到了體現(xiàn)。Borgmaster的每個節(jié)點維護了一份無狀態(tài)的“鏈接分片(link shard)”。每個分片只負責(zé)一部分Borglet機器的狀態(tài)檢查,而不是整個Cell。而且這些分片還能夠匯集并diif這些狀態(tài)信息,最后只讓leader獲知并更新那些發(fā)生了變化的數(shù)據(jù)。這種做法有效地降低了Borgmaster的工作負載。

當(dāng)然,如果一個Borglet在幾個poll周期內(nèi)都沒有回應(yīng),他就會被認(rèn)為宕機了。原本運行在整個節(jié)點上的任務(wù)容器會進入重調(diào)度周期。如果此期間Borglet與master的通信恢復(fù)了,那么master會請求殺死那些被重調(diào)度的任務(wù)容器,以防重復(fù)。Borglet的運行并不需要依賴于Borgmaster,及時master全部宕機,任務(wù)依然可以正常運行。

與Borg相比,Kubernetes則選擇了方向相反的狀態(tài)匯報策略。當(dāng)一個kubelet進程啟動后,它會主動將自己注冊給master節(jié)點上的apiserver。接下來,kubelet會定期向apiserver更新自己對應(yīng)的node的信息,如果一段時間內(nèi)沒有更新,則master就會認(rèn)為此工作節(jié)點已經(jīng)發(fā)生故障。上述匯報信息的收集主要依賴于每個節(jié)點上運行的CAdvisor進程,而并非直接與操作系統(tǒng)進行交互。

事實上,不止kubelet進程會這么做。Kubernetes里的所有組件協(xié)作,都會采用主動去跟apiServer建立聯(lián)系,進而通過apiserver來監(jiān)視、操作etcd的資源來完成相應(yīng)的功能。

舉個例子,用戶向apiserver發(fā)起請求表示要創(chuàng)建一個Pod,在調(diào)度器選擇好了某個可用的minion后apiserver并不會直接告訴kubelet說我要在這個機器上創(chuàng)建容器,而是會間接在etcd中創(chuàng)建一個“boundPod”對象(這個對象的意思是我要在某個kubelet機器上綁定并運行某個Pod)。與此同時,kubelet則定時地主動檢查有沒有跟自己有關(guān)的“boundPod”,一旦發(fā)現(xiàn)有,它就會按照這個對象保存的信息向Docker Daemon發(fā)起創(chuàng)建容器的請求。

這正是Kubernetes設(shè)計中“一切皆資源”的體現(xiàn),即所有實體對象,消息等都是作為etcd里保存起來的一種資源來對待,其他所有協(xié)作者要么通過監(jiān)視這些資源的變化來采取動作,要么就是通過apiserver來對這些資源進行增刪改查。

所以,我們可以把Kubernetes的實現(xiàn)方法描述為“面向etcd的編程模式”。這也是Kubernetes與Borg設(shè)計上的又一個不同點,說到底還是規(guī)模存在的差異:即Kubernetes認(rèn)為它管理的集群中不會存在那么多機器同時向apiserver發(fā)起大量的請求。這也從另一個方面表現(xiàn)出了作者們對etcd響應(yīng)能力還是比較有信心的。

3.4 可擴展性

這一節(jié)里與其說在Borg的可擴展性,倒不如說在講它如何通過各種優(yōu)化實現(xiàn)了更高的可擴展性。

首先是對Borgmaster的改進。最初的Borgmaster就是一個同步循環(huán),在循環(huán)過程中順序進行用戶請求響應(yīng)、調(diào)度、同Borglet交互等動作。所以Borg的第一個改進就是將調(diào)度器獨立出來,從而能夠同其他動作并行執(zhí)行。改進后的調(diào)度器使用Cell集群狀態(tài)的緩存數(shù)據(jù)來不斷重復(fù)以下操作:

  • 從Borgmaster接受集群的狀態(tài)變化
  • 更新本地的集群狀態(tài)緩存數(shù)據(jù)
  • 對指定的Task執(zhí)行調(diào)度工作
  • 將調(diào)度結(jié)果告訴Borgmaster

這些操作組成了調(diào)度器的完整工作周期。

其次,Borgmaster上負責(zé)響應(yīng)只讀請求和同Borglet進行交互的進程也被獨立出來,通過職責(zé)的單一性來保證各自的執(zhí)行效率。這些進程會被分配在Borgmaster的不同副本節(jié)點上來進一步提高效率(只負責(zé)同本副本節(jié)點所管理的那部分Worker節(jié)點進行交互)。

最后是專門針對調(diào)度器的優(yōu)化。

緩存機器的打分結(jié)果。畢竟每次調(diào)度都給所有機器重新打一次分確實很無聊。只有當(dāng)機器信息或者Task發(fā)生了變化(比如任務(wù)被從這個機器上調(diào)度走了)時,調(diào)度器緩存的機器分?jǐn)?shù)才會發(fā)生更新。而且,Borg會忽略那些不太明顯的資源變化,減少緩存的更新次數(shù)。

劃分Task等價類。Borg的調(diào)度算法針對的是一組需求和約束都一樣的Task(等價類)而不是單個Task來執(zhí)行的。

隨機選擇一組機器來做調(diào)度。這是很有意思的一種做法,即Borg調(diào)度器并不會把Cell里的所有機器拿過來挨個進行可行性檢查,而是不斷地隨機挑選一個機器來檢查可行性,判斷是否通過,再挑選下一個,直到通過篩選的機器達到一定的數(shù)目。然后再在這些通過篩選的機器集合里進行打分過程。這個策略與著名的Sparrow調(diào)度器的做法很類似。

這些優(yōu)化方法大大提高了Borg的工作效率,作者在論文中指出在上述功能被禁掉,有些原來幾百秒完成的調(diào)度工作需要幾天才能完全完成。

4. 可用性

Borg在提高可用性方面所做的努力與大多數(shù)分布式系統(tǒng)的做法相同。比如:

  • 自動重調(diào)度失敗的任務(wù)
  • 將同一Job的不同任務(wù)分布在不同的高可用域
  • 在機器或者操作系統(tǒng)升級的過程中限制允許的任務(wù)中斷的次數(shù)和同時中斷的任務(wù)數(shù)量
  • 保證操作的冪等性,這樣當(dāng)客戶端失敗時它可以放心的發(fā)起重試操作
  • 當(dāng)一臺機器失聯(lián)后,任務(wù)重調(diào)度的速度會被加以限制,因為Borg不能確定失聯(lián)的原因是大規(guī)模的機器失?。ū热鐢嚯姡€是部分網(wǎng)絡(luò)錯誤。
  • 任務(wù)失敗后,在一段時間內(nèi)在本地磁盤保留日志及其他關(guān)鍵數(shù)據(jù),哪怕對應(yīng)的任務(wù)已經(jīng)被殺死或者調(diào)度到其他地方了

最后也是最重要的,Borglet的運行不依賴于master,所以哪怕控制節(jié)點全部宕機,用戶提交的任務(wù)依然正常運行。

在這一部分,Kubernetes也沒有特別的設(shè)計。畢竟,在任務(wù)都已經(jīng)容器化的情況下,只要正確地處理好容器的調(diào)度和管理工作,任務(wù)級別高可用的達成并不算十分困難。

至此,論文的前四章我們就介紹完了。通過與Kubernetes的實現(xiàn)作比較,我們似乎能得到一個“貌合神離”的結(jié)論。即Kubernetes與Borg從表面上看非常相似:相同的架構(gòu),相似的調(diào)度算法,當(dāng)然還有同一伙開發(fā)人員。但是一旦我們?nèi)ド钊胍恍┘毠?jié)就會發(fā)現(xiàn),在某些重要的設(shè)計和實現(xiàn)上,Borg似乎有著和Kubernetes截然不同的認(rèn)識:比如完全相反的資源匯報方向,復(fù)雜度根本不在一個水平上的Master實現(xiàn)(集群VS單點),對batch job的支持(Kubernetes目前不支持batch job),對于任務(wù)優(yōu)先級和資源搶占的看法等等。

這些本來可以照搬的東西,為什么在Kubernetes又被重新設(shè)計了一遍呢?在本文的第二部分,我們將一步步帶領(lǐng)讀者領(lǐng)悟造成這些差異的原因,即:資源回收和利用率優(yōu)化。敬請關(guān)注。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Serverless 如何應(yīng)對 K8s 在離線場景下的資源供給訴求
google集群操作系統(tǒng)borg
Docker背后的容器集群管理——從Borg到Kubernetes(二)
Kubernetes K8S之調(diào)度器kube-scheduler詳解
Kubernetes調(diào)度詳解
K8s 實踐 | 如何解決多租戶集群的安全隔離問題?
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服