轉載:技術專欄/美團技術團隊技術專欄/深度剖析開源分佈式監控CAThtml
CAT(Central Application Tracking)是一個實時和接近全量的監控系統,它側重於對Java應用的監控,基本接入了美團上海側全部核心應用。目前在中間件(MVC、RPC、數據庫、緩存等)框架中獲得普遍應用,爲美團各業務線提供系統的性能指標、健康情況、監控告警等。自2014年開源以來,除了美團以外,CAT還在攜程、陸金所、獵聘網、找鋼網等多家互聯網公司生產環境應用,項目的開源地址是 http://github.com/dianping/cat。git
本文會對CAT總體設計、客戶端、服務端等的一些設計思路作詳細深刻的介紹。github
CAT整個產品研發是從2011年末開始的,當時正是大衆點評從.NET遷移到Java的核心起步階段。當初大衆點評已經有核心的基礎中間件、RPC組件Pigeon、統一配置組件Lion。總體Java遷移已經在服務化的路上。隨着服務化的深刻,總體Java在線上部署規模逐漸變多,同時,暴露的問題也愈來愈多。典型的問題有:web
雖然那時候也有一些簡單的監控工具(好比Zabbix,本身研發的Hawk系統等),可能單個工具在某方面的功能還不錯,但總體服務化水平良莠不齊、擴展能力相對較弱,監控工具間不能互通互聯,使得查找問題根源基本都須要在多個系統之間切換,有時候真的是靠「人品」才能找出根源。數據庫
適逢在eBay工做長達十幾年的吳其敏加入大衆點評成爲首席架構師,他對eBay內部應用很是成功的CAL系統有深入的理解。就在這樣天時地利人和的狀況下,咱們開始研發了大衆點評第一代監控系統——CAT。後端
CAT的原型和理念來源於eBay的CAL系統,最初是吳其敏在大衆點評工做期間設計開發的。他以前曾CAT不只加強了CAL系統核心模型,還添加了更豐富的報表。api
監控總體要求就是快速發現故障、快速定位故障以及輔助進行程序性能優化。爲了作到這些,咱們對監控系統的一些非功能作了以下的要求:緩存
CAT從開發至今,一直秉承着簡單的架構就是最好的架構原則,主要分爲三個模塊:CAT-client、CAT-consumer、CAT-home。tomcat
在實際開發和部署中,Cat-consumer和Cat-home是部署在一個JVM內部,每一個CAT服務端均可以做爲consumer也能夠做爲home,這樣既能減小整個層級結構,也能夠增長系統穩定性。安全
上圖是CAT目前多機房的總體結構圖,圖中可見:
客戶端設計是CAT系統設計中最爲核心的一個環節,客戶端要求是作到API簡單、高可靠性能,不管在任何場景下都不能影響客業務性能,監控只是公司核心業務流程一個旁路環節。CAT核心客戶端是Java,也支持Net客戶端,近期公司內部也在研發其餘多語言客戶端。如下客戶端設計及細節均以Java客戶端爲模板。
CAT客戶端在收集端數據方面使用ThreadLocal(線程局部變量),是線程本地變量,也能夠稱之爲線程本地存儲。其實ThreadLocal的功用很是簡單,就是爲每個使用該變量的線程都提供一個變量值的副本,屬於Java中一種較爲特殊的線程綁定機制,每個線程均可以獨立地改變本身的副本,不會和其它線程的副本衝突。
在監控場景下,爲用戶提供服務都是Web容器,好比tomcat或者Jetty,後端的RPC服務端好比Dubbo或者Pigeon,也都是基於線程池來實現的。業務方在處理業務邏輯時基本都是在一個線程內部調用後端服務、數據庫、緩存等,將這些數據拿回來再進行業務邏輯封裝,最後將結果展現給用戶。因此將全部的監控請求做爲一個監控上下文存入線程變量就很是合適。
如上圖所示,業務執行業務邏輯的時候,就會把這次請求對應的監控存放於線程上下文中,存於上下文的實際上是一個監控樹的結構。在最後業務線程執行結束時,將監控對象存入一個異步內存隊列中,CAT有個消費線程將隊列內的數據異步發送到服務端。
監控API定義每每取決於對監控或者性能分析這個領域的理解,監控和性能分析所針對的場景有以下幾種:
在上述領域模型的基礎上,CAT設計本身核心的幾個監控對象:Transaction、Event、Heartbeat、Metric。
一段監控API的代碼示例以下:
序列化和通訊是整個客戶端包括服務端性能裏面很關鍵的一個環節。
日誌埋點是監控活動的最重要環節之一,日誌質量決定着監控質量和效率。當前CAT的埋點目標是以問題爲中心,像程序拋出exception就是典型問題。我我的對問題的定義是:不符合預期的就能夠算問題,好比請求未完成、響應時間快了慢了、請求TPS多了少了、時間分佈不均勻等等。
在互聯網環境中,最突出的問題場景,突出的理解是:跨越邊界的行爲。包括但不限於:
一般Java客戶端在業務上使用容易出問題的地方就是內存,另一個是CPU。內存每每是內存泄露,佔用內存較多致使業務方GC壓力增大; CPU開銷最終就是看代碼的性能。
之前咱們遇到過一個極端的例子,咱們一個業務請求作餐飲加商鋪的銷售額,業務通常會經過for循環全部商鋪的分店,結果就形成內存OOM了,後來發現這家店是肯德基,有幾萬分店,每一個循環裏面都會有數據庫鏈接。在正常場景下,ThreadLocal內部的監控一個對象就存在幾萬個節點,致使業務Oldgc特別嚴重。因此說框架的代碼是不能想象業務方會怎麼用你的代碼,須要考慮到任何狀況下都有出問題的可能。
在消耗CPU方面咱們也遇到一個case:在某個客戶端版本,CAT本地存儲當前消息ID自增的大小,客戶端使用了MappedByteBuffer這個類,這個類是一個文件內存映射,測試下來這個類的性能很是高,咱們僅僅用這個存儲了幾個字節的對象,正常狀況理論上不會有任何問題。在一次線上場景下,不少業務線程都block在這個上面,結果發現當自己這臺機器IO存在瓶頸時候,這個也會變得很慢。後來的優化就是把這個IO的操做異步化,因此客戶端須要儘量異步化,異步化序列化、異步化傳輸、異步化任何可能存在時間延遲的代碼操做。
服務端主要的問題是大數據的實時處理,目先後端CAT的計算集羣大約35臺物理機,存儲集羣大約35臺物理機,天天處理了約100TB的數據量。線上單臺機器高峯期大約是110MB/s,接近千兆網打滿。
下面我重點講下CAT服務端一些設計細節。
在最初的總體介紹中已經畫了架構圖,這邊介紹下單機的consumer中大概的結構以下:
如上圖,CAT服務端在整個實時處理中,基本上實現了全異步化處理。
當某個報表處理器處理來不及時候,好比Transaction報表處理比較慢,能夠經過配置支持開啓多個Transaction處理線程,併發消費消息。
CAT服務端實時報表分析是整個監控系統的核心,CAT重客戶端採集的是是原始的logview,目前一天大約有1000億的消息,這些原始的消息太多了,因此須要在這些消息基礎上實現豐富報表,來支持業務問題及性能分析的須要。
CAT是根據日誌消息的特色(好比只讀特性)和問題場景,量身定作的,它將全部的報表按消息的建立時間,一小時爲單位分片,那麼每小時就產生一個報表。當前小時報表的全部計算都是基於內存的,用戶每次請求即時報表獲得的都是最新的實時結果。對於歷史報表,由於它是不變的,因此實時不實時也就無所謂了。
CAT基本上全部的報表模型均可以增量計算,它能夠分爲:計數、計時和關係處理三種。計數又能夠分爲兩類:算術計數和集合計數。典型的算術計數如:總個數(count)、總和(sum)、均值(avg)、最大/最小(max/min)、吞吐(tps)和標準差(std)等,其餘都比較直觀,標準差稍微複雜一點,你們本身能夠推演一下怎麼作增量計算。那集合運算,好比95線(表示95%請求的完成時間)、999線(表示99.9%請求的完成時間),則稍微複雜一些,系統開銷也更大一點。
CAT每一個報表每每有多個維度,以transaction報表爲例,它有5個維度,分別是應用、機器、Type、Name和分鐘級分佈狀況。若是全維度建模,雖然靈活,但開銷將會很是之大。CAT選擇固定維度建模,能夠理解成將這5個維度組織成深度爲5的樹,訪問時老是從根開始,逐層往下進行。
CAT服務端爲每一個報表單獨分配一個線程,因此不會有鎖的問題,全部報表模型都是非線程安全的,其數據是可變的。這樣帶來的好處是簡單且低開銷。
CAT報表建模是使用自研的Maven Plugin自動生成的。全部報表是可合併和裁剪的,能夠輕易地將2個或多個報表合併成一個報表。在報表處理代碼中,CAT大量使用訪問者模式(visitor pattern)。
實時業務指標監控 :核心業務都會定義本身的業務指標,這不須要太多,主要用於24小時值班監控,實時發現業務指標問題,圖中一個是當前的實際值,一個是基準值,就是根據歷史趨勢計算的預測值。以下圖就是當時的情景,能直觀看到支付業務出問題的故障。
系統報錯大盤。
CAT系統的存儲主要有兩塊:
報表是根據logview實時運算出來的給業務分析用的報表,默認報表有小時模式、天模式、周模式以及月模式。CAT實時處理報表都是產生小時級別統計,小時級報表中會帶有最低分鐘級別粒度的統計。天、周、月等報表都是在小時級別報表合併的結果報表。
原始logview存儲一天大約100TB的數據量,由於數據量比較大因此存儲必需要要壓縮,自己原始logview須要根據Message-ID讀取,因此存儲總體要求就是批量壓縮以及隨機讀。在當時場景下,並無特別合適成熟的系統以支持這樣的特性,因此咱們開發了一種基於文件的存儲以支持CAT的場景,在存儲上一直是最難的問題,咱們一直在這塊持續的改進和優化。
CAT每一個消息都有一個惟一的ID,這個ID在客戶端生成,後續都經過這個ID在進行消息內容的查找。典型的RPC消息串起來的問題,好比A調用B的時候,在A這端生成一個Message-ID,在A調用B的過程當中,將Message-ID做爲調用傳遞到B端,在B執行過程當中,B用context傳遞的Message-ID做爲當前監控消息的Message-ID。
CAT消息的Message-ID格式ShopWeb-0a010680-375030-2,CAT消息一共分爲四段:
消息存儲是CAT最有挑戰的部分。關鍵問題是消息數量多且大,目前美團天天處理消息1000億左右,大小大約100TB,單物理機高峯期每秒要處理100MB左右的流量。CAT服務端基於此流量作實時計算,還須要將這些數據壓縮後寫入磁盤。
總體存儲結構以下圖:
CAT在寫數據一份是Index文件,一份是Data文件.
CAT在分佈式實時方面,主要歸結於如下幾點因素:
最後咱們再花一點點時間來說一下咱們在實踐裏作的一些東西。
1、MVP版本,Demo版本用了1個月,MVP版本用了3個月。
爲何強調MVP版本?由於作這個項目須要老闆和業務的支持。大概在2011年左右,咱們整個生產環境估計也有一千臺機器(虛擬機),一旦出現問題就到運維那邊看日誌,看日誌的痛苦你們都應該理解,這時候發現一臺機器核心服務出錯,可能會致使更多的問題。咱們就作了MVP版本解決這個問題,當時咱們大概作了兩個功能:一個是實時知道全部的API接口訪問量成功率等;第二是實時能在CAT平臺上看到異常日誌。這裏我想說的是MVP版本不要作太多內容,可是在作一個產品的時候必須從MVP版本作起,要作一些最典型特別亮眼的功能讓你們支持你。
2、數據質量。數據質量是整個監控體系裏面很是關鍵,它決定你最後的監控報表質量。因此咱們要和跟數據庫框架、緩存框架、RPC框架、Web框架等作深刻的集成,讓業務方便收集以及看到這些數據。
3、單機開發環境,這也是咱們認爲對整個項目開發效率提高最重要的一點。單機開發環境實際上就是說你在一臺機器裏能夠把你全部的項目都啓起來。若是你在一個單機環境下把全部東西啓動起來,你就會千方百計地知道我依賴的服務掛了我怎麼辦?好比CAT依賴了HDFS。單機開發環境除了大幅度提升你的項目開發效率以外,還能提高你整個項目的可靠性。
4、最難的事情是項目上線推進。CAT整個項目大概有兩三我的,當時白天都是支持業務上線,培訓,晚上才能code,可是一旦隨着產品和完善以及業務使用逐漸變多,一些好的產品後面會造成良性循環,推廣就會變得比較容易。
5、開放生態。公司越大監控的需求越多,報表需求也更多,好比咱們美團,產品有不少報表,整個技術體系裏面也有不少報表很是多的自定義報表,不少業務方都提各自的需求。最後咱們決定把整個CAT系統裏面全部的數據都做爲API暴露出去,這些需求並非不能支持,而是這事情根本是作不完的。美團內部下游有不少系統依賴CAT的數據,來作進一步的報表展現。
CAT項目從2011年開始作,到如今整個生產環境大概有三千應用,監控的服務端從零到幾千,再到今天的兩萬多的規模,整個項目是從歷時看起來是一個五年多的項目,但即便是作了五年多的這樣一個項目,目前還有不少的需求須要開發。這邊也打個廣告,咱們團隊急缺人,歡迎對監控系統研發有興趣的同窗加入,請聯繫yong.you@dianping.com.