Kubernetes架構爲何是這樣的?

小編序:
在上週發佈的《從「鴻溝理論」看雲原生,哪些技術可以跨越鴻溝?》一文中,靈雀雲CTO陳愷表示:Kubernetes在雲計算領域已經成爲既定標準,進入主流市場,最新版本主要關注在穩定性、可擴展性方面,在開發人員中變得很是流行。Kubernetes會愈來愈多往下管理全部基礎設施,往上管理全部種類的應用。咱們會看到,愈來愈多的周邊技術向它靠攏,在其之上催化出一個龐大的雲原生技術生態。html

那麼,如今最新最流行的 Kubernetes 架構是什麼樣子呢?本文給你們介紹一下 Kubernetes 總體架構,並深刻探討其中 2 個比較關鍵的問題。算法

Kubernetes 架構解析數據庫

首先,Kubernetes 的官方架構圖是這樣的:緩存

圖片描述

這個架構圖看起來會比較複雜,很難看懂,我把這個官方的架構圖從新簡化了一下,就會很是容易理解了:服務器

圖片描述

ETCD :是用來存儲全部 Kubernetes 的集羣狀態的,它除了具有狀態存儲的功能,還有事件監聽和訂閱、Leader選舉的功能,所謂事件監聽和訂閱,各個其餘組件通訊,都並非互相調用 API 來完成的,而是把狀態寫入 ETCD(至關於寫入一個消息),其餘組件經過監聽 ETCD 的狀態的的變化(至關於訂閱消息),而後作後續的處理,而後再一次把更新的數據寫入 ETCD。所謂 Leader 選舉,其它一些組件好比 Scheduler,爲了作實現高可用,經過 ETCD 從多個(一般是3個)實例裏面選舉出來一個作Master,其餘都是Standby。架構

API Server:剛纔說了 ETCD 是整個系統的最核心,全部組件之間通訊都須要經過 ETCD,實際上,他們並非直接訪問 ETCD,而是訪問一個代理,這個代理是經過標準的RESTFul API,從新封裝了對 ETCD 接口調用,除此以外,這個代理還實現了一些附加功能,好比身份的認證、緩存等。這個代理就是 API Server。併發

Controller Manager:是實現任務調度的,關於任務調度能夠參考以前的文章,簡單說,直接請求 Kubernetes 作調度的都是任務,好比 Deployment 、Deamon Set 或者 Job,每個任務請求發送給Kubernetes以後,都是由Controller Manager來處理的,每個任務類型對應一個Controller Manager,好比 Deployment對應一個叫作 Deployment Controller,DaemonSet 對應一個 DaemonSet Controller。負載均衡

Scheduler:是用來作資源調度的,Controller Manager會把任務對資源要求,其實就是Pod,寫入到ETCD裏面,Scheduler監聽到有新的資源須要調度(新的Pod),就會根據整個集羣的狀態,給Pod分配到具體的節點上。異步

Kubelet:是一個Agent,運行在每個節點上,它會監聽ETCD中的Pod信息,發現有分配給它所在節點的Pod須要運行,就在節點上運行相應的Pod,而且把狀態更新回到ETCD。分佈式

Kubectl: 是一個命令行工具,它會調用 API Server發送請求寫入狀態到ETCD,或者查詢ETCD的狀態。

若是還以爲不清楚,咱們就用部署服務的例子來解釋一下整個過程。假設要運行一個多實例的Nginx,在Kubernetes內部,整個流程是這樣的:

1.經過kubectl命令行,建立一個包含Nginx的Deployment對象,kubectl會調用 API Server 往ETCD裏面寫入一個 Deployment對象。

2.Deployment Controller 監聽到有新的 Deployment對象被寫入,就獲取到對象信息,根據對象信息來作任務調度,建立對應的 Replica Set 對象。

3.Replica Set Controller監聽到有新的對象被建立,也讀取到對象信息來作任務調度,建立對應的Pod來。

4.Scheduler 監聽到有新的 Pod 被建立,讀取到Pod對象信息,根據集羣狀態將Pod調度到某一個節點上,而後更新Pod(內部操做是將Pod和節點綁定)。

5.Kubelet 監聽到當前的節點被指定了新的Pod,就根據對象信息運行Pod。

這就是Kubernetes內部如何實現整個 Deployment 被建立的過程。這個過程只是爲了向你們解釋每個組件的職責,以及他們之間是如何相互協做的,忽略掉了一些繁瑣的細節。

目前爲止,咱們有已經研究過幾個很是有表明性的調度系統:Hadoop MRv一、YARN、Mesos和Kubernetes。當時學習完這些調度系統的架構後,腦子裏面造成2個大大的疑問:

1.Kubernetes是二次調度的架構麼?和Mesos相比它的擴展性如何?

2.爲何全部調度系統都是沒法橫向擴展的?

後面咱們就針對這兩個問題深刻討論一下。

Kubernetes 是不是二層調度?

在 Google 的一篇關於內部 Omega 調度系統的論文中,將調度系統分紅三類:單體、二層調度和共享狀態三種,按照它的分類方法,一般Google的 Borg被分到單體這一類,Mesos被當作二層調度,而Google本身的Omega被當作第三類「共享狀態」。

論文的做者實際上以前也是Mesos的設計者之一,後來去了Google設計新的 Omega 系統,並發表了論文,論文的主要目的是提出一種全新的「Shard State」的模式,來同時解決調度系統的性能和擴展性問題。但我以爲 Shared State 模型太過理想化,根據這個模型開發的Omega系統,彷佛在Google內部並無被大規模使用,也沒有任何一個大規模使用的調度系統採用 Shared State 模型。

圖片描述

由於Kubernetes的大部分設計是延續 Borg的,並且Kubernetes的核心組件(Controller Manager和Scheduler)缺省也都是綁定部署在一塊兒,狀態也都是存儲在ETCD裏面的,因此一般你們會把Kubernetes也當作「單體」調度系統,實際上我並不贊同。

我認爲 Kubernetes 的調度模型也徹底是二層調度的,和 Mesos 同樣,任務調度和資源的調度是徹底分離的,Controller Manager承擔任務調度的職責,而Scheduler則承擔資源調度的職責。

圖片描述

實際上Kubernetes和Mesos調度的最大區別在於資源調度請求的方式:

主動 Push 方式。是 Mesos 採用的方式,就是 Mesos 的資源調度組件(Mesos Master)主動推送資源 Offer 給 Framework,Framework 不能主動請求資源,只能根據 Offer 的信息來決定接受或者拒絕。

被動 Pull 方式。是 Kubernetes 的方式,資源調度組件 Scheduler 被動的響應 Controller Manager的資源請求。

這兩種方式帶來的不一樣,我主要從一下 5 個方面來分析。另外注意,我所比較二者的優劣,都是從理論上作的分析,工程實現上會有差別,一些指標我也並無實際測試過。

1.資源利用率:Kubernetes 勝出

理論上,Kubernetes 應該能實現更加高效的集羣資源利用率,緣由資源調度的職責徹底是由Scheduler一個組件來完成的,它有充足的信息可以從全局來調配資源,而後而Mesos 卻作不到,由於資源調度的職責被切分到Framework和Mesos Master兩個組件上,Framework 在挑選 Offer 的時候,徹底沒有其餘 Framework 工做負載的信息,因此也不可能作出最優的決策。

舉個例子,好比咱們但願把對耗費 CPU的工做負載和耗費內存的工做負載儘量調度到同一臺主機上,在Mesos裏面不太容易作到,由於他們分屬不一樣的 Framework。

2.擴展性:Mesos勝出

從理論上講,Mesos 的擴展性要更好一點。緣由是Mesos的資源調度方式更容易讓已經存在的任務調度遷移上來。舉個例子,假設已經有了一個任務調度系統,好比 Spark,如今要遷移到集羣調度平臺上,理論上它遷移到 Mesos 比 Kubernetes 上更加容易。

若是遷移到 Mesos ,沒有改變原來的工做流程和邏輯,原來的邏輯是:來了一個做業請求,調度系統把任務拆分紅小的任務,而後從資源池裏面挑選一個節點來運行任務,而且記錄挑選的節點 IP 和端口號,用來跟蹤任務的狀態。遷移到 Mesos 以後,仍是同樣的邏輯,惟一須要變化的是那個資源池,原來是本身管理的資源池,如今變成 Mesos 提供的Offer 列表。

若是遷移到 Kubernetes,則須要修改原來的基本邏輯來適配 Kubernetes,資源的調度徹底須要調用外部的組件來完成,而且這個變成異步的。

3.靈活的任務調度策略:Mesos 勝出

Mesos 對各類任務的調度策略也支持的更好。舉個例子,若是某一個做業,須要 All or Nothing 的策略,Mesos 是可以實現的,可是 Kubernetes 徹底沒法支持。因此All or Nothing 的意思是,價格整個做業若是須要運行 10 個任務,這 10個任務須要可以所有有資源開始執行,不然就一個都不執行。

4.性能:Mesos 勝出

Mesos 的性能應該更好,由於資源調度組件,也就是 Mesos Master 把一部分資源調度的工做甩給 Framework了,承擔的調度工做更加簡單,從數據來看也是這樣,在多年以前 Twitter 本身的 Mesos 集羣就可以管理超過 8萬個節點,而 Kubernetes 1.3 只能支持 5千個節點。

5.調度延遲:Kubernetes 勝出

Kubernetes調度延遲會更好。由於Mesos的輪流給Framework提供Offer機制,致使會浪費不少時間在給不須要資源的 Framework 提供Offer。

爲何不支持橫向擴展?

可能你們已經注意到了,幾乎全部的集羣調度系統都沒法橫向擴展(Scale Out),好比早期的 Hadoop MRv1 的管理節點是單節點,管理的集羣上限是 5000 臺機器,YARN 資源管理節點同時也只能有一個節點工做,其餘都是備份節點,可以管理的機器的上限1萬個節點,Mesos經過優化,一個集羣可以管理 8 萬個節點,Kubernetes 目前的 1.13 版本,集羣管理節點的上限是 5000 個節點。

全部的集羣調度系統的架構都是沒法橫向擴展的,若是須要管理更多的服務器,惟一的辦法就是建立多個集羣。集羣調度系統的架構看起來都是這個樣子的:

圖片描述

中間的 Scheduler(資源調度器)是最核心的組件,雖然一般是由多個(一般是3個)實例組成,可是都是單活的,也就是說只有一個節點工做,其餘節點都處於 Standby 的狀態。爲何會這樣呢?看起來不符合互聯網應用的架構設計原則,如今大部分互聯網的應用經過一些分佈式的技術,可以很容易的實現橫向擴展,好比電商應用,促銷時,經過往集羣裏面添加服務器,就可以提高服務的吞吐量。若是是按照互聯網應用的架構,看起來應該是這樣的:

圖片描述

Scheduler 應該是能夠多活的,有任意多的實例一塊兒對外提供服務,不管是資源的消費者,仍是資源的提供者在訪問 Scheduler 的時候,都須要通過一個負載均衡的組件或者設備,負責把請求分配給某一個 Scheduler 實例。爲何這種架構在集羣調度系統裏面變得不可行麼?爲了理解這件事情,咱們先經過一個互聯網應用的架構的例子,來探討一下具有橫向擴展須要哪些前提條件。

橫向擴展架構的前提條件

假設咱們要實現這樣一個電商系統:

1.這是一個二手書的交易平臺,有很是多的賣家在平臺上提供二手書,咱們暫且把每一本二手書叫作庫存;

2.賣家的每個二手書庫存,根據書的條碼,均可以找到圖書目錄中一本書,咱們把這本書叫作商品;

3.賣家在錄入二手書庫存的時候,除了錄入是屬於哪個商品,同時還須要錄入其餘信息,好比新舊程度、價錢、發貨地址等等。

4.買家瀏覽圖書目錄,選中一本書,而後下單,訂單系統根據買家的要求(價格偏好、送貨地址等),用算法從這本書背後的全部二手書庫存中,匹配一本符合要求的書完成匹配,咱們把這個過程叫訂單匹配好了。

這樣一個系統,從模型上看這個電商系統和集羣調度系統沒啥區別,這個裏面有資源提供者(賣家),提供某種資源(二手書),組成一個資源池(全部二手書),也有資源消費者(買家),提交本身對資源的需求,而後資源調度器(訂單系統)根據算法自動匹配一個資源(一本二手書)。

可是很顯然,這個電商系統是能夠設計成橫向擴展架構的,爲何呢?這個電商系統和集羣調度系統的區別到底在什麼地方? 在回答這個問題以前,咱們先來回答另一個問題:這個電商系統橫向擴展的節點數是否有上限,上限是多少,這個上限是有什麼因素決定的?

系統理論上的併發數量決定了橫向擴展的節點數

假設系統架構設計的時候,不考慮任何物理限制(好比機器的資源大小,帶寬等),可以併發處理 1000個請求,那麼很顯然,橫向擴展的節點數量上限就是1000,由於就算部署了 1001個節點,在任什麼時候候都有一個節點是處於空閒狀態,部署更多的節點已經徹底沒法提升系統的性能。咱們下面須要想清楚的問題其實就變成了:系統理論上可以併發處理請求的數量是多少,是有什麼因素決定的。

系統的併發數量是由「獨立資源池」的數量決定的

「獨立資源池」是我本身造出來的一個詞,由於實在想不到更加合適的。仍是以上面的電商系統爲例,這個訂單系統的理論上可以處理的併發請求(訂購商品請求)數量是由什麼來決定的呢?先看下面的圖:

圖片描述

在訂單系統在匹配需求的時候,實際上應該是這樣運行的,在訂單請求來了以後,根據訂單請求中的購買的商品來排隊,購買同一個商品的請求被放在一個隊列裏面,而後訂單的調度系統開始從隊列裏面依次處理請求,每次作訂單匹配的時候,都需根據當前商品的全部庫存,從裏面挑選一個最佳匹配的庫存。

雖然在實現這個系統的時候,這個隊列不見得是一個消息隊列,可能會是一個關係型數據庫的鎖,好比一個購買《喬布斯傳》的訂單,系統在處理的時候須要先從全部庫存裏面查詢出《喬布斯傳》的庫存,將庫存記錄鎖住,並作訂單匹配且更新庫存(將生成訂單的庫存商品設置爲」不可用」狀態)以後,纔會將數據庫鎖釋放,這時候全部後續購買《喬布斯傳》的訂單請求都在隊列中等待。

也有些系統在實現的時候採用「樂觀鎖」,就是每次訂單處理時,並不會在一開始就鎖住庫存信息,而是在最後一步更新庫存的時候纔會鎖住,若是發生兩個訂單匹配到了同一個庫存物品,那麼其中一個訂單處理就須要徹底放棄而後重試。這兩種實現方式不太同樣,可是本質都是相同的。

因此從上面的討論能夠看出來,之因此全部購買《喬布斯傳》的訂單須要排隊處理,是由於每一次作訂單匹配的時候,須要《喬布斯傳》這個商品的全部庫存信息,而且最後會修改(佔用)一部分庫存信息的狀態。在該訂單匹配的場景裏面,咱們就把《喬布斯傳》的全部庫存信息叫作一個「獨立資源池」,訂單匹配這個「調度系統」的最大併發數量就徹底取決於獨立資源池的數量,也就是商品的數量。咱們假設一下,若是這個二手書的商城只賣《喬布斯傳》一本書,那麼最後全部的請求都須要排隊,這個系統也幾乎是沒法橫向擴展的。

集羣調度系統的「獨立資源池」數量是 1

咱們再來看一下集羣調度系統,每一臺服務器節點都是一個資源,每當資源消費者請求資源的時候,調度系統用來作調度算法的「獨立資源池」是多大呢?答案應該是整個集羣的資源組成的資源池,沒有辦法在切分了,由於:

1.調度系統的職責就是要在全局內找到最優的資源匹配。

2.另外,哪怕不須要找到最優的資源匹配,資源調度器對每一次資源請求,也沒辦法判斷應該從哪一部分資源池中挑選資源。

正是由於這個緣由,「獨立資源池」數量是 1,因此集羣調度系統沒法作到橫向擴展。

相關文章
相關標籤/搜索