1. 程式人生 > 程式設計 >美團點評Kubernetes叢集管理實踐

美團點評Kubernetes叢集管理實踐

背景

作為國內領先的生活服務平臺,美團點評很多業務都具有非常顯著、規律的”高峰“和”低谷“特徵。尤其遇到節假日或促銷活動,流量還會在短時間內出現爆發式的增長。這對叢集中心的資源彈性和可用性有非常高的要求,同時也會使系統在支撐業務流量時的複雜度和成本支出呈現指數級增長。而我們需要做的,就是利用有限的資源最大化地提升叢集的吞吐能力,以保障使用者體驗。

本文將介紹美團點評Kubernetes叢集管理與使用實踐,包括美團點評叢集管理與排程系統介紹、Kubernetes管理與實踐、Kubernetes優化與改造以及資源管理與優化等。

美團點評叢集管理與排程系統

美團點評在叢集管理和資源優化這條道路上已經“摸爬滾打”多年。2013年,開始構建基於傳統虛擬化技術的資源交付方式;2015年7月,開始建立完善的叢集管理與排程系統——HULK,目標是推動美團點評服務容器化;2016年,完成基於Docker容器技術自研實現了彈性伸縮能力,來提升交付速度和應對快速擴縮容的需求,實現彈性擴容、縮容,提升資源利用率,提升業務運維效率,合理有效的降低企業IT運維成本;2018年,開始基於Kubernetes來進行資源管理和排程,進一步提升資源的使用效率。

美團點評叢集管理與排程平臺演進

最初,美團點評通過基於Docker容器技術自研實現了彈性伸縮能力,主要是為瞭解決基於虛擬化技術的管理及部署機制在應對服務快速擴容、縮容需求時存在的諸多不足。例如資源例項建立慢、無法統一執行環境、例項部署和交付流程長、資源回收效率低、彈效能力差等等。經過調研與測試,結合業界的實踐經驗,我們決定基於Docker容器技術自研叢集管理與排程系統,有效應對快速擴縮容的需求,提升資源的利用效率。我們把它叫做"綠巨人"——HULK,這個階段可以看作是HULK1.0。

之後,在生產環境中經過不斷摸索和嘗試,我們逐漸意識到,僅僅滿足於叢集的彈性伸縮能力是不夠的,成本和效率肯定是未來必將面臨且更為棘手的問題。我們吸取了2年來HULK 1.0的開發和運維經驗,在架構和支撐系統層面做了進一步優化和改進,並藉助於生態和開源的力量來為HULK賦能,即引入了開源的叢集管理與排程系統Kubernetes,期望能進一步提升叢集管理、執行的效率和穩定性,同時降低資源成本。所以我們從自研平臺轉向了開源的Kubernetes系統,並基於Kubernetes系統打造了更加智慧化的叢集管理與排程系統——HULK2.0。

架構全覽

在架構層面,HULK2.0如何能與上層業務和底層Kubernetes平臺更好地分層和解耦,是我們在設計之初就優先考慮的問題。我們期望它既要能對業務使用友好,又能最大限度地發揮Kubernetes的排程能力,使得業務層和使用方毋需關注資源關係細節,所求即所得;同時使釋出、配置、計費、負載等邏輯層與底層的Kubernetes平臺解耦分層,並保持相容原生Kubernetes API來訪問Kubernetes叢集。從而可以藉助於統一的、主流的、符合業界規範的標準,來解決美團點評基礎架構面臨的複雜的、多樣的、不統一的管理需求。

架構介紹

HULK2.0架構圖

自上而下來看,美團叢集管理與排程平臺面向全公司服務,有各個主要業務線、統一的OPS平臺以及Portal平臺,HULK不可能針對每個平臺定製化介面和解決方案,所以需要將多樣的業務和需求抽象收斂,最終統一通過HULK API來遮蔽HULK系統的細節,做到HULK與上層業務方的解耦。HULK API是對業務層和資源需求的抽象,是外界訪問HULK的唯一途徑。

解決了上層的問題後,我們再來看與下層Kubernetes平臺的解耦。HULK接到上層資源請求後,首先要進行一系列的初始化工作,包括引數校驗、資源餘量、IP和Hostname的分配等等,之後向Kubernetes平臺實際申請分配機器資源,最終將資源交付給使用者,Kubernetes API進一步將資源需求收斂和轉換,讓我們可以藉助於Kubernetes的資源管理優勢。Kubernetes API旨在收斂HULK的資源管理邏輯並與業界主流對齊。此外,因為完全相容Kubernetes API,可以讓我們藉助社群和生態的力量,共同建設和探索。

可以看到,HULK API和Kubernetes API將我們整個系統分為三層,這樣可以讓每一層都專注於各自的模組。

Kubernetes管理與實踐

為什麼會選擇Kubernetes呢?Kubernetes並不是市面上唯一的叢集管理平臺(其他如Docker Swarm或Mesos),之所以選擇它,除了它本身優秀的架構設計,我們更加看重的是Kubernetes提供的不是一個解決方案,而是一個平臺和一種能力。這種能力能夠讓我們真正基於美團點評的實際情況來擴充套件,同時能夠依賴和複用多年來的技術積累,給予我們更多選擇的自由,包括我們可以快速地部署應用程式,而無須面對傳統平臺所具有的風險,動態地擴充套件應用程式以及更好的資源分配策略。

HULK-Kubernetes架構圖

Kubernetes叢集作為整個HULK叢集資源管理與平臺的基礎,需求是穩定性和可擴充套件性,風險可控性和叢集吞吐能力。

叢集運營現狀

  • 叢集規模:10萬+級別線上例項,多地域部署,還在不斷快速增長中。
  • 業務的監控告警:叢集對應用的啟動和狀態資料進行採集,container-init自動整合業務監控資訊,業務程式毋需關注,做到可插拔、可配置。
  • 資源的健康告警:從資源的角度對 Node、Pod和 Container等重要資料監控採集,及時發現它們的狀態資訊,例如 Node不可用、Container不斷重啟等等。
  • 定時巡檢與對賬:每天自動對所有宿主機進行狀態檢查,包括剩餘磁碟量(資料卷)、D程式數量、宿主機狀態等,並對AppKey擴容資料和實際的Pod和容器資料同步校驗,及時發現不一致情況。
  • 叢集資料視覺化:對當前叢集狀態,包括宿主機資源狀態、服務數、Pod數、容器化率、服務狀態、擴縮容資料等等視覺化;並提供了介面化的服務配置、宿主機下線以及Pod遷移操作入口。
  • 容量規劃與預測:提前感知叢集資源狀態,預先準備資源;基於規則和機器學習的方式感知流量和高峰,保證業務正常、穩定、高效地執行。

Kubernetes優化與改造

kube-scheduler效能優化

我們有叢集在使用1.6版本的排程器,隨著叢集規模的不斷增長,舊版本的Kubernetes排程器(1.10之前版本)在效能和穩定性的問題逐漸凸顯,由於排程器的吞吐量低,導致業務擴容超時失敗,在規模近3000臺的叢集上,一次Pod的排程耗時在5s左右。Kubernetes的排程器是佇列化的排程器模型,一旦擴容高峰等待的Pod數量過多就會導致後面Pod的擴容超時。為此,我們對排程器效能進行了大幅度的優化,並取得了非常明顯的提升,根據我們的實際生產環境驗證,效能比優化前提升了400%以上。

Kubernetes排程器工作模型如下:

kube-scheduler示意圖

(kubernetes排程器,圖片來源於網路)

預選失敗中斷機制

一次排程過程在判斷一個 Node是否可作為目標機器時,主要分為三個階段:

  • 預選階段:硬性條件,過濾掉不滿足條件的節點,這個過程稱為 Predicates。這是固定先後順序的一系列過濾條件,任何一個 Predicate不符合則放棄該 Node。
  • 優選階段:軟性條件,對通過的節點按照優先順序排序,稱之為 Priorities。每一個Priority都是一個影響因素,都有一定的權重。
  • 選定階段:從優選列表中選擇優先順序最高的節點,稱為 Select。選擇的Node即為最終部署Pod的機器。

kube-scheduler排程過程

通過深入分析排程過程可以發現,排程器在預選階段即使已經知道當前 Node不符合某個過濾條件仍然會繼續判斷後續的過濾條件是否符合。試想如果有上萬臺 Node節點,這些判斷邏輯會浪費很多計算時間,這也是排程器效能低下的一個重要因素。

為此,我們提出了“預選失敗中斷機制”,即一旦某個預選條件不滿足,那麼該 Node即被立即放棄,後面的預選條件不再做判斷計算,從而大大減少了計算量,排程效能也大大提升。如下圖所示:

kube-scheduler的Predicates過程

我們把該項優化貢獻給了 Kubernetes社群(詳見PR),增加了 alwaysCheckAllPredicates 策略選項,並在 Kubernetes1.10版本釋出並開始作為預設的排程策略,當然你也可以通過設定alwaysCheckAllPredicates=true使用原先的排程策略。

在實際測試中,排程器至少可以提升40%的效能,如果你目前在使用的Kube-scheduler的版本低於1.10,那麼建議你嘗試升級到新的版本。

區域性最優解

對於優化問題尤其是最優化問題,我們總希望找到全域性最優的解或策略,但是當問題的複雜度過高,要考慮的因素和處理的資訊量過多時,我們往往會傾向於接受區域性最優解,因為區域性最優解的質量不一定都是差的。尤其是當我們有確定的評判標準,同時標明得出的解是可以接受的話,通常會接收區域性最優的結果。這樣,從成本、效率等多方面考慮,才是我們在實際工程中真正會採取的策略。

kube-scheduler的區域性最優解

(圖片來源於網路)

當前排程策略中,每次排程排程器都會遍歷叢集中所有的Node,以便找出最優的節點,這在排程領域稱之為BestFit演演算法。但是在生產環境中,我們是選取最優Node還是次優Node,其實並沒有特別大的區別和影響,有時候我們還是會避免選取最優的Node(例如我們叢集為瞭解決新上線機器後頻繁在該機器上建立應用的問題,就將最優解隨機化)。換句話說,找出區域性最優解就能滿足需求。

假設叢集一共1000個Node,一次排程過程PodA,這其中有700個Node都能通過Predicates(預選階段),那麼我們就會把所有的Node遍歷並找出這700個Node,然後經過得分排序找出最優的Node節點NodeX。但是採用區域性最優演演算法,即我們認為只要能找出N個Node,並在這N個Node中選擇得分最高的Node即能滿足需求,比如預設找出100個可以通過Predicates(預選階段)的Node即可,最優解就在這100個Node中選擇。當然全域性最優解NodeX也可能不在這100個Node中,但是我們在這100個Node中選擇最優的NodeY也能滿足要求。最好的情況是遍歷100個Node就找出這100個Node,也可能遍歷了200個或者300個Node等等,這樣我們可以大大減少計算時間,同時也不會對我們的排程結果產生太大的影響。

區域性最優的策略是我們與社群合作共同完成的,這裡面還涉及到如何做到公平排程和計算任務優化的細節(詳見PR1,PR2),該項優化在Kubernetes 1.12版本中釋出,並作為當前預設排程策略,可以大幅度提升排程效能,尤其在大規模叢集中的提升,效果非常明顯。

kubelet改造

風險可控性

前面提到,穩定性和風險可控性對大規模叢集管理來說非常重要。從架構上來看,Kubelet是離真實業務最近的叢集管理元件,我們知道社群版本的Kubelet對本機資源管理有著很大的自主性,試想一下,如果某個業務正在執行,但是Kubelet由於出發了驅逐策略而把這個業務的容器幹掉了會發生什麼?這在我們的叢集中是不應該發生的,所以需要收斂和封鎖Kubelet的自決策能力,它對本機上業務容器的操作都應該從上層平臺發起。

容器重啟策略

Kernel升級是日常的運維操作,在通過重啟宿主機來升級Kernel版本的時候,我們發現宿主機重啟後,上面的容器無法自愈或者自愈後版本不對,這會引發業務的不滿,也造成了我們不小的運維壓力。後來我們為Kubelet增加了一個重啟策略(Reuse),同時保留了原生重啟策略(Rebuild),保證容器系統盤和資料盤的資訊都能保留,宿主機重啟後容器也能自愈。

IP狀態保持

根據美團點評的網路環境,我們自研了CNI外掛,並通過基於Pod唯一標識來申請和複用IP。做到了應用IP在Pod遷移和容器重啟之後也能複用,為業務上線和運維帶來了不少的收益。

限制驅逐策略

我們知道Kubelet擁有節點自動修復的能力,例如在發現異常容器或不合規容器後,會對它們進行驅逐刪除操作,這對於我們來說風險太大,我們允許容器在一些次要因素方面可以不合規。例如當Kubelet發現當前宿主機上容器個數比設定的最大容器個數大時,會挑選驅逐和刪除某些容器,雖然正常情況下不會輕易發生這種問題,但是我們也需要對此進行控制,降低此類風險。

可擴充套件性

資源調配

在Kubelet的擴充套件性方面我們增強了資源的可操作性,例如為容器繫結Numa從而提升應用的穩定性;根據應用等級為容器設定CPUShare,從而調整排程權重;為容器繫結CPUSet等等。

增強容器

我們打通並增強了業務對容器的配置能力,支援業務給自己的容器擴充套件ulimit、io limit、pid limit、swap等引數的同時也增強容器之間的隔離能力。

應用原地升級

大家都知道,Kubernetes預設只要Pod的關鍵資訊有改動,例如映象資訊,就會出發Pod的重建和替換,這在生產環境中代價是很大的,一方面IP和HostName會發生改變,另一方面頻繁的重建也給叢集管理帶來了更多的壓力,甚至還可能導致無法排程成功。為瞭解決該問題,我們打通了自上而下的應用原地升級功能,即可以動態高效地修改應用的資訊,並能在原地(宿主機)進行升級。

映象分發

映象分發是影響容器擴容時長的一個重要環節,我們採取了一系列手段來優化,保證映象分發效率高且穩定:

  • 跨Site同步:保證伺服器總能從就近的映象倉庫拉取到擴容用的映象,減少拉取時間,降低跨Site頻寬消耗。
  • 基礎映象預分發:美團點評的基礎映象是構建業務映象的公共映象。業務映象層是業務的應用程式碼,通常比基礎映象小很多。在容器擴容的時候如果基礎映象已經在本地,就只需要拉取業務映象的部分,可以明顯的加快擴容速度。為達到這樣的效果,我們會把基礎映象事先分發到所有的伺服器上。
  • P2P映象分發:基礎映象預分發在有些場景會導致上千個伺服器同時從映象倉庫拉取映象,對映象倉庫服務和頻寬頻來很大的壓力。因此我們開發了映象P2P分發的功能,伺服器不僅能從映象倉庫中拉取映象,還能從其他伺服器上獲取映象的分片。

資源管理與優化

資源管理與優化

優化關鍵技術

  • 服務畫像:對應用的CPU、記憶體、網路、磁碟和網路 I/O 容量和負載畫像,瞭解應用的特徵、資源規格和應用型別以及不同時間對資源的真實使用,然後從服務角度和時間維度進行相關性分析,從而進行整體排程和部署優化。
  • 親和性和互斥性:哪些應用放在一起使整體計算能力比較少而吞吐能力比較高,它們就存在一定親和性;反之如果應用之間存在資源競爭或相互影響,則它們之間就存在著互斥性。
  • 場景優先:美團點評的業務大都是基本穩定的場景,所以場景劃分很有必要。例如一類業務對延遲非常敏感,即使在高峰時刻也不允許有太多的資源競爭產生,這種場景就要避免和減少資源競爭引起的延遲,保證資源充足;一類業務在有些時間段需要的CPU資源可能會突破配置的上限,我們通過CPU Set化的方式讓這類業務共享這部分資源,以便能夠突破申請規格的機器資源限制,不僅服務能夠獲得更高的效能表現,同時也把空閒的資源利用了起來,資源使用率進一步提升。
  • 彈性伸縮:應用部署做到流量預測、自動伸縮、基於規則的高低峰伸縮以及基於機器學習的伸縮機制。
  • 精細化資源調配:基於資源共享和隔離技術做到了精細化的資源排程和分配,例如Numa繫結、任務優先順序、CPU Set化等等。

策略優化

排程策略的主要作用在兩方面,一方面是按照既定策略部署目標機器;二是能做到叢集資源的排布最優。

  • 親和性:有呼叫關係和依賴的應用,或哪些應用放在一起能使整體計算能力比較少、吞吐能力比較高,這些應用間就存在一定親和性。我們的CPU Set化即是利用了對CPU的偏好構建應用的親和性約束,讓不同CPU偏好的應用互補。
  • 互斥性:跟親和性相對,主要是對有競爭關係或業務幹擾的應用在排程時儘量分開部署。
  • 應用優先順序:應用優先順序的劃分是為我們解決資源競爭提供了前提。當前當容器發生資源競爭時,我們無法決策究竟應該讓誰獲得資源,當有了應用優先順序的概念後,我們可以做到,在排程層,限制單臺宿主機上重要應用的個數,減少單機的資源競爭,也為單機底層解決資源競爭提供可能;在宿主機層,根據應用優先順序分配資源,保證重要應用的資源充足,同時也可執行低優先順序應用。
  • 打散性:應用的打散主要是為了容災,在這裡分為不同級別的打散。我們提供了不同級別的打散粒度,包括宿主機、Tor、機房、Zone等等。
  • 隔離與獨佔:這是一類特殊的應用,必須是獨立使用一臺宿主機或虛擬機器器隔離環境部署,例如搜尋團隊的業務。
  • 特殊資源:特殊資源是滿足某些業務對GPU、SSD、特殊網路卡等特殊硬體需求。

線上叢集優化

線上叢集資源的優化問題,不像離線叢集那樣可以通過預知資源需求從而達到非常好的效果,由於未來需求的未知性,線上叢集很難在資源排布上達到離線叢集的效果。針對線上叢集的問題,我們從上層排程到底層的資源使用都採取了一系列的優化。

  • Numa繫結:主要是解決業務側反饋服務不穩定的問題,通過繫結Numa,將同一個應用的CPU和Memory繫結到最合適的Numa Node上,減少跨Node訪問的開銷,提升應用效能。
  • CPU Set化:將一組特性互補的應用繫結在同一組CPU上,從而讓他們能充分使用CPU資源。
  • 應用錯峰:基於服務畫像資料為應用錯開高峰,減少資源競爭和相互幹擾,提升業務SLA。
  • 重排程:資源排布優化,用更少的資源提升業務效能和SLA;解決碎片問題,提升資源的分配率。
  • 幹擾分析:基於業務監控資料指標和容器資訊判斷哪些容器有異常,提升業務SLA,發現並處理異常應用。

結束語

當前,在以下幾個方面我們正在積極探索:

  • 線上-離線業務混合部署,進一步提升資源使用效率。
  • 智慧化排程,業務流量和資源使用感知排程,提升服務SLA。
  • 高效能、強隔離和更安全的容器技術。

作者簡介

國樑,美團點評基礎研發平臺叢集排程中心高階工程師。

招聘資訊

美團點評基礎研發平臺叢集排程中心,致力於打造高效的業界領先的叢集管理與排程平臺,通過企業級叢集管理平臺建設業界領先的雲化解決方案,提高叢集管理能力和穩定性,同時降低IT成本,加速公司的創新發展。同時隨著Kubernetes已經成為業界的事實標準,美團點評也在逐步擁抱社群,參與開源並且在叢集排程領域已經取得很大進展,也期待和業界同仁一起努力,共同提高叢集管理和排程能力,降低整個行業的IT成本,協同創新發展。美團點評基礎研發平臺長期招聘叢集管理與排程、彈性排程、Kubernetes以及Linux核心方面的人才,有興趣的同學可以傳送簡歷到[email protected]