TKE團隊負責公有云,私有云場景下近萬個集羣,數百萬核節點的運維管理工做。爲了監控規模如此龐大的集羣聯邦,TKE團隊在原生Prometheus的基礎上進行了大量探索與改進,研發出一套可擴展,高可用且兼容原生配置的Prometheus集羣系統,理論上可支持無限的series數目和存儲容量,支持納管TKE集羣,EKS集羣以及自建K8s集羣的監控訴求。node
本文從TKE的架構出發,逐步介紹了整個監控系統的演進過程,包括早期的方案和遇到的問題,社區方案的瓶頸,咱們的改進原理等。web
爲了讓讀者更好理解咱們的場景,咱們首先簡單介紹一下TKE的基礎架構。算法
TKE團隊是公有云界首家採用Kubernetes in Kubernetes進行集羣聯邦管理的Kubernetes運營團隊,其核心思想就是用一個Meta Cluster來託管其餘集羣的apiserver,controller-manager,scheduler,監控套件等非業務組件,在Meta Cluster中的組件對用戶而言是隱藏的,以下圖所示。api
上圖Meta Cluster中的組件對於用戶而言都是隱藏的。支撐環境服務用於直接處理來至TKE控制檯的請求。緩存
TKE早期監控方案不支持用戶添加業務相關的監控指標,只包括集羣運維關注的監控,主要但願監控的目標以下:架構
在上一節的TKE架構圖中,咱們在Meta Cluster中看到每一個集羣有一套Cluster-monitor組件,該組件就是單集羣級別的監控採集套件。Cluster-monitor包含了以Prometheus爲核心的一系列組件,其基本功能就是採集每一個用戶集羣的基礎監控數據,例如Pod負載,Deployment負載,Node CPU使用率等,採集到的數據將直接寫到雲監控團隊提供的Argus系統中存儲於告警。核心組件以下圖。併發
Barad:雲監控提供的多維監控系統,是雲上其餘服務主要使用的監控系統,其相對成熟穩定,可是不靈活,指標和label都須要提早在系統上設置好。負載均衡
Argus:雲監控團隊提供的多維業務監控系統,其特色是支持較爲靈活的指標上報機制和強大的告警能力。這是TKE團隊主要使用的監控系統。運維
數據流:ide
這部分數據將經過控制檯輸出給用戶
成功採集到了屬於每一個用戶集羣的數據,可是,對於一些地域級別的監控,包括
經過單個Cluster-monitor沒法採集。須要構建更上一級的地域級別監控。
Region Prometheus不只拉取如meta cluster operator,meta cluster service controller等核心組件的數據外,還經過Prometheus聯邦接口拉取Cluster-monitor中的單集羣數據進行二次聚合,產生地域級別集羣的數據。地域級別數據直接存在本地,不寫往Argus,由於這部分數據須要對接Grafana,由團隊內部使用。
咱們在單地域監控的基礎上又構建了一層全網級別的監控。用於監控
全網數據也是給內部人員查看。
上述介紹的架構雖然解決了咱們對於大規模集羣聯邦的基本監控訴求,可是依舊存在幾點不足。
原生Prometheus並不支持高可用,也不能作橫向擴縮容,當集羣規模較大時,單一Prometheus會出現性能瓶頸,沒法正常採集數據,咱們將在後續章節中給出Prometheus的壓測數據。
目前採集週期是1m,咱們但願能下降到15s。
因爲雲監控所能提供的Argus系統的聚合能力有限,咱們並無將Cluster-monitor採集到的數據直接輸出到Argus,而是將數據按預約的指標進行聚合,只發送聚合過的數據,TKE控制檯在數據展現時只作時間上的聚合。而原始數據咱們只保存15分鐘。若是加長時間進行本地存儲,咱們須要爲每一個Cluster-monitor部署雲硬盤,因爲TKE存在部分空集羣(節點個數爲0),這會產生資源浪費。
因爲每一個集羣的數據都是本地落盤,Region Prometheus因爲性能有限的緣由,只採集了部分聚合指標,使得沒法進行跨集羣原始數據的聚合查詢,而這類查詢對於獲取單用戶多集羣的綜合數據是頗有幫助的。
每一級Prometheus都是單獨管理的,缺少全局管理工具。
怎樣的監控系統,能夠同時解決上述幾個問題呢?咱們先構思一個理想模型,稱之爲Kvass。
先看採集,咱們採集側遇到的問題主要就是性能問題,即咱們但願Kvass擁有如下能力
存儲側,咱們遇到的問題是存儲時長,以及資源利用率,咱們但願Kvass的存儲擁有如下能力
展現側,咱們遇到的問題是沒法獲得全局視圖,因此,對於理想化的展現,咱們但願Kvass的展現擁有如下能力
告警側,咱們但願能支持原生Prometheus的告警配置。
咱們但願Kvass沒有過於複雜的配置項,且系統擁有一套完整的運維工具,能使用Kubernetes原生方式進行管理。
假設咱們有了這麼一個模型,那麼咱們的監控就能夠變成下面這種架構,在這種模型下,咱們擁有了單個地域下全部咱們要的原始數據。
這一節介紹咱們是如何實現理想模型中的高性能採集器的
首先咱們先了解一下Prometheus的採集原理,爲後面修改Prometheus實現高可用分片打下基礎。下圖展現了Prometheus採集時各模塊的關係
咱們已經從Prometheus在實際中的表現知道Prometheus對內存使用會隨着採集目標的規模增加而增加,那Prometheus的內存到底用在哪了?
存儲模塊
抓取模塊
分析了Prometheus的採集原理後,咱們能夠想肯定如下幾個事情
如下表格中的資源個數爲Kubenetes官方給出的大規模集羣應該包含的資源數 series個數經過統計cadvisor 和kube-state-metrics的指標得出
總計 5118w series。
有大量節點數目高於300的集羣,經過前面的壓測,單個Prometheus確實存在性能瓶頸。那咱們根據前面的採集原理,嘗試修改Prometheus讓其支持橫向擴縮容。
不管怎麼修改,咱們但願保持如下特性
再來回顧一下上邊的採集原理圖,看看咱們應該在哪一個地方進行修改。
從上圖中,咱們發現,負載產生的源泉是target scraper,若是減小target scraper個數,就能減小總體採集到的series,從而下降負載。
假設咱們有多個Prometheus共享相同的配置文件,那麼理論上他們產生出來的target scraper應當是如出一轍的。若是多個Prometheus之間可以相互協調,根據每一個target scraper抓取的目標數據量狀況,分配這些target scraper,就是實現負載的均攤。以下圖所示。
爲了實現上述方案,咱們須要一個獨立於全部Prometheus的負載協調器,協調器週期性(15s) 進行負載計算,該協調器負責收集全部target scraper的信息,以及全部Prometheus的信息,隨後經過分配算法,爲每一個Prometheus分配一些target scraper,最後將結果同步給全部Prometheus。
相應的,每一個Prometheus須要添加一個本地協調模塊,該模塊負責和獨立的協調器進行對接,上報本Prometheus經過服務發現發現的全部target,以及上一次採集獲知的target的數據量,另外該模塊也接受協調器下發的採集任務信息,用於控制本Prometheus應該開啓哪些target scraper。
當協調器收集到全部target信息後,須要將target分配給全部Prometheus在分配時,咱們保持如下原則
咱們最終採用了以下算法來分配target
4.1 若是以前沒有采集過,則隨機分配個一個Prometheus。
4.2 若是原來採集的Prometheus負載未超過avg_load,則分配給他。
4.3 找到全部Prometheus中負載最低的實例,若是該實例目前的負載總和加上當前target的負載依舊小於avg_load,則分配他給,不然分配給原來的採集的Prometheus。
咱們還能夠用僞代碼來表示這個算法:
func load(t target) int { return t.series * (60 / t.scrape_interval) } func reBalance(){ global_targets := 全部Prometheus的targets信息彙總 avg_load = avg(global_targets) for 每一個Prometheus { p := 當前Prometheus for 正在採集的target{ t := 當前target if p.Load <= avg_load { p.addTarget(t) global_targets[t] = 已分配 p.Load += load(t) } } } for global_targets{ t := 當前target if t 已分配{ continue } p := 正在採集t的Prometheus if p 不存在 { p = 隨機Prometheus }else{ if p.Load > avg_load { exp := 負載最輕的Prometheus if exp.Load + load(t) <= avg_load{ p = exp } } } p.addTarget(t) p.Load += load(t) } }
當一個Prometheus上的target抓取任務被分配到另一個Prometheus時,須要增長一種平滑轉移機制,確保轉移過程當中不掉點。這裏咱們容忍重複點,由於咱們將在後面將數據去重。
target交接的實現很是簡單,因爲各個Prometheus的target更新幾乎是同時發生的,因此只須要讓第一個Prometheus的發現抓取任務被轉移後,延遲2個抓取週期結束任務便可。
協調器會在每一個協調週期計算全部Prometheus的負載,確保平均負載不高於一個閾值,不然就會增長Prometheus個數,在下個協調週期採用上邊介紹的targets交接方法將一部分targets分配給它。
考慮到每一個Prometheus都有本地數據,縮容操做並不能直接將多餘的Prometheus刪除。咱們採用瞭如下方法進行縮容
在上述介紹的方案中,當某個Prometheus的服務不可用時,協調器會第一時間把target轉移到其餘Prometheus上繼續採集,在協調週期很短(5s)的狀況下,出現斷點的概率實際上是很是低的。可是若是須要更高的可用性,更好的方法是進行數據冗餘,即每一個targets都會被分配給多個Prometheus實例,從而達到高可用的效果。
到目前爲止,咱們雖然將Prometheus的採集功能成功分片化,可是,各個Prometheus採集到的數據是分散的,咱們須要一個統一的存儲機制,將各個Prometheus採集到的數據進行整合。
在上一節最後,咱們引出,咱們須要一個統一的存儲來將分片化的Prometheus數據進行存儲。業界在這方面有很多優秀的開源項目,咱們選取了知名度最高的兩個項目,從架構,接入方式,社區活躍度,性能等各方面作了調研。
Thanos簡介
Thanos是社區十分流行的Prometheus高可用解決方案,其設計如圖所示
從採集側看,Thanos,利用Prometheus邊上的Thanos sidecar,將Prometheus落在本地的數據盤上傳至對象存儲中進行遠程存儲,這裏的Prometheus能夠有多個,各自上報各自的數據。
查詢時,優先從各Prometheus處查詢數據,若是沒查到,則從對象存儲中查詢歷史數據,Thanos會將查詢到的數據進行去重。Thanos的設計十分符合咱們前面的採集方案提到的統一存儲。接入後如圖所示。
Cortex簡介
Cortex是Weavework公司開源的Prometheus兼容的TSDB,其原生支持多租戶,且官方宣傳其具備很是強大的性能,能存儲高達2500萬級別的series,其架構如圖所示
從架構圖不難發現,Cortex比Thanos要複雜得多,外部依賴也多,估計總體運維難度的比較大。Cortex再也不使用Prometheus自帶的存儲,而是讓Prometheus經過remote write將數據所有寫到Cortex系統進行統一的存儲。Cortex經過可分片接收器來接收數據,隨後將數據塊存儲到對象存儲中,而將數據索引存儲到Memcache中。
社區現狀
上文從架構角度對兩個項目進行了一番對比,可是實際使用中,他兩表現如何呢,咱們進行性能壓測:
咱們保持兩個系統series總量老是擁有相同的變化,從查詢性能,系統負載等多方面,去評估他們以前的優劣
穩定性:不一樣數據規模下,組件是否正常工做
從數據上看 Thanos 更加穩定一些。
查詢性能:不一樣數據規模下,查詢的效率
從數據上看,Thanos的查詢效率更高。
未啓用Ruler資源消耗:沒有啓動Ruler狀況下,各組件的負載
就採集和查詢而言,Thanos的資源消耗要比Cortex低不少。
在整個壓測過程當中,咱們發現Cortex的性能遠沒有官方宣稱的好,固然也多是咱們的調參不合理,可是這也反應出Cortex的使用難度極高,運維十分複雜(上百的參數),總體使用體驗很是差。反觀Thanos總體表現和官方介紹的較爲相近,運維難度也比較低,系統較好把控。
從前面的分析對比來看,Thanos不管是從性能仍是從社區活躍度,仍是從接入方式上看,較Cortex都有比較大的優點。因此咱們選擇採用Thanos方案來做爲統一存儲。
到目前爲止,咱們經過實現可分片Prometheus加Thanos,實現了一套與原生Prometheus配置100%兼容的高性能可伸縮的Kvass監控系統。組件關係如圖:
上圖咱們只畫了一套採集端(即多個共享同一份配置文件的Prometheus,以及他們的協調器),實際上系統支持多個採集端,即一個系統可支持多個Kubernetes集羣的監控,從而獲得多集羣全局數據視圖。
回顧舊版本監控在運維方法的不足,咱們但願咱們的新監控系統有用完善的管理工具,且能用Kubernetes的方式進行管理。咱們決定使用operator模式進行管理,Kvass-operator就是整個系統的管理中心,它包含以下三種自定義資源
因爲Prometheus配置文件管理比較複雜,CoreOS開源了一個Prometheus-operator項目,用於管理Prometheus及其配置文件,它支持經過定義ServiceMonitor,PodMonitor這兩種相比於原生配置文件具備更優可讀性的自定義類型,協助用戶生成最終的採集配置文件。
咱們但願實現一種虛擬Prometheus機制,即每一個user cluster可以在本身集羣內部管理其所對應的Prometheus採集配置文件,進行ServiceMonitor和PodMonitor的增刪改查,也就是說,Prometheus就好像部署在本身集羣裏面同樣。
爲了達到這種效果,咱們引入並修改了Prometheus-operator。新版Prometheus-operator會鏈接上用戶集羣進行ServiceMonitor和PodMonitor的監聽,並將配置文件生成在採集側。
另外咱們將協調器和Prometheus-operator放在了一塊兒。
經過一步一步改進,咱們最終擁有了一套支持多集羣採集,並支持擴縮容的高可用監控系統,咱們用其替換原來監控方案中的Cluster-monitor + Region Prometheus。實現了文章之初的訴求。
最第一版本
新方案
咱們上邊介紹的方案,已經能夠總體替換早期方案中的Region Prometheus及Cluster-monitor。如今咱們再加入一套Thanos,用於將全網數據進行整合。
相比於舊版本監控的指標預約義,新版本監控系統因爲Prometheus是可擴縮容的,因此是能夠支持用戶上報自定義數據的。
Kvass的設計不是天馬行空拍腦殼決定的,而是在當前場景下一些問題的解決思路所組成的產物。
雖然咱們整篇文章就是在介紹一種用於取代舊版本監控的新系統,可是這並不意味着咱們以爲舊版本監控設計得差勁,只是隨着業務的發展,舊版本監控系統所面臨的場景相較於設計之初有了較大變化,當時合理的一些決策,在當前場景下變得再也不適用而已。與其說是替換,不如稱爲爲演進。
相比於直接開始系統落地,咱們更傾向於先設計系統模型,以及肯定設計原則,系統模型用於理清咱們究竟是要解決什麼問題,咱們的系統應該由哪幾個核心模塊組件,每一個模塊最核心要解決的問題是什麼,有了系統模型,就等於有了設計藍圖和思路。
在系統設計過程當中,咱們尤其重視設計的原則,即不管咱們採用什麼形式,什麼方案,哪些特性是新系統必需要有的,對於Kvass而言,原生兼容是咱們首要的設計原則,咱們但願不管咱們怎麼設計,對用戶集羣而言,就是個Prometheus。
在總體研發過程當中,咱們也踩了很多坑。Cortex的架構設計相比於thaos而言,採用了索引與數據分離的方式,設計上確實更加合理,理論上對於大規模數據,讀取性能會更優,而且Cortex因爲原生就支持多租戶,實現了大量參數用於限制用戶的查詢規模,這點是Thanos有待增強的地方。咱們最初的方案也嘗試採用Cortex來做爲統一存儲,可是在實際使用時,發現Cortex存在內存佔用高,調參複雜等問題,而Thanos相比而言,性能較爲穩定,也更加切近咱們的場景,咱們再結合壓測報告,選擇將存儲切換爲Thanos。
因爲Kvass系統因此解決的問題具備必定普適性,TKE決定將其做爲一個子產品對用戶暴露,爲用戶提供基於Kvass的雲原生系統,該產品目前已開放內測。
【騰訊雲原生】雲說新品、雲研新術、雲遊新活、雲賞資訊,掃碼關注同名公衆號,及時獲取更多幹貨!!