做者<br />阿里雲容器平臺技術專家 王程<br />阿里雲容器平臺技術專家 張曉宇(衷源)java
<a name="Ga22a"></a>node
不知道你們有沒有過這樣的經歷,當咱們擁有了一套 Kubernetes 集羣,而後開始部署應用的時候,咱們應該給容器分配多少資源呢?很難說。因爲 Kubernetes 本身的機制,咱們能夠理解容器的資源實質上是一個靜態的配置。若是我發發現資源不足,爲了分配給容器更多資源,咱們須要重建 Pod。若是分配冗餘的資源,那麼咱們的 worker node 節點彷佛又部署不了多少容器。試問,咱們能作到容器資源的按需分配嗎?這個問題的答案,咱們能夠在本次分享中和你們一塊兒進行探討。git
首先容許咱們根據咱們的實際狀況拋出咱們實際生產環境的挑戰。或許你們還記的,2018 的天貓雙 11,一天的總成交額達到了 2135 億。由此一斑可窺全豹,可以支撐如此龐大規模的交易量背後的系統,其應用種類和數量應該是怎樣的一種規模。在這種規模下,咱們經常聽到的容器調度,如:容器編排,負載均衡,集羣擴縮容,集羣升級,應用發佈,應用灰度等等這些詞,在被超大規模集羣這個詞修飾後,都再也不是件容易處理的事情。規模自己也就是咱們最大的挑戰。如何運營和管理好這麼一個龐大的系統,並遵循業界 dev-ops 宣傳的那樣效果,猶如讓大象去跳舞。可是馬老師說過,大象就該幹大象該乾的事情,爲何要去跳舞呢。github
<a name="1"></a>web
大象是否能夠跳舞,帶着這個問題,咱們須要從淘寶天貓等 APP 背後系統提及。這套互聯網系統應用部署大體可分爲三個階段,傳統部署,虛擬機部署和容器部署。相比於傳統部署,虛擬機部署有了更好的隔離性和安全性,可是在性能少不可避免的產生了大量損耗。而容器部署又在虛擬機部署實現隔離和安全的背景下,提出了更輕量化的解決方案。咱們的系統也是沿着這麼一條主航道上運行的。假設底層系統比如一艘巨輪,面對巨量的集裝箱---容器,咱們須要一個優秀的船長,對它們進行調度編排,讓系統這艘大船能夠避開層層險阻,操做難度下降,且具有更多靈活性,最終達成航行的目的。算法
<a name="2"></a>數據庫
在開始之初,想到容器化和 Kubernetes 的各類美好場景,咱們理想中的容器編排效果應該是這樣的:api
然而理想很豐滿,現實很骨感。迎接咱們的是雜亂和形態萬千的窘迫。雜亂是由於:做爲一個異軍突起的新型技術棧,不少配套工具和工做流的建設處於初級階段。Demo 版本中運行良好的工具,在真實場景下大規模鋪開,各類隱藏的問題就會暴露無遺,層出不窮。從開發到運維,全部的工做人員都在各類被動地疲於奔命。另外,「大規模鋪開」還意味着,要直接面對形態萬千的生產環境:異構配置的機器,複雜的需求,甚至是適配用戶的既往的使用習慣等等。安全
<br />除了讓人心力交瘁的混亂,系統還面臨着應用容器的各類崩潰問題:內存不足致使的 OOM, CPU quota 分配太少致使的,進程被 throttle,還有帶寬不足,響應時延大幅上升...甚至是交易量在面對訪問高峯時候因爲系統不給力致使的斷崖式下跌等等。這些都使咱們在大規模商用 Kubernetes 場景中積累很是多的經驗。網絡
<a name="3"></a>
<a name="4"></a>
問題總要進行面對的。正如某位高人說過:若是感受哪裏不太對,那麼確定有些地方出問題了。因而咱們就要剖析,問題究竟出在哪裏。針對於內存的 OOM,CPU 資源被 throttle,咱們能夠推斷咱們給與容器分配的初始資源不足。
資源不足就勢必形成整個應用服務穩定性降低的問題。例如上圖的場景:雖然是同一種應用的副本,或許是因爲負載均衡不夠強大,或者是因爲應用自身的緣由,甚至是因爲機器自己是異構的,相同數值的資源,可能對於同一種應用的不一樣副本並具備相等的價值和意義。在數值上他們看似分配了相同的資源,然而在實際負載工做時,極有可能出現的現象是肥瘦不均的。
<br />而在資源 overcommit 的場景下,應用在整個節點資源不足,或是在所在的 CPU share pool 資源不足時,也會出現嚴重的資源競爭關係。資源競爭是對應用穩定性最大的威脅之一。因此咱們要盡力在生產環境中清除全部的威脅。<br />咱們都知道穩定性是件很重要的事情,尤爲對於掌控上百萬容器生殺大權的一線研發人員。或許不經心的一個操做就有可能形成影響面巨大的生產事故。所以,咱們也按照通常流程也作了系統預防和兜底工做。在預防維度,咱們能夠進行全鏈路的壓力測試,而且提早經過科學的手段預判應用須要的副本數和資源量。若是無法準確預算資源,那就只採用冗餘分配資源的方式了。在兜底維度,咱們能夠在大規模訪問流量抵達後,對不緊要的業務作服務降級並同時對主要應用進行臨時擴容。可是對於陡然增長几分鐘的突增流量,這麼多組合拳的花費不菲,彷佛有些不划算。或許咱們能夠提出一些解決方案,達到咱們的預期。
<a name="5"></a>
回顧一下咱們的應用部署狀況:節點上的容器通常分屬多種應用,這些應用自己不必定,也通常不會同時處於訪問的高峯。對於混合部署應用的宿主機,若是能都錯峯分配上面運行容器的資源或許更科學。<br />
應用的資源需求可能就像月亮同樣有陰晴圓缺,有周期變化。例如在線業務,尤爲是交易業務,它們在資源使用上呈現必定的週期性,例如:在凌晨、上午時,它的使用量並非很高而在午間、下午時會比較高。打個比方:對於 A 應用的重要時刻,對於 B 應用可能不那麼重要,適當打壓B應用,騰挪出資源給A應用,這是個不錯的選擇。這聽起來有點像是分時複用的感受。可是若是咱們按照流量峯值時的需求配置資源就會產生大量的浪費。
<br />除了對於實時性要求很高的在線應用外,咱們還有離線應用和實時計算應用等:離線計算對於 CPU 、Memory 或網絡資源的使用以及時間不那麼敏感,因此在任什麼時候間段它均可以運行。實時計算,可能對於時間敏感性就會很高。早期,咱們業務是在不一樣的節點按照應用的類型獨立進行部署。從上面這張圖來看,若是它們進行分時複用資源,針對實時性這個需求層面,咱們會發現它實際的最大使用量不是 2+2+1=5,而是某一時刻重要緊急應用需求量的最大值,也就是 3 。若是咱們可以數據監測到每一個應用的真實使用量,給它分配合理值,那麼就能產生資源利用率提高的實際效果。
對於電商應用,對於採用了重量級 java 框架和相關技術棧的 web 應用,短期內 HPA 或者 VPA 都不是件容易的事情。先說 HPA,咱們或許能夠秒級拉起了 Pod,建立新的容器,然而拉起的容器是否真的可用呢。從建立到可用,可能須要比較久的時間,對於大促和搶購秒殺-這種訪問量「洪峯」可能僅維持幾分鐘或者十幾分鐘的實際場景,若是咱們等到 HPA 的副本所有可用,可能市場活動早已經結束了。至於社區目前的 VPA 場景,刪掉舊 Pod,建立新 Pod,這樣的邏輯更難接受。因此綜合考慮,咱們須要一個更實際的解決方案彌補 HPA 和 VPA 的在這一單機資源調度的空缺。
<a name="6"></a>
<a name="7"></a>
咱們首先要對解決方案設定一個能夠交付的標準:那就是 「既要穩定性,也要利用率,還要自動化實施,固然若是可以智能化那就更好」。<br />而後再交付標準進行細化:
上圖是咱們最初的工具流程設計:當一個應用面臨很高的業務訪問需求時,體如今 CPU、Memory 或其餘資源類型需求量變大,咱們根據 Data Collector 採集的實時基礎數據,利用 Data Aggregator 生成某個容器或整個應用的畫像,再將畫像反饋給 Policy engine。 Policy engine 會瞬時快速修改 容器 Cgroup 文件目錄下的的參數。咱們最先的架構和咱們的想法同樣樸實,在 kubelet 進行了侵入式的修改。雖然咱們只是加了幾個接口,可是這種方式確實不夠優雅。每次 kubenrnetes 升級,對於 Policy engine 相關組件升級也有必定的挑戰。
<br />爲了作到快速迭代並和 Kubelet 解耦,咱們對於實現方式進行了新的演進。那就是將關鍵應用容器化。這樣能夠達到如下功效:
固然在後續演進中,咱們也在嘗試和 HPA,VPA 進行打通,畢竟這些和 Policy engine 是存在着互補的關係。所以咱們架構進一步演進成以下情形。當 Policy engine 在處理一些更多複雜場景搞到無力時,上報事件讓中心端作出更全局的決策。水平擴容或是垂直增長資源。
下面咱們具體討論一下 Policy engine 的設計。Policy engine 是單機節點上進行智能調度並執行 Pod 資源調整的核心組件。它主要包括 api server,指揮中心 command center 和執行層 executor。其中 api server 用於服務外界對於 policy engine 運行狀態的查詢和設置的請求;command center 根據實時的容器畫像和物理機自己的負載以及資源使用狀況,做出 Pod 資源調整的決策。Executor 再根據 command center 的決策,對容器的資源限制進行調整。同時,executor 也把每次調整的 revision info 持久化,以便發生故障時能夠回滾。
指揮中心按期從 data aggregator 獲取容器的實時畫像,包括聚合的統計數據和預測數據,首先判斷節點狀態,例如節點磁盤異常,或者網絡不通,表示該節點已經發生異常,須要保護現場,再也不對Pod進行資源調整,以避免形成系統震盪,影響運維和調試。若是節點狀態正常,指揮中心會策略規則,對容器數據進行再次過濾。好比容器 cpu 率飆高,或者容器的響應時間超過安全閾值。若是條件知足,則對知足條件的容器集合給出資源調整建議,傳遞給executor。
在架構設計上,咱們遵循瞭如下原則:
在資源調整方面,Cgroup 支持咱們對各個容器的 CPU、內存、網絡和磁盤 IO 帶寬資源進行,目前咱們主要對容器的 CPU 資源進行調整,同時在測試中探索在時分複用的場景下動態調整 memory limit 和 swap usage 而避免 OOM 的可行性;在將來咱們將支持對容器的網絡和磁盤 IO 的動態調整。 <a name="9"></a>
<a name="d7WS0"></a>
<br />上圖展現了咱們在測試集羣獲得的一些實驗結果。咱們把高優先級的在線應用和低優先級的離線應用混合部署在測試集羣裏。SLO 是 250ms,咱們但願在線應用的 latency 的 95 百分位值低於閾值 250ms。在實驗結果中能夠看到,在大約90s前,在線應用的負載很低;latency 的均值和百分位都在 250ms 如下。到了 90s後,咱們給在線應用加壓,流量增長,負載也升高,致使在線應用 latency 的 95 百分位值超過了 SLO。在大約 150s 左右,咱們的小步快跑控制策略被觸發,漸進式地 throttle 與在線應用發生資源競爭的離線應用。到了大約 200s 左右,在線應用的性能恢復正常,latency 的 95 百分位回落到 SLO 如下。這說明了咱們的控制策略的有效性。
<a name="10"></a>
下面咱們總結一下在整個項目的進行過程當中,咱們收穫的一些經驗和教訓,但願這些經驗教訓可以對遇到相似問題和場景的人有所幫助。
<a name="G7TgI"></a>
總結起來,咱們的工做主要實現瞭如下幾方面的收益:
展望將來,咱們但願在如下幾個方面增強和擴展咱們的工做:
<a name="RrmTn"></a>
若是你們對於咱們的項目代碼感興趣的話,預計 2019 年 9 月份,咱們的工做也將出如今阿里巴巴開源項目OpenKruise (https://github.com/openkruise)中,敬請期待!