阿里巴巴鷹眼技術解密


作者|周小帆

編輯|小智

最新一代的阿里全鏈路監控系統鷹眼 3.0,同時將基礎設施層、分布式應用層、業務邏輯層與客戶端層進行了全鏈路跟蹤;技術層面,鷹眼 3.0 日均處理萬億級別的分布式調用鏈數據,針對海量實時監控的痛點,對底層的流計算、多維時序指標與事件存儲體系等進行了大量優化,同時引入了時序檢測、根因分析、業務鏈路特征等技術,將問題發現與定位由被動轉為主動。

注:本文整理自阿里巴巴技術專家周小帆在 ArchSummit 2017 深圳站上的演講。

今天我講的是應用分布式鏈路追蹤技術。業界大部分的應用分布式追蹤的原理源自 Google 的一篇 Dapper 系統的論文,我們的鷹眼系統也不例外。今天講的這個議題和微服務框架是有一些關系的,大家可能聽微服務相很多遍了,對微服務框架帶來的好處也感同身受,比如說它提高了開發的效率,它具備更好的擴展性,這些好處大家也體會過了。可是微服務其實是一把雙刃劍,微服務同時也帶來了一些問題,而這些問題也就是我們的鷹眼系統需要解決的問題。

本文分為三個部分,第一個是阿里巴巴的分布式追蹤系統,也就是鷹眼系統的技術實現原理、基礎功能以及在阿里的使用場景。第二個想和大家分享一下這套系統背后的一些技術細節,包括流計算,存儲的架構演進,我們踩過的一些坑、技術層面一些優化是什么樣的,也會分享一下我們是如何對監控系統進行模塊化改造的。第三個就是我們如何把一個被動的監控系統轉成一個主動發現問題的系統,這一塊我們其實也是在做初步的嘗試和探索,在做的過程中也希望跟大家一起分享,拋磚引玉,交流一下經驗。

分布式鏈路追蹤技術原理

微服務之熵

微服務的好處已經不用多說,而微服務的壞處,大家看這張圖就明白了。這張圖是 2012 年淘寶核心業務應用關系的拓撲圖,還不包含了其他的非核心業務應用,所謂的核心業務就是和交易相關的,和錢相關的業務。這張圖大家可能看不清楚,看不清楚才是正常的,因為當時的阿里應用數量之多、應用間關系之混亂靠人工確實已經無法理清楚了。

基於微服務體系之下構建的業務系統存在的問題基本上分為四類,第一個是故障定位難,今天我們淘寶下單的動作,用戶在頁面上點購買按鈕,這么一個簡單操作,其實它背后是由十幾個甚至數十個的微服務去共同完成的,這十幾個甚至幾十個微服務也由不同的團隊去負責,這是微服務的過度協同帶來的結果,一旦出現問題,最壞情況下我們也許就要拉上十幾個團隊一起來看問題。

第二個問題是容量預估難,阿里每年要做若干次大促活動,在以前的巨石系統當中做容量預估是非常容易的,因為我們大促時候按照預估的流量與當前系統的單機壓測容量做一個對比,把所有的系統按比例去擴容就可以了。而實際上在大促的場景下,每一個系統在核心鏈路當中的參與度、重要性都是不一樣的,我們並不能對每一個系統做等比例的擴容,所以微服務架構下的容量預估也是一件難事。

第三個問題就是資源浪費多,資源浪費多首先是容量預估不准的一個后果,同時資源浪費多背后隱含的另一個問題就是性能優化難,為什么這么說呢?我們當打開一個頁面發現它慢的時候,我根本不知道這個頁面慢在哪里,瓶頸在哪里,怎么去優化,這些問題累積下來,資源的浪費也成為了一個巨大的問題。

第四個是鏈路梳理難,我們一個新人加入阿里的時候,老板讓他負責一個系統,他在這個復雜的微服務體系中,就像人第一次在沒有地圖沒有導航的情況下來到一個大城市一樣,根本不知道自己身在何處。應用負責人不知道自己的系統被誰依賴了,也不知道自己的系統下游會影響其他哪些人。

整體來看,我們所說的微服務之熵主要就包含了這四個問題。

鷹眼是什么

鷹眼就是主要的目的就是解決上面所說的這四個問題,我們首先來定義一下鷹眼這個系統,它是一個以鏈路追蹤技術為核心的監控系統,它主要的手段是通過收集、存儲、分析、分布式系統中的調用事件數據,協助開發運營人員進行故障診斷、容量預估、性能瓶頸定位以及調用鏈路梳理。它的靈感是來自於 Google 的 Dapper。

基本實現原理

我們來看一下它的基本實現原理。在阿里巴巴每天有超過一萬億次的分布式調用,這個數據其實也是很早之前統計的,如果在這一萬億次調用當中出現了一個問題,我們怎么去定位?看一下這個例子,系統 A 調用 B,B 調用 C,在這之后 A 又調用了 D,如果 B 調 C 出了問題的話,那么負責維護 A 系統的開發人員根本不知道問題到底出在哪里,他只知道這次調用失敗了,那么我們怎么樣解決這個問題?雖然現在的很多大公司都在重復造很多輪子,但還好在阿里巴巴中間件這個東西沒有被重復造出兩個,基礎設施還是相對比較統一的。所以我們可以在一套中間件里做統一埋點,在分布式調用框架、分布式消息系統、緩存系統、統一接入層、Web 框架層的發送與接收請求的地方做統一埋點,埋點的數據能夠被一套中間件在系統之間進行無縫透傳。

當用戶的請求進來的時候,我們在第一個接收到這個請求的服務器的中間件會生成唯一的 TraceID,這個 TraceID 會隨着每一次分布式調用透傳到下游的系統當中,所有透傳的事件會存儲在 RPC log 文件當中,隨后我們會有一個中心化的處理集群把所有機器上的日志增量地收集到集群當中進行處理,處理的邏輯比較簡單,就是做了簡單清洗后再倒排索引。只要系統中報錯,然后把 TraceID 作為異常日志當中的關鍵字打出來,我們可以看到這次調用在系統里面經歷了這些事情,我們通過 TraceID 其實可以很容易地看到這次調用是卡在 B 到 C 的數據庫調用,它超時了,通過這樣的方式我們可以很容易追溯到這次分布式調用鏈路中問題到底出在哪里。其實通過 TraceId 我們只能夠得到上面這張按時間排列的調用事件序列,我們希望得到的是有嵌套關系的調用堆棧。

要想還原調用堆棧,我們還需要另外一個東西叫做 RPCId(在 OpenTracing 中有類似的概念,叫做 SpanID),RPCId 是一個多維序列。它經過第一次鏈路的時候初始值是 0,它每進行一次深入調用的時候就變成 0.1,然后再升就是 0.1.1,它每進行一次同深度的調用,就是說 A 調完 B 以后又調了 D 就會變成 0.2,RPCId 也隨着本次調用被打印至同一份 RPC Log 中,連同調用事件本身和 TraceId 一起被采集到中心處理集群中一起處理。

收集完了以后,我們對所有調用事件按照 RPCId 進行一個深度遍歷,我們就可以獲得這樣的一個調用堆棧,上圖中的調用堆棧實際上就是真實的淘寶交易系統里面進行下單的交易調用堆棧,可以看到這次調用經歷了很多系統。但大家在鷹眼的視角上面來看,就好像是在本地發生的一樣,我們可以很容易地去看到如果一次調用出現了問題,那問題的現象是出現在哪里,最后問題的根因又是發生在了哪里。除了調用異常的返回碼之外,我們在右邊其實還可以看到每次調用的耗時是多少,我們也可以看到每一次調用如果慢了它是慢在哪里。我們從這張圖中解釋了鷹眼是如何解決微服務四大問題中的故障定位難的問題,它可以通過倒排索引,讓用戶反查出每一次調用的全貌是怎樣的。

如果我們對萬億級別的調用鏈數據進行聚合,是否能夠獲得更有價值的信息?我們可以看一下,每一次調用除了它唯一標識 TraceID 和 RPCID 之外,還包含了一些標簽信息 (Tag),什么是標簽呢?就是具備共性的, 大家都會有的這么一些信息,比如說這次調用它分別經歷了這些系統,這些系統它每次調用的 IP 是什么,經過哪個機房,服務名是什么?有一些標簽是可以通過鏈路透傳下去的,比如入口 url,它透傳下去以后我就知道這次請求在下去之后發生的每一次事件都是由通過這個入口去發起的,那么如果把這些標簽進行聚合計算,我們可以得到調用鏈統計的數據,例如按某機房標簽統計調用鏈,我們就可以得到每個機房的調用次數的趨勢圖。

這樣做有什么好處呢?實際上在容量預估當中這樣做的好處是非常明顯的。我們來看一個例子,假如我們有一個交易下單入口標簽,我們對這樣的標簽做了聚合以后,不光能看到單次調用它的情況是如何,還能看到將這些調用鏈數據聚合以后,它的總調用次數是多少,平均耗時是多少,我可以發現系統當中熱點瓶頸在哪里,同時我們可以發現一些非法流量,也就是說我之前不知道的事。

比如說我們今天看到交易下單入口,訂單系統耗時比以往要長了,以往都是一毫秒,但現在是三毫秒,我們通過完整鏈路可以看到,實際上這次交易下單應該是一個單元內的操作,但是有一部分流量因為業務邏輯的原因,本該到杭州的數據庫最后跑到上海的數據庫,這么一個跨集群的網絡調用,實際上會導致整體的耗時增加,我們可以通過這種方式看到它熱點是由什么原因引起的。同時,我們在做雙 11 流量預估的時候,機器預估其實可以很容易做,因為我們只要知道交易下單入口我們預期的峰值是多少,可以按照平時的調用比例知道這次下單入口,在下游的每一個調用環節分攤到的基線流量是多少,根據基線流量來做等比例的擴容,就可以得到雙 11 相對來說比較精准的擴容機器數量。

這是真實的我們系統當中的下單鏈路聚合結果圖。除了我剛才說的一些點,我們還可以獲得一些什么呢?比如說易故障點,也就是說這個系統看上去大面上沒什么問題,但是偶爾它會出一些小問題。為什么我們說是易故障點,因為一旦它出現問題,下游的鏈路就終止了,也就是說調用對下游系統其實是強依賴的關系,那我們可以認為這個鏈路如果有一天下游系統真的掛了,那么整條鏈路的穩定性很可能出現問題,我們可以根據這些數據幫助用戶提前發現這些潛在的問題。

第一節就是對基礎功能的小結,它分為兩部分的功能,第一個是通過 TraceId 和 RPCId 對分布式調用鏈的堆棧進行還原,從而實現故障定位的功能。同時通過調用鏈數據分析,將這些入口、鏈路特征、應用、機房這么一些 tag 進行聚合統計,可以做到容量預估、性能瓶頸的定位以及調用鏈的梳理,所有這些都包含在我們在 2012 年發布的第一版鷹眼系統中,我們接下來看一下這套系統背后的技術演進過程。

EagleEye 架構演進

鷹眼 2012 年架構

這是我們 2012 年架構,這一套架構完成了剛才我在第一章里面所說的這些功能。其實后端的技術架構看上去非常簡單,但實際上是非常“重”的,我們整體的技術架構實現的大概是這樣一個流程,中間件會打出調用事件流,統一在所有機器上安裝的 agent 把數據上報到收集集群,然后數據進行一些簡單的清洗以后,將它存到 HDFS 當中。后面我們做兩件事。

第一個就是把調用鏈數據按照 TraceId 去做一個排序, 這樣用戶去查找的時候就可以通過類似像二分查找法的這種方式, 定位到 TraceId 經歷的所有的調用事件。第二件事是按照 tag 進行聚合得到了一個統計報表。2012 年的這個架構初步滿足了功能,但可以看到明顯的問題是第一個不夠實時,因為整個 Hadoop 的這一套東西是批次執行的,我們批次越大,它整體的吞吐量就越大,那么它顯而易見的問題就是不夠實時。我記得當時我們的延遲大概是一個多小時左右,也就是說發生了問題一個多小時以后才可以查到。第二個是不夠輕量,如果我們在多個機房輸出的話,每個地方都要部署這么重的一套東西,我們越來越深刻地意識到對於監控數據來說,它的價值隨着時間的推移迅速地衰減,如果我們不能第一時刻給用戶提供到這些數據的話,實際上我們的監控數據沒有發揮出它最大的價值。

鷹眼 2014 年架構

也因為這樣的原因,我們在 14 年的時候完成了這么一個實時化的改造,我們把原來比較簡單的、職責較為單一的負責鏈路調用收集的中心集群改造成了用現在大家都知道的流計算引擎去完成這件事。我們把一部分核心的,我們認為比較重要的,用戶認為比較重要的數據通過流計算引擎增量計算,第一時間經過統計和聚合存儲到 HBase 當中,通過大屏幕可以第一時間實時地看到用戶整體的微服務之間的調用流量情況。通過實時化的改造我們也催生出了一些場景,比如說 14 年,在全鏈路壓測的時候鷹眼成為了不管是運維人員還是開發人員非常重要的數據支撐工具,它可以實時看到流量壓測下來以后每個系統的響應情況和鏈路之間的調用關系。同時實時流量調度與限流也是會基於這么一個調用鏈的情況去追溯到,比如說我發現有個下游系統扛不住了,那么我可以根據這個鏈路數據反過來追溯到上游,去看到鏈路數據的發源地是哪里,是手機淘寶還是天貓的交易。可以根據這樣的鏈路追溯實時地去響應去做一些流量調度和限流的工作,異常鏈路整個的數據必須以非常高的實時性呈現給用戶。

鷹眼 2016 年架構

那么 2016 年我們又做了哪些呢?這套系統足夠實時,但是還不夠輕量,因為 Hadoop 還在那,那么 2016 年我們徹底把 Hadoop 那一套給拋棄掉,把所有的統計計算全部變到了實時引擎當中。每天幾萬億查詢的調用鏈事件存在 HBase 當中顯然是扛不住的,我們是放到一個叫做 HiStore 的 MPP 列式數據庫當中,這一套列式存儲數據庫不但能夠完成原來按照 TraceId 的事情,同時它還可以通過耗時超過多少毫秒,錯誤碼是多少各種各樣的多維查詢條件,把 TraceId 給查出來,更加方便用戶去查找問題。

流計算挑戰

我們在實施這套流計算的過程當中遇到一些坑。第一個我們回顧一下離線計算實時計算區別,離線計算實際上是通過批次計算這么一個手段,對靜態的文件進行分而治之的 map-reduce 的工作,流計算實際上是對無限的流數據切成很小的批次,對每一個批次進行的一個增量的計算,也就是說數據是不斷上來的,監控數據不斷產生的。以往的做法是把它存到一個大的存儲當中,后面悠哉悠哉地去跑一下,計算任務掛了也沒有關系。但是流計算我們不能這么做,我們必須要保持 24 x 7 的穩定性,沒有辦法停機維護的。因為一停機的話整個監控數據掉下來,因此系統必須具備自愈能力。解決方案其實是我們跟 JStorm 團隊進行了緊密的合作, 做了不少優化,比如說把中控節點改成了高可用,自帶 Exactly-Once 功能,當數據出現問題的時候,我們可以永遠通過上一回滾點去回滾到上批次的數據,這樣可以做到監控數據永不停息,永不丟失。

流計算第二個挑戰我剛才也提到它的中間結果是盡量不落地的,那么不落地帶來的問題就是說它實際上要比離線計算要難得多。舉一個例子,統計全量數據,如果我們是統計一個入口 UV 這件事,其實我們在離線計算當中,這是非常容易做的。按照訪問 Id 排個序,遍歷得到它的 UV 就可以了,但是在流計算里面是比較難做的。這邊簡單提兩點,一個就是全量計算到增量計算的過程,這個過程我們實際上是用了一些開源流計算庫,這邊給推薦大家 StreamLib,它可以很容易地幫你通過近似計算估算的方式完成一些看上去在流計算里面比較難的事情。流計算就跟離線計算一樣,熱點問題在離線計算當中,因為我預先知道熱點在哪里,其實很容易去做數據的拆分,但是在流計算當中我們預先是不知道的。所以其實我們的做法也非常簡單,我們前置了一個 LocalReduce 節點,也就是說在所有的監控數據進來之前先在本地監控一次,實際上再發到下游的時候它的流量就是均勻的,它就不會對下游的節點產生影響。

監控系統

做監控系統,大家只要做過監控系統底層設施建設的其實都可能碰到這么樣一個問題,也就是說那這個問題,其實我在剛開始做鷹眼的時候也是碰到比較痛苦的一個問題,就是說凌晨兩點鍾突然監控的曲線掉下來了,這時候我應該給運維人員發報警,還是不發報警,為什么我很難做這個抉擇,因為我不知道監控的對象真的出了問題,還是監控系統本身的流計算部分出了問題,流計算系統是不是哪里卡住了,還是數據收集通道出現了問題。其實當流計算系統被應用到了監控領域中,它提出了更高的要求,一個叫做“確定性”的要求。“確定性”要求在監控系統里面,是遠遠大於最終一致性的,所以為了解決這個問題,我們看了一圈現在的流計算引擎提供的解法,實際上沒有很好的現成方案去解決這個問題。

相關優化

我們自己實現了一個齊全度算法來完成確定性的保證。它與 Apache Flink 中采納的 Snapshot 算法有些近似,它其實是在整個流的過程當中去安插一些屏障 (Barrier),我們可以做一個假設,在所有流計算數據產生的地方,數據都是有序的。也就是說我們在收集數據的時候,通過第一探測數據源的深度,第二個在數據時間間隔出現交替的時候,比如說從 12:10 跑到 12:11 的時候去安插一個屏障隨着流做傳遞,流計算過程中保證 FIFO,下游可以把這些屏障聚合起來,這樣最終數據落地的時候,我就可以知道數據源當中有多少個屏障已經達到了最終的存儲當中。通過這種方式,我們其實可以預測出當一個系統在任意一個時刻它的齊全度是多少,這樣的話我們其實可以很容易得到一件事,就是說這個線掉下去了,但是因為在某一個時間點的屏障還沒有完全到齊,所以我現在可以預測是因為監控系統卡住了,沒有辦法給下游的運維人員發報警。因為我知道現在數據還沒有收齊,我沒有具備確定性的閾值保證,是沒有辦法去發報警的。這個齊全度的算法,也就是我們在流計算當中,針對監控系統報警場景作出的確定性保證的優化。

存儲層優化

存儲層的優化也說一下,我們一開始是用 HBase 來做倒排索引的,其實我們現在在測試環境當中還是用 HBase 來存,因為簡單可靠。第二個階段也就是我們在 2012 年的時候,把這個 TraceId 進行分片,按 TraceId 排序,反過來用戶通過二分查找方式進行查找。實際上我們現在是用了列式存儲的技術,區別是把同一列的內容用物理相鄰的方式進行存儲,這樣可以換來更好的壓縮比。

因為我們知道對於調用鏈的數據來說,大部分的調用鏈數據都是一些非常相近的數值型類型,比如說 2ms,3ms,1ms 這樣的數據,如果物理上能夠連續地存儲在一起的話,它的壓縮比是非常高的,我們實際通過我們內部叫做 HiStore 這么一個產品, 經過這個產品的壓縮以后,我們整體調用鏈的壓縮比最高能達到 20:1,也就是說每天如果是 100G 調用鏈日志,我們最終壓縮下來只有 5G。

指標存儲,因為大家對現在對時間序列數據庫的開源的實現應該也有所了解,我們對 OpenTSDB 也做了一些改造,第一個把 Proxy 層直接干掉了,降低了網絡開銷和一些不確定性。第二個 OpenTSDB 必須讓你的數據一次算完指標,直接丟到里面存儲,沒有辦法再進行更新的操作。而在一個真實的流計算場景下,我們知道數據有早來的、遲來的,因此業務上原本應該屬於同一個時間窗口的兩條數據有可能實際卻在相差非常遙遠的兩個系統時間內到達流計算引擎,晚到的數據對於原先指標的更新的操作就很難去做。我們在基於 HBase 的時序存儲的背后增加了應對這種場景的 Co-Processor,對於這些晚來的數據背后可以進行一個合並操作,變相地解決了流計算當中數據和時間窗口不對齊的問題。

模塊化改造

下面一個議題上是我們對鷹眼進行的模塊化改造,我先講一下背景, 大家如果對分布式調用鏈系統非常熟悉的話,實際上它的核心還是在於 TraceId,也就是說我要查什么問題必須有 TraceId 才行,但實際業務當中碰到的問題,都不是開發人員或者運維人員發現的,而是一線的客服發現的,是業務操作人員發現的,他會跟你說某某訂單號的訂單有問題,某某用戶發現某某商品狀態不對。其實這些問題都是跟業務緊密相關的,實際上最終所有用戶向我們提出了一個需求,需要能夠將業務 Id 和 TraceId 雙向綁定,第二個是業務指標和系統指標雙向關聯。這兩個需求的本質都是用戶需要“自定義”自己的鏈路。這樣的需求來了,我們按照 2012 年的架構來做,就出現了一些問題。

按照我們之前所描述的架構,一種簡單解決自定義鏈路數據的解決方法是,讓所有的用戶都把自定義的數據按照規范打同一份日志,所有的這些計算方式我們沿用原來的那一套,用統一的方式去處理用戶的自定義鏈路日志,把它和另外的中間鏈路進行關聯就可以了,實際上我們發現在阿里的環境下這套方案沒法實施。第一個原因用戶的日志量根本是不可控的,存儲和計算的開銷很大。

第二是用戶的這些數據,從各個方面都充滿了自定義的需求,比如說它數據來源不一定是日志,可能是隊列,可能是數據庫的修改的 binlog,可能是巡檢、撥測的結果。數據過濾方式也不一樣,它聚合的維度更是五花八門,就算是我們系統的數據,聚合維度都是不一樣的。持久化方式也是不一樣的,因為我們原生的方案只提供兩種,一種是列式存儲,它是基於寫多讀少這么一個場景,有的用戶說我就是要毫秒級查詢,我想用某某存儲來存這些數據。部署方式也存在各種各樣,比如說跨機房、獨立部署、專有雲輸出的需求等。

這樣的自定義鏈路監控需求我們是沒有辦法滿足的。當需求無法滿足時,大家都喜歡造輪子,監控系統里面的這些輪子造起來還真的蠻有意思,它有流計算,高壓縮比的存儲,有各種各樣的數據收集,海量數據挑戰。所以我們在想,與其我們訂一套規范讓你們強制接入,然后你回過頭跟我們說我們的這套規范滿足不了你們的需求,所以你們得自己造一個輪子,還不如把輪子直接給用戶,讓用戶自己通過這些輪子造出自己的汽車來。一開始我們嘗試着自己在 pipeline 里面寫代碼。全鏈路壓測、線上精准回歸、故障主動發現的這些場景我們就在原來那套邏輯里面去寫,寫完了以后發現真的是扛不住了,因為我們光是解決中間自己的問題就已經連軸轉了。

后來我們發現在這套 pipeline 里雖然需求五花八門,但組成 pipeline 的各個組件其實存在大量復用的可能,所有的這些對於監控數據的計算邏輯都是可復用的。

積木塊系統

如果我們能夠把這些可被復用的邏輯變成積木塊,讓用戶按照自己的需求去拼裝監控系統的 pipeline,對用戶來說是一件很爽的事情。所以我們干脆就做了一套積木塊的系統,其實是把整個監控系統當中這些模塊,進行了抽象和分類,比如說切分、邏輯判斷、聚合、持久化、告警,還有一些用戶自定義的邏輯,這一塊也是借助了這套叫做 Google Blockly 開源可視化的框架,我們對它進行二次開發。用戶可以直接在我們的界面上,拼出自己的監控數據處理流程。

我們來看一個例子,假如有一個交易系統,現在系統里面有一份日志,日志按照豎線分隔分別代表不同含義,它對我們的要求是,第一: 如果操作出現失敗,將該業務與鷹眼調用鏈產生關聯,這樣根據交易的 ID 我們能查到底下鏈路到底失敗在哪里。第二個是現在原生的鷹眼里雖然有交易下單的微服務調用曲線,但實際上是想知道與之對應的各個來源交易額度,想跟微服務的調用曲線放在一個視圖上進行關聯的對比。

我們首先定義數據來源,然后定義切分規則豎線分隔,分別這些字符是什么意思。當返回碼為“ERROR”時,去記錄一個鷹眼事件,這個事件是什么呢?交易下單錯誤,然后我把 TraceId 和用戶的手機號進行關聯,同時 RPCId、日期都關聯上去,我們再定義一個 Aggregator 積木塊來做一個聚合計算,比如按照比如入口去進行一個聚合,聚合的計算是對價格的累加,聚合后順便存到 ODPS 阿里的大數據存儲平台,可能后面這個用戶還需要對這份日志去做一個離線的分析。

這一套積木塊的框架,只要在頁面上面簡單拖拽就可以完成,同時這個框架還提供了一個所見既所得編輯模式,也就是說你把樣例日志放在右上角,左邊拼出你的積木塊以后點一個測試,右邊結果就出來了,來驗證你這個積木塊的邏輯是否符合預期。點擊啟動這個積木塊就會被翻譯成流計算的邏輯,把它提交到當前比較空閑的一個流計算 Slot 去執行,當然這個翻譯的過程我們也是有一些優化。自動合並開銷比較小的算子,比如說簡單的一些切分、邏輯判斷,把它壓到一個 action 當中去執行。不必要的數據傳遞,也就是說下一步不需要的 key 和 value,其實我們幫它自動刪掉了,這樣用戶不會進行那些沒有必要的網絡開銷,點擊啟動以后這個邏輯就直接跑到我們鷹眼計算邏輯集群里面去執行了。

用戶對這套積木塊系統比較熟悉的話,基本上五分鍾就可以完成一個自定義鏈路的過程。自定義鏈路完成后的結果在圖中我們可以看到,在是鷹眼的系統調用堆棧之上,會穿插顯示出在與系統調用並行出現的業務事件,另外,由於 TraceId 與業務 Id 形成了雙向關聯,客服人員在進行排查問題的時候,只要輸入一個手機號,對應的所有系統鏈路就出來了。除了 Id 關聯之外,業務指標和系統指標也實現了雙向關聯,我們可以在一個視圖中看到左邊是服務用量,右邊是各個業務的圖,在上面這張圖的例子中我們可以看到這個時間點的整體調用量上去了,我們可以知道大部分是來自於淘寶業務,其他的兩個天貓和聚划算的業務量是沒有什么變化的。

模塊化改造的結果,總結一下就是 2014 的第一個季度以前鷹眼是一個只能接受固定來源格式、按固定方式清洗、聚合、持久化的監控系統,到了 2014 年的 Q1 以后,實際上它也變成了一個自定義流式數據采集、清洗、計算、持久化的系統,它可以讓用戶自定義的鏈路數據和原來的鷹眼鏈路數據進行雙向的關聯,很快的,這套系統就在用戶當中推廣起來了。

截止七月前兩天還統計了一下,整個鷹眼的集群線上作業數超過了 1780 了,實際上其中只有 2 個是鷹眼原生的鏈路統計,其他都是由用戶自己配置的,可以說我們是提供了一套接入平台,是用戶幫助我們構建了完整的鷹眼全鏈路監控體系。每天日均處理量是一個 PB 以上,秒級處理峰值是 7000 萬每秒。除了原先中間那塊藍色中間件之外,我們還接入了下面橘黃色的用戶業務上面的數據以及一些其他上下游的基礎設施的鏈路數據,比如說移動用戶終端、瀏覽器等設備的鏈路數據,還有數據庫層面的數據,我們把 TraceId 和數據庫的 binlog 打通了,當然這個也是依賴於我們數據庫團隊的一些改造。

上面紅色的部分實際上是模塊化之前,模塊化之后藍色部分就是用戶自定義的鏈路,日志事件流、數據庫事件流、終端事件流都可以通過自定義的邏輯存到指定的存儲當中,同時它的這些數據一定要通過 TraceId 和我們原生的這些鷹眼數據進行關聯,這樣就算大家再怎么重復造輪子,最終都可以關聯在一起,為一輛汽車所用,這個才是造輪子的最終目的。

從被動到主動

我們聊一下從監控系統如何從被動報警轉化為主動發現,這一轉變是我們從去年開始啟動的一個項目。剛才大家看到的鷹眼系統目前已經已經到了 7000 萬每秒的處理峰值,在這個之前其實我們不斷地做優化,2016 年以前我們自己一直陶醉在技術優化的享受當中。到了去年的時候,我們開始反思問自己一些問題,這些問題包括:我們真的需要存儲每一條鏈路嗎?就算我們的壓縮比很高,但實際上隨着阿里流量不斷的增長,不管怎么優化存儲量也是相當驚人的。第二個是就算我們有那么多數據,用戶在上面配了這么多報表,我們給用戶算出這么多報表,用戶真的理解每個報表的含義嗎?第三個是我們能不能比用戶更早發現問題,在這個之前實際上鷹眼還是一個被動的用戶出現問題了過來查問題的系統,我們能不能領先一步,在用戶發現問題之前提前把問題暴露,給用戶預知問題,甚至提示用戶問題的最終原因在哪里。

識別、關聯、定位

我們解決問題的方法基本上也是分為三個步驟,第一個是識別,第二個是關聯,第三個是定位,具體的說一下每一個步驟。

識別什么呢?識別每一個鏈路當中出現異常的情況。時序指標當中的異常點,也就是突然高上去那一下子,那個時間點我們要識別出來。指標中的一些離群點,比如說機房當中所有的機器,某些機器出現和其他機器不一樣的行為,我們把它識別出來。

我們還能識別什么?其實今年我們做了一個挺有意思的項目,用戶接了這么多的自定義日志進來,我們實際上把用戶的這些日志進行了自動的歸納和整理。平時大家做應用負責人的時候可能都會有一個經歷,我們常常會帶着很強的“主觀性”去觀察我們的日志。特別是在發布的時候會盯着日志看,看日志跟以前長得差不多,這次發布好像是沒什么問題,換一個人來發布的時候就完全懵了,因為他不知道日志以前長什么樣子。我們其實做這件事的目的就是幫你把日志每一個種類當中的次數歸納整理出來。

當你的日志出現異動,什么叫異動,如果你的日志里面長期出現某一類的異常,這個不算異動,這個叫破罐子破摔,這個異常沒有人修的,或者是前面開發的人都已經離職走了,沒人知道怎么回事。異動是什么,昨天沒有,今天有了,昨天每小時只有兩百條的,今天每小時有兩萬條,這是一個異動。

再說一下識別,我們會把這些異動給識別出來,也作為識別的一個依據,和之前的所有異常點結合在一起,進行一個關聯,怎么關聯呢?

第一個是按點關聯:同一個部署單元,比如說同一台機器上面或者同一個應用里面的這些東西可以相互關聯。第二個是按線關聯,時間點上靠近的,比如說這件事在某個時間點發生的,在前一分鍾發生了另外一件可疑的事,這兩件事其實可以關聯起來。第三個是按鏈路關聯,下面是一個鏈路,在 A 點上發生的事在 B 點上同一時刻也發生了,這兩件事就可能有關系。最終通過關聯的結果我們可以定位原因了,通過這三步識別、關聯以及最后定位,我們可以定位到最終這些相關聯的事到底什么是現象,什么是原因,可以把現象和原因做出有可能的關聯。

舉個例子,我們前段時間通過這套系統發現了一個案例,某個核心入口應用 A 的業務指標出現了小幅的波動,另外一個系統應用賣家中心日志出現了新增的異常堆棧,這兩件事通過識別把它識別出來,當然在同一個時間點上識別出了一堆其他亂七八糟的異常,我們是怎么把這兩件看似不相關的事情關聯起來呢?

第一,在波動前一分鍾,我們同時發現了做數據庫拆分有分庫分表的規則推送的變更,在這個變更發生前一分鍾我們發現了業務指標的波動。按點關聯是為什么,因為應用 B 實際上是接受到了配置變更的,那么按時間線關聯,實際上這兩個事情,時間線上面是非常接近的。鏈路關聯是什么呢?應用 A 是強依賴應用 B 的,兩個應用強依賴,其實是可以通過一些基線去得到。那么最終我就可以認為這一次的分布分表配置變更是引發 A 應用指標波動的高嫌疑原因,實際上我們通過識別出來異動新增的異常堆棧,人工驗證以后確實如此。也就是說這一套識別加上關聯再加上定位的手段,我們認為有可能是行之有效的,我們也准備將這套系統繼續開發下去,今后有什么新的進展也可以跟大家一起同步。

總 * 結

總結一下之前講的一些東西,實際上我之前講的這幾部分內容的順序,也就正好吻合鷹眼版本的演進史,第一版本實現基本的鏈路定位以及指標分析的能力。第二個是平台化,通過積木塊的方式把這些輪子給用戶,讓用戶自定義我們的鏈路,用模塊化平台化的手段讓所有用戶把不同的數據接入進來,共建我們的全鏈路系統。第三個版本實際上是全息排查,同時我們對流計算以及底下的一些存儲做了優化。

實際上如果我們去看整個監控領域的話,基礎運維層面是大概五年前大家都做得滾瓜爛熟的事情,再往上是應用層以及鏈路層的監控,這些監控通常是通過調用鏈的數據或者調用鏈聚合的數據來完成的。業務層面,我們希望通過業務和應用系統層面雙向的 TraceId 的關聯以及指標的關聯來完成一件事,就是業務出現了問題,我能第一時刻定位到底是哪個系統出了問題,哪個系統的變更可能導致業務層面給用戶感知的問題。

17 年我們的鷹眼系統也正式在公有雲向用戶開放,目前 EDAS 中的鷹眼包含了對阿里中間件 (Aliware) 體系之上構建的微服務系統提供了開箱即用的鏈路監控能力。而更加完整的自定義鏈路監控功能、前端瀏覽器監控以及其他相關的 APM 功能在阿里雲的 ARMS(Application Realtime Monitoring System) 上面也開放了,如果將 EDAS/PTS/ARMS 配合在一起使用的話基本可以讓一個企業在微服務治理、容量規划、應用鏈路監控以及全鏈路壓測方面做到和阿里相同的水准。同時我們內部也在做一些智能診斷相關的一些事情,包括業務鏈路自動梳理和自動根因定位的能力,在合適的時機也會在雲產品上開放給大家使用。

作者介紹

周小帆,阿里巴巴高級技術專家。8 年金融 + 電商 + 中間件工作經驗,目前就職於阿里巴巴中間件技術部,整體負責中間件的監控與數據化運營工作,同時為阿里商品、菜鳥、安全、國際站等多個業務部門提供了完整監控方案。參與了阿里近五年來監控體系的建設及演進。阿里雲“業務實時監控 (ARMS)”技術負責人。興趣是業務架構、分布式計算與數據存儲技術。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM