【DevOps】阿里微服務之殤及分散式鏈路追蹤技術原理

本文來自周小帆在2017年ArchSummit全球架構師峰會的分享。

ArchSummit即將在2018年7月6日深圳華僑城洲際酒店開幕,更多分享內容請瀏覽:鏈接

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

作者介紹

周小帆,阿里巴巴高級技術專家。8年金融+電商+中間件工作經驗,目前就職於阿里巴巴中間件技術部,整體負責中間件的監控與數據化運營工作,同時為阿里商品、菜鳥、安全、國際站等多個業務部門提供了完整監控方案。

參與了阿里近五年來監控體系的建設及演進。阿里雲「業務實時監控(ARMS)」技術負責人。興趣是業務架構、分散式計算與數據存儲技術。

寫在前面

今天我講的是應用分散式鏈路追蹤技術。業界大部分的應用分散式追蹤的原理源自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也隨著本次調用被列印至同一份RPCLog中,連同調用事件本身和TraceID一起被採集到中心處理集群中一起處理。

收集完了以後,我們對所有調用事件按照RPCID進行一個深度遍歷,我們就可以獲得這樣的一個調用堆棧,上圖中的調用堆棧實際上就是真實的淘寶交易系統裡面進行下單的交易調用堆棧,可以看到這次調用經歷了很多系統。

但大家在鷹眼的視角上面來看,就好像是在本地發生的一樣,我們可以很容易地去看到如果一次調用出現了問題,那問題的現象是出現在哪裡,最後問題的根因又是發生在了哪裡。除了調用異常的返回碼之外,我們在右邊其實還可以看到每次調用的耗時是多少,我們也可以看到每一次調用如果慢了它是慢在哪裡。我們從這張圖中解釋了鷹眼是如何解決微服務四大問題中的故障定位難的問題,它可以通過倒排索引,讓用戶反查出每一次調用的全貌是怎樣的。

如果我們對萬億級別的調用鏈數據進行聚合,是否能夠獲得更有價值的信息?我們可以看一下,每一次調用除了它唯一標識TraceID和RPCID之外,還包含了一些標籤信息 (Tag)。

什麼是標籤呢?就是具備共性的,大家都會有的這麼一些信息,比如說這次調用它分別經歷了這些系統,這些系統它每次調用的IP是什麼,經過哪個機房,服務名是什麼?

有一些標籤是可以通過鏈路透傳下去的,比如入口url,它透傳下去以後我就知道這次請求在下去之後發生的每一次事件都是由通過這個入口去發起的,那麼如果把這些標籤進行聚合計算,我們可以得到調用鏈統計的數據,例如按某機房標籤統計調用鏈,我們就可以得到每個機房的調用次數的趨勢圖。

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

比如說我們今天看到交易下單入口,訂單系統耗時比以往要長了,以往都是一毫秒,但現在是三毫秒,我們通過完整鏈路可以看到,實際上這次交易下單應該是一個單元內的操作,但是有一部分流量因為業務邏輯的原因,本該到杭州的資料庫最後跑到上海的資料庫,這麼一個跨集群的網路調用,實際上會導致整體的耗時增加,我們可以通過這種方式看到它熱點是由什麼原因引起的。

同時,我們在做雙11流量預估的時候,機器預估其實可以很容易做,因為我們只要知道交易下單入口我們預期的峰值是多少,可以按照平時的調用比例知道這次下單入口,在下游的每一個調用環節分攤到的基線流量是多少,根據基線流量來做等比例的擴容,就可以得到雙11相對來說比較精準的擴容機器數量。

這是真實的我們系統當中的下單鏈路聚合結果圖。除了我剛才說的一些點,我們還可以獲得一些什麼呢?比如說易故障點,也就是說這個系統看上去大面上沒什麼問題,但是偶爾它會出一些小問題。

為什麼我們說是易故障點,因為一旦它出現問題,下游的鏈路就終止了,也就是說調用對下游系統其實是強依賴的關係,那我們可以認為這個鏈路如果有一天下游系統真的掛了,那麼整條鏈路的穩定性很可能出現問題,我們可以根據這些數據幫助用戶提前發現這些潛在的問題。

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

EagleEye 架構演進

鷹眼 2012 年架構

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

第一個就是把調用鏈數據按照TraceID去做一個排序,這樣用戶去查找的時候就可以通過類似像二分查找法的這種方式,定位到TraceID經歷的所有的調用事件。

第二件事是按照tag進行聚合得到了一個統計報表。2012年的這個架構初步滿足了功能,但可以看到明顯的問題是:

第一個不夠實時,因為整個Hadoop的這一套東西是批次執行的,我們批次越大,它整體的吞吐量就越大,那麼它顯而易見的問題就是不夠實時。我記得當時我們的延遲大概是一個多小時左右,也就是說發生了問題一個多小時以後才可以查到。

第二個是不夠輕量,如果我們在多個機房輸出的話,每個地方都要部署這麼重的一套東西,我們越來越深刻地意識到對於監控數據來說,它的價值隨著時間的推移迅速地衰減,如果我們不能第一時刻給用戶提供到這些數據的話,實際上我們的監控數據沒有發揮出它最大的價值。

鷹眼 2014 年架構

也因為這樣的原因,我們在2014年的時候完成了這麼一個實時化的改造,我們把原來比較簡單的、職責較為單一的負責鏈路調用收集的中心集群改造成了用現在大家都知道的流計算引擎去完成這件事。

我們把一部分核心的,我們認為比較重要的,用戶認為比較重要的數據通過流計算引擎增量計算,第一時間經過統計和聚合存儲到HBase當中,通過大屏幕可以第一時間實時地看到用戶整體的微服務之間的調用流量情況。

通過實時化的改造我們也催生出了一些場景,比如說2014年,在全鏈路壓測的時候鷹眼成為了不管是運維人員還是開發人員非常重要的數據支撐工具,它可以實時看到流量壓測下來以後每個系統的響應情況和鏈路之間的調用關係。

同時實時流量調度與限流也是會基於這麼一個調用鏈的情況去追溯到,比如說我發現有個下游系統扛不住了,那麼我可以根據這個鏈路數據反過來追溯到上游,去看到鏈路數據的發源地是哪裡,是手機淘寶還是天貓的交易。可以根據這樣的鏈路追溯實時地去響應去做一些流量調度和限流的工作,異常鏈路整個的數據必須以非常高的實時性呈現給用戶。

鷹眼2016年架構

那麼2016年我們又做了哪些呢?這套系統足夠實時,但是還不夠輕量,因為Hadoop還在那,那麼2016年我們徹底把Hadoop那一套給拋棄掉,把所有的統計計算全部變到了實時引擎當中。

每天幾萬億查詢的調用鏈事件存在HBase當中顯然是扛不住的,我們是放到一個叫做HiStore的MPP列式資料庫當中,這一套列式存儲資料庫不但能夠完成原來按照TraceID的事情,同時它還可以通過耗時超過多少毫秒,錯誤碼是多少各種各樣的多維查詢條件,把TraceID給查出來,更加方便用戶去查找問題。

流計算挑戰

我們在實施這套流計算的過程當中遇到一些坑:

第一個我們回顧一下離線計算實時計算區別,離線計算實際上是通過批次計算這麼一個手段,對靜態的文件進行分而治之的map-reduce的工作,流計算實際上是對無限的流數據切成很小的批次,對每一個批次進行的一個增量的計算,也就是說數據是不斷上來的,監控數據不斷產生的。

以往的做法是把它存到一個大的存儲當中,後面悠哉悠哉地去跑一下,計算任務掛了也沒有關係。但是流計算我們不能這麼做,我們必須要保持24x7的穩定性,沒有辦法停機維護的。因為一停機的話整個監控數據掉下來,因此系統必須具備自愈能力。

解決方案其實是我們跟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的關聯以及指標的關聯來完成一件事,就是業務出現了問題,我能第一時刻定位到底是哪個系統出了問題,哪個系統的變更可能導致業務層面給用戶感知的問題。

2017年我們的鷹眼系統也正式在公有雲向用戶開放,目前EDAS中的鷹眼包含了對阿里中間件(Aliware)體系之上構建的微服務系統提供了開箱即用的鏈路監控能力。

而更加完整的自定義鏈路監控功能、前端瀏覽器監控以及其他相關的APM功能在阿里雲的ARMS(Application Realtime Monitoring System)上面也開放了,如果將EDAS/PTS/ARMS配合在一起使用的話基本可以讓一個企業在微服務治理、容量規劃、應用鏈路監控以及全鏈路壓測方面做到和阿里相同的水準。

同時我們內部也在做一些智能診斷相關的一些事情,包括業務鏈路自動梳理和自動根因定位的能力,在合適的時機也會在雲產品上開放給大家使用。


推薦閱讀:

讀懂這100篇論文,你也能成為大數據專家
中國最稀缺的職業,如何成為一名出色的管理架構師?
SACC2017乾貨分享 | 李波:小米生態雲應用引擎實踐

TAG:架構 | 架構師 | 阿里巴巴集團 |