Mercury:唯品會全鏈路應用監控系統解決方案詳解(含 PPT)
姚捷,唯品會平臺架構部高級架構師,加入唯品會前有超過 10 年的金融/保險互聯網技術架構和團隊管理經驗,擅長以產品思維設計和構建系統。現專注于互聯網基礎架構,負責唯品會全鏈路監控/分析平臺的開發,管理,推廣和運維落地工作。對大數據體系,實時計算,微服務體系,消息系統有深入研究和實踐。
我來自唯品會平臺架構部,非常感謝高可用架構在上海組織了這么一場高逼格的活動。唯品會平臺架構部是長期致力于基礎應用架構建設與推廣的部門,我們承擔非常多的基礎應用架構研發。
唯品會有三大特點,特賣 + 閃購 + 正品,在唯品會,峰值訪問量非常大,這樣的流量,使得唯品會平臺架構部承擔非常大的挑戰,包括我今天分享的全鏈路監控系統。
上面是我們的新廣告,周杰倫代言,傲嬌品牌,只賣呆萌的價格。
今天給大家帶來的是我們一個比較重要的產品 Mercury,它是一個大型互聯網應用全鏈路監控系統解決方案。
大家可能了解,500 錯誤場景可能是大家在線上經常遇到的問題,等待很長時間,然后系統給你 500,讓大家很抓狂。在部署全鏈路監控之前,大家可能需要使用比較古老的方式,跑到生產機上面去查問題,這個過程可能耗費大量的時間。
之前在唯品會,我們做了一個叫 Logview 的產品,它是一款基于 nginx access log 的監控平臺。唯品會大量系統前置了一個代理服務器,Logview 的機制是通過解析 nginx access log,構建一個日志監控平臺。它跑了蠻長時間,迄今還在線上穩定運行,它曾經是唯品會最重要的一個監控平臺。
但隨著業務規模的不斷增加,基于 nginx access log 的監控會遇到不少問題。
-
沒有辦法從代碼級別進行監控,通過它只能看到粗粒度的監控信息;
-
隨著服務化的改造,大部分的流量,已經不經過 nginx 了;
-
它支持告警,但是沒有辦法通過告警跟蹤到問題的 root cause。比如說 500 通常是某一個異常導致的,但是這里是看不到異常的,你還得到主機上、到 ELK 上查日志。它沒有辦法通過告警很快速的定位到我們線上的 root cause,尋找問題的成本還是很高。
-
告警規則配置呆板,維護變更代價大。
-
沒有辦法跟蹤業務之間的調用關系。唯品會在全網大概有上個業務域,主機現在接近幾萬臺,這個體量是非常之大的,當一個系統一個域出了一個業務問題的時候,其實導致它產生問題的地方可能是很深層的。Logview 沒有辦法幫你跟蹤到這些業務之間的關聯關系,調用關系沒有建立起來,出了問題你不知道最根本的原因在哪個域。
-
沒有辦法快速定位應用性能瓶頸。上面也提到,應用出了問題沒有辦法關聯異常。
-
高峰值期間流量一上來就經常掛。
因為上面種種問題,我們痛定思痛,尋找新的方法。這個新的方向是什么?當時我們看了 Google Dapper ( http://research.google.com/pubs/pub36356.html ) 的文章之后,認為基本上就是全鏈路監控系統。
Dapper 是幫大家構建一套比較完整的端到端的全鏈路日志采集的規范,是大家可以跟隨的一個原則或者準則。它最關鍵的概念就是 span。
基于 Dapper 原理,有蠻多行業解決方案,比較有名的有淘寶 eagle eye,點評/攜程的 CAT,微博的 Watchman,還有聽云 Server 等。當時我們也對這些方案做了一些調研,但最終我們還是選擇自建平臺。
為什么呢?因為唯品會還算有錢,團隊的能力也比較強,有蠻多資深的技術人員。除了有錢有之外,更多的是從業務上,從系統層面上去看我們為什么要自建平臺。
第一, 系統復雜 。上千個業務域,同時又是異構系統,有很多系統還是 PHP。服務化體系內存在眾多的異構系統的,我們要去監控這樣的異構系統,顯然不能直接用一些業界的方案。
第二, 海量數據 。唯品會峰值每分鐘上億日志量,一天達到上百億的日志量,這是非常海量的數據。BAT 之外,對比其他公司,唯品會在這個數據量上面也是很高的。對這些海量日志,怎么樣端到端對海量數據搜集、計算、存儲、檢索,這是一個很大的挑戰。
第三,我們需要 自建服務化體系的監控 。我們有自建的服務化體系,這個服務化體系要怎么監控?我們的服務端其實需要一些定制的埋點和數據透傳機制的,它沒有辦法說我直接打一個 log,這其實是每個公司有自己的服務化體系,它需要自己去埋點。
第四, 高度可治理 。這個非常重要,因為當你整個攤子鋪大了之后,上千個域都接入后,怎么去管理?比如說大促的時候經常遇到我沒數據了,為什么沒有數據,整個體系是非常復雜的,我怎么樣能夠快速的知道這個業務為什么沒有監控數據了,這就涉及到治理。
另外大促的時候我們要做一些動態的升降級,這些動態的升降級也是依賴比較強的治理能力,需要在生產環境去控制日志的產生。
第五, 快速接入,升級便捷 。因為我們的團隊很大,開發人員很多,所以我們的產品要做到讓業務用起來很方便,我們需要一些無侵入埋點,快速接入。
同時在我們很復雜的體系當中,需要考慮怎么快速的升級,我不知道大家有沒有經歷過在一個很龐大的體系當中升級客戶端,不管是監控系統的客戶端,還是其他的客戶端都是很頭疼的問題,特別是在業務線眾多的大型公司。據說阿里的 dubbo/hsf 的升級其實是非常困難的,我們現在也遇到類似的問題,因此需要提前去考慮這些問題。
第六, 靈活的告警策略和高效告警 。我們需要一個多維度、多監督、多級別、多時效、同時支持告警收斂的告警引擎
第七,還有一個很重要的一點, 監控體系要與公司的很多體系無縫對接 ,我需要滿足不同角色的需求,同時要與唯品會的發布、監控、問題跟蹤平臺無縫對接。
所以正是因為以上種種原因,我們決定自建平臺。
先快速給大家介紹一下 Mercury。
-
Mercury 是 唯品會自主研發的應用性能監控和問題跟蹤平臺
-
基于客戶端探針上報應用調用鏈相關日志
-
基于流式計算和大數據存儲和檢索技術
-
提供實時和準實時告警,并快速定位根源問題
-
分布式應用調用鏈路跟蹤
-
提供快速有效的數據展現和分析平臺
唯品會監控體系
我們的全鏈路應用監控體系在唯品會處于什么樣的位置?
系統層監控我們主要還是 Zabbix,我們在上面做了一些封裝,提供更好的交互。
業務層我們有一個產品叫 Telescope,所有的業務監控,包括 PV/UV、定單量、支付成功/失敗率等重要業務數據,全部在這個產品上面可以看到。
在應用層,現在 ELK 用得比較多,另外一個產品 SKYHAWK,它其實是 APP 應用端的監控平臺。
接下來是 Mercury,唯品會現在所有的應用,所有服務化的應用,所有 PHP/Web 應用,都是通過 Mercury 來做應用層的監控。
為唯品會的監控生態而設計
在說到一些技術之前,我還想強調一點,我們做產品并不是簡單地做一個技術,簡單地把很多東西搭在一起,我們更多的是要為整個技術生態去設計。我們的產品更多的是為滿足整個唯品會的運營、技術運營的需要,為這個生態的需要而設計,所以會涉及到人、流程和技術。
人的話,無非就是開發、監控、運維、運營、管理人員,這些人都會通過我們平臺,去察看他們想看的數據。我們的監控系統會發布流程,發布的時候我要監控整個發布的質量,監控流程、故障問題定位、故障問題修復、以及故障回顧,這些其實是整個監控系統需要控制的流程。
技術上,主要包括大數據采集、大數據計算、大數據的存儲和分析,這些技術整個形成了我們的監控生態。
Mercury 核心價值
Mercury 的核心價值在于:
-
生產環境 端到端 的性能可視化;
-
展現一個應用的完整的拓撲關系,通過全鏈路監控系統,我們把整個鏈路的拓撲展現出來;
-
快速告警,并且定位根源的問題。
這三點我總結下來,是我們這個產品最核心的價值。
海量數據剛才我也提到了,大約如下:
-
1萬+ 應用服務器接入
-
接入業務域 500+
-
大促峰值每分鐘處理日志 1億+
-
日均處理日志量 150億+
-
日均存儲日志 5T+
-
日均索引量 1T
這些數據都體現我們的產品,我們是在支撐一個非常海量的數據。
前面提到這么多的統計數據也好,監控流程也好,回頭來看一下,Mercury 是怎么去支撐這樣的海量數據的?我們的架構是怎么樣的?我們可以深入到一些架構的細節,去看怎么去構建一個比較完整的全鏈路監控系統。
完整的全鏈路監控系統
一個比較完整的全鏈路監控系統,通常會包括幾個部分。
第一, 數據埋點和采集 ,這個相當重要,其實說白了,數據是整個監控系統最核心的部分,必須有能力快速和正確和方便地采集日志,所以我們在數據埋點和采集上做了很多文章。
第二, 指標計算 。指標計算有好幾種方式,一種我可以在客戶端做一些計算,通過 agent 上報計算結果,然后到服務端再做加工。還有一種策略是完全在服務端的計算,客戶端只做簡單的數據采集,所有的指標計算全放在服務端。這二種架構其實都有不同的優缺點。
第三, 指標存儲、查詢、展現 ,這個也非常重要。算完后的指標放在哪里,這些指標怎么樣快速的查詢出來,指標怎么樣很靈活的展現給我們的運營人員、開發人員。
第四, 調用鏈的存儲、查詢、展現 。因為我們是全鏈路監控系統,調用鏈怎么存、怎么查、怎么看,這個也是非常重要的。
第五, 告警、問題定位 ,因為你單純只有查詢遠遠不夠,我們需要一個很快速很高效的告警,同時產生告警之后,我們需要很快速的去定位這個告警是什么原因導致的。
第六, 自監控 。我們的體系需要一個自監控的功能,假如我在大促的時候掛了,我需要很快的恢復我們的平臺,自監控非常重要。
第七, 治理 。大促之前需要動態地調整日志采樣率,或者對日志采集做一些功能降級,例如不采集緩存相關日志。
建設一個完整的全鏈路監控體系是需要考慮以上這幾個過程。
全鏈路監控技術棧
技術棧,我們的體系有用了很多的技術,Spark 、 Open TSDB 、HBase 、Elastic Search,Kafka,Flume,Python 等,整個技術棧相當之復雜。
系統架構
我們 Mercury 的架構是怎么樣的呢,大家來看一下,大致來跟大家描述一下我們整個架構的走法。
(點擊圖片可以全屏縮放)
先說客戶端,應用系統其實是依賴一個 client 這樣的探針組件,它其實是一個非常非常高效的數據采集組件,對用戶來說是完全透明的,你不需要去做任何的編程,基于字節碼織入技術,只需要做一些簡單的配置。那么客戶端就能夠很高效的采集相關日志數據。這些日志是基于一個標準格式的,因此,我們的接入是非常高效的,你不需要關心我采集日志的格式是什么。很多其它的監測系統,比如像 CAT,可能它需要手動埋點,這個時候你可能需要非常關注它的埋點格式是什么。我們是不需要關心埋點格式的。
我們的日志數據是不會直接傳到后端的,它首先落地在客戶端的磁盤上面。
接著我們有一個 flume agent,基于 Flume,我們做了一個插件,這個插件會非常高效地采集我們客戶端的日志。
當我們搜集到了日志之后,它就很高效地把日志推到 Kafka 集群里面。我們要保證它的日志是非常精簡的,因為唯品會有多個 IDC 機房,跨機房低帶寬占用是非常重要的。這個上面我們做了一些基于 avro 的數據序列化的優化,序列化之后帶寬基本上降了一倍左右。 我們沒有用壓縮,因為壓縮會導致客戶端的消耗比較大。
當這些數據來到 Kafka 集群,后面有幾個集群,首先第一個是 Spark 集群,這是一個非常重要的數據流式計算的集群,我們通過 Spark 做指標計算,讓所有的日志都通過 Spark 很快速的算下來的,基本上延時在兩分鐘左右。考慮到端到端數據上報的時效性,其中只有一到兩分鐘是計算的延時。
指標算完之后,一條線到 OpenTSDB,如果做過監控的同學對這個應該是蠻熟的,相對來說也是比較成熟,比較簡單的基于 HBase 的一個時間序列的框架。
另外一條路,通過 flume 寫到 HBase 里,因為大家看到其實我們有調用鏈,那我們要對調用鏈做很快速的檢索,我們以前是直接把調用鏈日志寫到 HBase 里,但是有一個頭疼的問題是它的寫入很快,通過 rowkey 一鍵查詢也很快,但是如果說你需要做一些比較復雜的查詢,HBase 是不支持二級索引查詢的,你必須自己在它之上構建二級索引。
原來我們直接設計了一個索引表,但在海量數據下,查詢起來非常之慢,所以我們后來用 ElasticSearch,首先日志數據送到 Kafka 后會被消費兩次,一條路是直接送到 ElasticSearch 里建索引。另外一條路是調用鏈日志直接落地到 HBase。
查詢的時候,首先到 ES 里根據查詢條件定位到 trace id,接著拿著 trace ID 到HBase 里一鍵把所有的端到端的請求都拉出來,所以通過一個 Trace ID 就能一下子把作為的調用鏈全拉出來,因此這個設計是非常輕巧的。
整個體系還有很重要的是兩個告警引擎,它分為實時秒級告警和一個指標告警。實時秒級告警更多的是對嚴重問題的告警,比如大量的服務超時,或者服務熔斷。這個時候我們整個體系會上報一些事件,會有一些熔斷事件,我們會預埋在我們的服務框架里面,一旦遇到這種問題的時會立刻上報。我們的上一級告警框架,會立刻檢測到這個 alarm,然后做實時告警。
同時我們會對這些異常做一些收斂,假設瞬間好幾百臺或者上千臺的主機都產生了異常,那整個異常都會一下子上報服務端,這個時候你會在服務端產生大量的報警,所以我們秒級告警會做一些收斂,會做一個特征值的設定,我會在三十秒或者十秒,這個時間窗口你可以定制,比如我十秒的窗口,我先對一些有特制的異常做一些簽名,緩存到內存里面,如果在一段時間之內,上報的異常匹配了特征值,則不會做重復告警。
當這個時間窗口過去之后,這個特征值就會失效,下一次再進來的時候,我們會重新構建這個特征值。我們用這樣的一個方法實現告警收斂。
下面這個是指標告警,它是一個周期性的告警任務,它會根據我的告警規則設定,定時掃描指標數據庫做一個周期性的告警。比如連續三分鐘,響應時間大于 30。毫秒就告警,類似這樣的告警我們通過周期性的告警規則來設定。
在后面還有 Dashboard 和告警跟蹤系統。上面也提到,我們是為整個唯品會的監控生態而設計,這個告警跟蹤系統會把我們所有的告警聚合到一起。告警看板的作用是說我立刻能在大盤上看到所有的告警,但是這些問題是不是已經處理完了,我們是需要一個比較好的跟蹤平臺去跟蹤的,所以我們設計了這樣的跟蹤系統。它是長時間運行的,開發人員每天會上去看。比如我昨天有些告警,這些告警有沒有處理完,都會在這個系統當中呈現。
調用鏈
整個體系還是蠻龐大的,接下來跟大家說一下我們整個體系最核心的調用鏈。
什么是調用鏈,大家可能第一次接觸全鏈路系統,可能對調用鏈的概念并不一定熟。你可以認為它是一個串聯端到端請求的鏈路,在這個鏈路上面我們會看到非常豐富的信息。
調用參數
我們在調用鏈上面我們去關聯說這個調用的參數是什么,我的出參入參可以在這個調用鏈上面。
業務關鍵字
這里我需要稍微解釋一下什么叫業務關鍵字。很多時候想象一下這樣一個場景,有一個用戶下單支付失敗了,這個時候我們怎么樣知道,為什么這個支付失敗了,到底是支付整個鏈路上面哪里出了問題,這個是需要我們還原現場。
如果有一個系統它能夠幫你還原這次調用,到底哪一步出了問題,所以你需要去反查,你需要拿著一些業務上面預先埋的點,比如說定單號或者用戶ID,通過這些信息我能夠反查到當時用戶下單操作的那次調用,再去看那次調用到底哪里出了問題。所以業務關鍵字是非常重要的。
我們要求核心的業務系統要通過我們的 API 去埋它的關鍵字,把它的用戶信息、訂單號,或者說我們一些很關鍵的業務字段,都預先的埋到我們的調用鏈上面,出了問題之后就可以反查。
調用耗時
這個應該很清楚。事件,因為有的時候我們要調用的時候,我們可以把一些這次調用產生的事件關聯在一起,我們也可以通過事件去反查當時的調用。異常日志這個信息非常重要,因為當你出了 500 的時候,一定會有異常產生,這個時候我就要通過這次調用去關聯這個異常,然后通過這個異常信息我就知道產生問題的是什么。
調用結果
調用結果,成功失敗。
調用鏈總結
所以整個調用鏈的信息還是蠻豐富的,那么調用鏈最核心的是什么?核心的是 每個請求都會生成一個全局唯一的 TraceID 和 SpanID ,它都會端到端的透傳到上下游所有的節點。每一個請求 TraceID 都要透傳上去,從最上游的移動端一直到最下面的數據庫, 通過這個 TraceID 我們將不同系統的孤立的調用日志和異常日志串聯在一起 ,同時 通過 SpanID 可以表達節點的父子關系 。
下面我為大家來說一說我們每一個組件當中的一些非常重要的設計原則,
1. 客戶端 - 舉重若輕
首先從客戶端講起,客戶端我把它形容為舉重若輕,你需要有一個很輕量級的客戶端,但它同時又能夠承擔很大的流量,怎么能夠做到這一點?我覺得很關鍵有以下幾點需要去注意。
高效率
高效率更多的是對開發人員來說,我要讓他們很快能夠用我們的東西。我們現在是支持 Java 和 PHP,高效率主要體現在:
-
Java 采用 AOP 埋點,不管是一個 Java 調用、其他的調用還是服務化調用,我們都會攔截所有的請求,植入我們的邏輯,包括透傳。
-
PHP 也有自己的框架,所以在 PHP 里面也進行預埋,對 PHP 的應用邏輯而言也是透明的。
-
日志格式是標準的,要不然日志框架沒有辦法很快的去監控我們的系統,用戶是沒有感知的。
高性能
在數據采集端其實負載很低,客戶端對應用的影響控制在 5% 以內。為什么能夠有比較高的性能?因為我們的客戶端會構建一個異步日志隊列。同時,會良好的管理內存和 CPU 的使用。
我們通過 AVRO 序列化傳輸,可以節省一半的帶寬。
通過設計日志數據格式,避免冗余數據。整個客戶端我們先把數據打到磁盤上面,磁盤 IO 比較高效。這個時候 IO 性能是比較重要的,如果我的日志格式是相當冗余的,會導致 IO 上升。所以我會做一些比較精巧的設計,讓整個日志相對來說比較小。
高可治理
客戶端的可治理也非常重要,在高可治理上面我們做了這些事情:
第一集成我們的配置中心。唯品會有一個比較重要的組件,就是配置中心,它承擔了所有的業務配置、系統配置、以及服務化的動態發現。我們現在服務治理也放在這個配置中心里面,包括服務的一些路由策略。當然在配置中心做了一些分群,讓整個管理比較可控。
通過這個配置中心我可以動態下發很多的指令,采樣率等等都是可以被動態的降級,比如 HTTP、OSP、SQL 等也可以關閉,出問題時,一鍵關閉這個客戶端的日志采集。
采樣率可以動態的調整,我不知道大家對這個采樣是怎么理解的。采樣是蠻有講究,采樣不是說我這個域要設一個采樣率,那個域要設一個采樣率,在全鏈路監控系統上面,采樣率必須要在調用源頭設置,需要在最上游去設置采樣率,然后采樣率會透傳到下游所有的節點上。每個服務一看上游給過來的,告訴說要采樣我就用它。所以整個采樣率是完全跟著最上游的節點來看,每個模塊不能隨便的去設采樣率。這個也是非常關鍵的一點,想明白這個就非常簡單了。
同時除了源頭采樣之外,我們也支持域級的采樣,雖然源頭設了采樣率,但是我不想跟隨,我就想自己設一個采樣率,也是可以支持的。這樣有一個什么后果?假如說我源頭設一個采樣率,你自己也設了一個,后果就是出了問題的時候,我去查我的調用鏈信息,如果不跟隨相同策略,有可能當中的鏈路會斷掉。
客戶端會上報客戶端的版本,這個也是相當的重要,因為在一個比較大的體系當中,版本的規劃與升級是相當重要,這個我們其實也踩了很多坑,因為業務在飛速發展,組件在飛速發展,這個時候如果需要考慮升級,就需要考慮線上到底有哪些版本,有哪些域需要推動他們去升級,我不知道對方需要什么版本,因為一段時間之內,他可能會出很多個版本,最多的時候我們有五、六個版本在線上跑,當出新版本的時候,你需要推動升級,有上千個域,你不知道有誰在用你的版本。所以我們會把所有的版本全上報到我們服務端,通過我們的治理平臺,會很快看到我每個域的版本。
敏感信息脫敏,這個也是非常重要的,因為我們采集的信息相當豐富,所有的出參入參都會采集,會有很多敏感的信息,帳務信息、用戶的登陸信息,這些都是需要脫敏的。
可升級性,輕量級客戶端,還是跟上面這個版本有關,我們的客戶端要能夠支持我持續升級,我不能說每個版本它的一直工作很好,我一改以后功能都需要去升級,所以可升級是相當重要的。
上面是建設客戶端需要注意的幾點。
2. 服務端 - 海納百川
下面是服務端,服務端我們形容它是海納百川,因為整個服務端的數據是海量的,每分鐘上億的峰值量,所以站在服務端角度我們要考慮這些事情:
流式計算
首先是流式計算,Spark 是一個主流的流式計算平臺,我們要關注幾點,這里我不想去講 Spark 的架構,更多的是我們怎么樣去用好它。
第一,Kafka 端建立多 Topic,之前老的方案我們會只建立 2 個 Topic,對 Spark 內存開銷比較大。因為 Spark 需要消費這 2 個 Topic,因為不同的指標其實需要的數據量是不一樣的,需要的數據類型是不一樣的,如果你 Topic 數量比較少,意味著我的 Spark 需要消費一個很大的池子,然后把池子里的數據做一個篩選過濾再去做指標計算,這個對 Spark 的內存需要是相當大的。
舉個例子,我的池子里面有一百條魚,我要算這一百條魚,不同的魚有不同的品種。假如我只算某一種魚類品種,我只需要把這種魚的類型挑出來再去算。如果是一百條還好,如果是一億條這個量是非常之大的,所以我們需要在客戶端的時候,首先把這些不同類型的日志分類,接著分發到不同的 Topic 上面,然后 Spark 按照不同的計算去消費不同的 Topic,這樣就不用一億條魚全部放到里面去算了。我只需要用不同的池子去算不同的指標。
第二,Wall Time Or Event Time,這是兩種不同計算的策略。
第一種是只算當前的時間,我根據當前的時間來算,根據當前的時間來算有一個重要的缺陷,由于日志上報其實是有延時的,有些日志可能受限于客戶端,可能網絡的問題,或者客戶端有失敗的調用,或者說客戶端和服務端連接的問題,或者客戶端的時間有問題,都會導致我的日志沒有很及時的跟上,沒有很及時的上報到服務端,所以通過 wall time 方式就會過濾到部分日志,精準度就不高。
第二種是 Event Time,是根據整個日志上報時間來的,不是根據當前時間來的。
第三,這里有個很重要的點,即我們現在基于 二階段計算模式 ,能夠保證整個 Spark 計算的精準性。大家知道 Spark 其實是一個批處理,更多的是一個批量的去處理日志,我們目前的策略會每隔 20 秒去消費這 20 秒的數據,然后把這 20 秒的數據算完之后推到 Kafka 里面,我先不給一個最終結果,后面還有另外一個集群,它會再去計算這 20 秒的數據,再把它聚合成一分鐘的數據。
這樣的好處是什么?因為二階段計算非常重要,它能夠容忍 30 分鐘的延遲,假設網絡有延時,或者客戶端有問題日志上報很慢,這時二階段就能夠包容這樣的錯誤,它會計算 30 分鐘以前的數據,經過聚合以后,通過一階段的計算,把這個數據量降到一個很低的程度,這個時候二階段可以重新去算這 30 分鐘的數據。這個架構是非常之輕巧,使得我們計算的精準性相當之高。
第四,我們會記錄數據回放 Checkpoint,支持容錯,這是流式計算很重要的一點。假設 Spark 垮了,需要從頭找當時消費的 Checkpoint 去做一些容錯,我會定時的把這個 checkpoint 存下來,需要做數據回放的時候,我們就會通過它重新去拉數據。
第五,數據流控。為了保證我們的流式計算,我們會在 Spark 端做一些流控。
第六,參數調優。內核參數其實也是相當重要,針對流式計算非常大的痛點就是,假設你忽然有一個非常大的 STW(Stop the World) GC,整個流式計算就會產生延時,產生延時的一個最大后果就是所有的指標趨勢圖,都會看到一個波谷,因為產生延時之后,整個指標就已經不準確了。
之前在沒有對內核參數做調整之前,經常會出現峰值高峰時,忽然監控打電話來說,為什么某個地方沒數據了,過了五分鐘又有了。這個時候就是因為系統在做 GC,或者有內存的換頁,或者有內存的回收。
所以我們對這塊做一些性能調優,讓整個內存的回收是比較平緩的。大家可以去關注一下 Linux numa 架構,它對這個內存的管理。所以我們在這上面做了一些調優,使得 Linux 內核對于內存的管理做得相對比較平緩,不至于非常激進,比如內存一旦不足就立刻做 swap 或者內存頁回收,導致整個系統 CPU 消耗很高,最終導致計算超時。
海量存儲
基于 OpenTSDB 保存全量指標,我們其實存的是全量日志,針對于指標你是可以查詢歷史上所有的數據點。
對于 TSDB,優化整個查詢性能很重要的兩點,第一點是控制 Cardinality 的大小,要保證在設計我們指標的時候,讓整個 cardinality 盡量的小,否則從上億條里面去做一個指標查詢是很慢的。
怎么樣讓它變小?很重要的一點就是通過 Shift to Metric 去設計這個 Metric Name。所以當我把這個這個 Metric Name 作為一個指標名的時候,我就能把我當前的指標變小,可能我的指標會膨脹,可能我一個指標變成十個指標了,但是我單純去指標的時候,就會變的很快。
高速查詢
最后是高速查詢,我們通過 ElasticSearch 建立索引。ElasticSearch 怎么分布,怎么部署,怎么建立索引?我們現在是按日,而且按域建立索引,每天每一個業務域,它會去建立一個索引,而且針對于不同的重要的業務域,我的索引機器也不一樣,有些很重要的業務域可能給它多一點資源。
Trace Log 進入 HBase,TraceId 作為 RowKey,一行保存一條調用鏈。
先查 ElasticSearch,再一鍵定位調用鏈。
告警平臺建設
告警平臺的建設,也是 Mercury 里面比較核心的一個功能。
首先是秒級告警。我們會端到端的延時30秒內,對異常日志和異常事件告警,同時對告警做一些收斂。
指標告警延時在兩分鐘內。我們的告警機做了動態分配,我們后面會有若干臺,現在大概有五臺告警機,每臺告警機會分配一些資源,這些資源都是可以動態分配的,也是基于ZK做的一個告警機的動態的注冊,動態資源的分配。所有的告警都會推到我們的告警大盤上面。
告警策略也是相當重要的,我們做了一些設計,我會分離我的告警策略和告警分派,你先去指定策略,然后再把策略分派給不同的業務。多維度、多監督、多級別告警規則配置,針對業務域、針對主機、針對API,各種不同的告警都會體現在我們的告警策略上面,所以我們的告警策略場景覆蓋率是相當高的。
再說一下多層告警的重要性。在我們的運營過程當中,要對不同的告警做不同的分類。我們現在其實會會警告和告警,產生警告的時候,通常來說可能我們的監控人員不會一下子看這個警告的問題。當這個警告問題上升到告警的時候,這些人才會撲上去。這個策略是蠻重要的,如果說你一下子產生告警,每個監控人員都一直要關注這些告警那是相當痛苦的。所以我們對告警會分不同的池子,哪些池子是你不需要很快的去看,哪些池子是需要你立刻去看的。
監控質量保障——篤定泰山
功能都有了,那我們還缺什么?我們要保障監控質量。
監控數據的質量是非常重要的,不能在大促的時候,監控先出問題。做過監控的人也知道,監控系統最麻煩的就是大促的時候,其他的業務域沒出問題,你自己先出了問題。監控數據量很大,而且對于很多業務團隊來說,監控系統的重要性不一定排在第一,所以它給到你的資源相對來說也是比較少的。所以經常會遇到說我的監控質量下降了。
我們可以通過下面的方式去保障我們的監控質量:
第一,在系統層,我們的監控系統的組件都會接入 Zabbix,對通常系統層面上的指標做一些監控,特別對機器的指標也要做一些監控。我們也會監控跨機房的網絡流量,因為這個流量也是非常寶貴的。
第二,對客戶端,我們會監控客戶端的日志落盤狀態。客戶端有問題日志沒有正常落盤,落盤之后是不是有丟失。agent 發送的日志的狀態,是不是有異常,是不是有堆積,channel size 就能夠幫你監控。
第三,組件的監控。我們會對 Kafka topic 做一個監控,持續觀察 topic 的入口流量。很重要的一點,對 lag 要進行監控,它能讓你很快的知道下游的消費是不是存在一些延遲。因為我們很多的問題都是通過監控 lag 能夠快速的發現的,所以對 lag 的監控和告警是非常關鍵的。還有 Flume 的指標、Channel Size,以及對 HBase 也會做很多的監控。
系統界面展示
講了這么多技術的東西,讓大家輕松一下,看幾個我們的畫面。
這是我們的入口,我們會提供若干這樣的功能,從業務監控、大盤、策略配置、調用鏈查詢、主機系統查詢,組件版本查詢等等。進入這個區域之后我們會展現更多的信息,曲線、服務信息、日常失敗、系統信息等等,都會在這個平臺上面。
這個是我截的一個調用鏈,相對來說還比較簡單,它只跨三四個域。響應的時間,察看細節,你可以看到調用鏈的細節信息。
這是一個告警策略的指定,大家可以看到我們會先去設計告警策略,然后在這些告警分配出去,告警很簡單,比如說連續五分鐘環比請求失敗率大于昨天的三倍。告警策略我可以組合,做一個規則組,當規則組同時滿足的時候我才告警。
這個是對業務域治理的功能,我們會每天去看哪些業務域什么時候接入的,負責人是誰,我的告警策略有沒有分配,我的告警機有沒有分配。如果出了問題,我會立刻排查標簽,是異常、正常,還是警告。所以我們的運營人員一看都知道說,你這個運營可能是異常的接入,他可以直接去找那個負責人做后續的跟進。
展望未來,智能化告警,開放平臺,打造我們唯品會后端的 SaaS 品牌。所謂 SaaS 就是說從客戶端你可以把你的數據推上來,推之后我們在這個平臺上面幫你做指標的展現。這個指標展現,可能涉及到你可以自定義很多的報表,同時我們可以幫你對所有指標都做告警,你不用關心后面的時間是什么樣的,你只要把數據送上來就可以了。包括容器化的監管,離線分析平臺,最后是對整個系統監控數據做結合。這些就是我們未來要做的一些事情。
Q&A
提問:你們應該對有對 client 進行改造的吧?
姚捷:對,我們有自己的插件。
提問:需要到生產的機器上去安裝這個東西?
姚捷:那肯定的,但是這個對業務系統不關心,它不是業務的部分,完全是部署在生產機上的 lib 而已,完全是運維去推動就可以。
提問:序列化直接在 client 做的?有沒有遇到機器的 CPU 過高?
姚捷:沒有遇到。我們對整個客戶端做過蠻多的壓力測試,單機的峰值量是蠻高的,我們一個域可能入口流量是五六千,但是五六千的 QPS 后面還會訪問很多的下游域,日志你可以認為單機有五六萬的 QPS。在現場我們做過一些壓測,CPU 過關,但是出現過 gc 頻繁的情況,因為對于 gc 的參數,優化也是蠻重要的,因為畢竟它會跟你爭搶增援,所以對 gc 的優化也是非常重要的,避免它去爭搶資源。
提問:剛才說在客戶端高性能的時候測試了一個并發隊列,一個是無鎖的,一個是有鎖的,那我想知道如果用一個無鎖隊列的話,因為它在沒有的時候,獲取的是 null,那您如何做到觸發式?
姚捷:無鎖隊列它的優點在于,它是類似于有兩個門,我的日志進入我的前門和后門的時候,有一個比較好的技術,能夠保證一個環形。但是這個隊列要足夠的長足夠大,當我日志量打滿我整個環形的時候,還是會包不住。所以基于這個特性,因為我們整個客戶端要做到容錯,當落盤出問題的時候,client 要保證不影響業務。所以基于這個前提,我們沒有用無鎖,因為你用無鎖之后,首先這個隊列要求比較大,這個環形如果比較大的話,性能比較好。如果無鎖比較小,所有的線程打滿這個環之后,落盤出了問題,這個業務上是不能接受的,寧可丟棄日志,也不能 fail,這個是我們在業務端的策略。
本文及本次沙龍相關 PPT 鏈接如下,也可點擊閱讀原文直接下載
http://pan.baidu.com/s/1nvnOEBf
來自:http://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=2653547643&idx=1&sn=c06dc9b0f59e8ae3d2f9feb734da4459&scene=0