稜鏡-分散式實時計算的跟蹤校驗系統

lijinhui發表於2015-12-08

該文章來自於阿里巴巴技術協會(ATA)精選文章。


摘要:*目前,各種分散式實時計算系統已經在各大網際網路公司得到了廣泛應用。但是,這些實時系統的計算過程多不進行持久化,如果出現訊息丟失等異常情況,通常很難定位問題出現的位置和具體原因,更無法做到主動發現訊息丟失。對於廣告營銷等對訊息準確性要求較高的業務場景來說,這種訊息丟失的代價通常很高,即便很低的訊息丟失率也會造成大量的財物損失。為此,阿里媽媽開發了一套面向分散式實時計算框架storm的實時跟蹤校驗系統——稜鏡系統,稜鏡系統實時記錄每條訊息在storm上的處理路徑,主動發現訊息丟失情況並報警。本文詳細介紹了幾位作者在開發稜鏡中遇到的困難和相應的解決方案,相信對其他分散式實時計算系統的跟蹤校驗系統也有一定的借鑑意義。*

專案wiki

1.介紹:

1.1.稜鏡專案的背景

  如今的網際網路應用,日均資料處理量越來越大,對計算實時性的要求也越來越高。為此,各種分散式實時計算系統層出不窮,比較有名的有Yahoo S4,storm,puma等。其中storm由於具備易恢復、可擴充套件、高容錯等特性,目前被廣泛應用在阿里媽媽營銷系統的各條業務線上。
不過,雖然storm的acker機制巧妙地保證了每條訊息都會被完整處理,但這一機制也有其侷限:1)必須正確的呼叫ack和fail介面,對於邏輯複雜的應用,誤呼叫在所難免;2)和storm相連線的外部更新系統不在acker的監控範圍內;3)如果訊息處理出錯,無法確切知道在storm的哪個bolt出錯。
同時,由於Storm計算過程未進行持久化,無法檢視歷史訊息的處理路徑。這樣即便我們發現了某條訊息有處理不完整的情況出現,也很難復現。
在稜鏡系統上線之前,阿里媽媽的開發人員通常不能及時發現線上問題,有時甚至要晚於客戶發現。而為了定位這些問題,往往又需要分別查詢storm及storm訪問的多個外部分散式系統的日誌。由於這些日誌散落在叢集的各臺機器上,查詢起來非常費時,且有些日誌受限於單機的儲存能力,儲存的時效有限。這樣帶來的問題一是問題處理不及時,引發客戶投訴,客戶滿意度下降,造成財物損失;二是定位問題費時費力,定位成功率也不高;三是有些問題客戶自己可能也無法發現,或者發現後沒有及時反饋,導致bug一直線上上執行。

1.2.營銷實時系統對稜鏡的要求

  為了解決1.1節中提到的問題,我們開發了稜鏡系統,它實時地監測著storm系統的執行情況,記錄下每條訊息的處理路徑,方便開發人員復現問題。同時準實時地對每條訊息的處理路徑進行校驗,在發現問題時主動向開發和運維人員報警,並提供了一鍵訊息重發工具,在異常出現時做到及時恢復。
稜鏡系統在設計之初,就考慮到了營銷系統的特殊要求,提出了以下設計目標:
1. 精確性,作為一個跟蹤校驗系統,如果本身不夠精確,那麼必定引起使用者的不信賴,同時,營銷系統與收入、扣款直接相關的特性,也要求稜鏡必須做到足夠精確。
2. 實時性,實時系統的監測系統自然也需要滿足實時性,不然在使用者投訴後,再收到異常報警也沒有任何意義。
3. 對應用盡可能透明。阿里媽媽的營銷系統有數十、上百個拓撲,如果升級十分困難的話,也必然會阻礙稜鏡的推廣。對於稜鏡,非常幸運的一點是,阿里媽媽的多條業務線共用一套拓撲框架,不同的業務在這套框架下,通過不同的配置得到適用於自己的業務邏輯,故而稜鏡的改動可以集中在這個拓撲框架中,業務不需要關心。

2.稜鏡系統架構和跟蹤、校驗原理:

2.1.稜鏡系統總體架構:

![稜鏡系統的總體設計架構]
_design

2.1 稜鏡系統的總體架構

  圖2.1展示了稜鏡系統的總體架構。其中Spout/Bolt[A-C]是要監控的某個拓撲進行流式處理的多個分散式元件。Dispatcher和updated是storm訪問的外部更新系統,也在稜鏡的監控範圍內。ODPS(Open Data Processing Service)是阿里巴巴研發的海量離線資料處理平臺,提供了批量結構化資料的儲存和計算服務,稜鏡的跟蹤記錄、主動校驗計算、歷史資料查詢等都在ODPS平臺上進行。從資料流的角度看,在storm等叢集上收集到ODPS原始trace資料首先通過準實時merge將同屬於一條訊息的所有trace聚集到一起,再通過訊息校驗發現異常訊息、觸發報警,詳細的資料流處理將在2.3節中介紹。

2.2.trace資料的打點方式

  Spout/Bolt在接收和發射(emit)訊息之後各打一條trace日誌,每條日誌以key-value形式記錄下SeqID(每條訊息唯一的主鍵,在各個bolt間不變,用於對齊),execTime(在storm中打點時的時刻,精確到毫秒),appName(拓撲名),clusterName(叢集名稱),boltName(spout或者bolt的名稱), 機器ID以及一些其他自定義的個性化、多維度的資訊。
舉例來講,對於如圖2.1中的拓撲結構所要處理的某條訊息來說,它會在Spout/Bolt[A-C]的入口、出口各打一條trace日誌,共八條,這八條日誌組成該條訊息的處理路徑。

2.3.訊息跟蹤、主動檢驗流程

  如2.2節所述,每一條訊息在storm中進行處理時,都會產生多條散佈在各臺機器上的trace資料。 接下來需要對這些Trace資料進行收集、對齊和完整性校驗。整個流程包含以下幾個步驟:
1、 使用分散式系統日誌收集工具TimeTunnel將storm各節點上的trace日誌收集到ODPS上,表中每一行是一條原始的Trace日誌。
2、 對原始Trace資料進行解析、分列,並儲存於一張split表。這張表在查詢定位問題時使用,由於進行了分列,可以按照各種條件組成sql語句進行查詢。
3、 將Trace資料按照訊息主鍵(SeqID)進行對齊,我們稱這個過程為merge流程。經過對齊,同一條訊息的所有trace資料就被合併到一起,形成了一條訊息的處理路徑(tracing path)。
4、 對每條訊息的處理路徑進行完整性校驗(見2.4),如果發現有處理不完整的情況,則觸發報警。
以上步驟全部在ODPS以準實時的方式(小batch處理)進行處理,batch時間間隔可以進行調整。

2.4.主動校驗的原理

  所謂主動校驗,就是檢查每條訊息的處理路徑是否完整,是否走完了storm中預期要經過的所有bolt。同時,校驗時還必須考慮到以下幾種特殊情況
1、 可能有重傳。在訊息處理出現問題時,storm會通過重發訊息,防止瞬時故障造成的影響。
2、 可能有訊息分裂。在storm中,一個bolt可以emit多個訊息,我們稱這種情況為訊息分裂(1分N)。
3、 可能有主動丟棄,這種情況下訊息處理流程提前中止為正常情況。
為了解決上述三個問題,在稜鏡的主動檢驗中,採用瞭如下演算法:
1、 對訊息處理路徑上的trace進行排序,找到最後一次重傳的所有trace日誌,在主動校驗中僅考慮最後一次重傳。
2、 對最後一次重傳中每種spout/bolt入口、出口的trace日誌進行計數,檢視是否有訊息分裂的情況。如果有,則流程後方bolt的trace數也必須與之吻合。
3、 對於提前中止的情況,再檢查3.3節中將要介紹的ErrorCode,如果ErrorCode也表示異常,才認為該訊息處理路徑真的出現異常。

2.5.Debug tracing的實現

  利用2.1節中所述的架構,稜鏡還提供了debug tracing或者稱為即時tracing的功能。有些時候,開發同學需要線上上檢視某條訊息處理時的debug日誌(預設關閉)。這在以前只能通過重啟拓撲,開啟debug日誌選項,再到storm各節點上grep才能檢視。
在稜鏡中,由於已經有了日誌收集,日誌分列的架構,通過新增一些截獲debug日誌輸出的程式碼,就簡便地實現了這個功能。現在,開發同學只要在Storm的輸入訊息體里加入debug=true的選項,稜鏡就會把這條訊息的所有debug日誌都收集到split表中,供開發同學方便地查詢。

3.稜鏡開發遇到的困難和相應的解決方案

3.1. merge時間段區間劃分問題及兩階段merge的引入

merge_

3.1 merge時間段劃分問題

  現在考慮2.3節中的merge流程。在稜鏡的處理中,為保持實時性,對這一聚合過程採取了分小batch處理的方式。例如,本次處理0分到5分的資料,下次處理5分到10分的資料。但是,這種時間區間劃分方式會導致某些同屬一條訊息的處理路徑被切分到不同batch。圖3.1給出了這一問題的圖形化描述,其中,每個彩色長方形代表一條訊息的處理路徑,長方形上沿對應最早的spout的execTime時間,下沿對應最後一條trace日誌的execTime時間。黑線代表批處理時間區間的某個邊緣(如下邊緣)的可能劃分位置,從圖中可以看出,不管這個時間邊緣劃在哪裡,都會導致某條訊息處理路徑被一分為二。
為解決這一問題,我們將merge流程劃分為兩個階段,分別稱為merge1和merge2。在merge1階段,以15分鐘為一個時間區間進行一次聚合,這樣部分位於區間邊緣的訊息路徑(tracing path)將不可避免地被切分到兩個區間。所以在merge1做訊息聚合時,將本次處理區間內同一path的每條trace的execTime統一設定為該path所有trace中最小的execTime,這樣一來path在時間線上的表示也就由“方塊”壓縮成了“直線”,因此在merge2劃分時間區間時就不會再遇到時間區間邊緣的劃分問題。之後在merge2階段,以merge1時間區間的中點為邊緣再進行一次跨merge1分割槽的聚合操作,將merge1時被劃分到不同分割槽的同一訊息路徑重新聚集到一起。

3.2.對重傳的處理和時間戳不準促使UUID的引入

  在2.3節介紹的主動校驗演算法中,需要對訊息路徑上的trace進行排序,找出最後一次重傳的所有trace。理論上,這隻需要按每條trace的execTime大小排序就可以了。但是,作為一個分散式系統,storm各臺機器間的時間戳會有最多5毫秒的誤差,這會打亂排序的順序。
或者,既然我們知道訊息流過spout/bolt的順序,那按這個順序進行排序不是也可以嗎?這在正常情況下的確可以。不過重傳會導致這種排序演算法失靈。
為此,我們為每一次重傳引入一個唯一的UUID,它在spout中通過函式System.nanotime()獲得,可以精確到納秒。這樣,在多次重傳間就可以利用execTime+UUID得到每次重傳發生的相對位置,在一次重傳內,再利用Bolt間的相對位置確定排序順序。

3.3.有合理丟棄情況存在,稜鏡引入ErrorCode

  對於有些訊息來說,沒有走完整套訊息處理流程是正常情況。為了不產生誤報,我們在稜鏡中定義了一套返回值ErrorCode,用來表徵處理流程中的訊息丟棄是否符合預期。只要相關業務線外掛按照這套ErrorCode上報自己的處理結果,稜鏡就可以提供精準的主動校驗。

4.使用稜鏡的效能消耗

  圖4.1列出了兩個拓撲使用稜鏡前後的效能對比。可以看出,稜鏡造成的時延增加在16%以內,QPS下降約在5%。
稜鏡的效能消耗

4.1 稜鏡的效能消耗

5.稜鏡的應用場景分析

  目前,稜鏡專案已經在阿里媽媽的搜尋營銷、展示營銷、定向廣告等多個業務場景的多個storm拓撲上得到了廣泛的應用,取得了豐碩的成果。但是,稜鏡的應用場景絕不僅僅侷限於storm,任何具有分散式、訊息流式處理(實時或非實時的)架構的系統都可以通過接入類稜鏡的trace收集(timetunnel) + ODPS + 監控資料流pipeline的外部監控系統獲得歷史訊息查詢和訊息處理實時監測的好處,令這些系統由黑盒變白盒,為發現問題、定位問題提供方便。

6. 專案成果

  稜鏡上線以後,取得了激動人心的效果。訊息丟失的問題得到了全面修復,日均丟訊息數量從之前的280餘條降為現在的接近0條,相當於每年減少數百萬的財物損失。調查、定位問題的效率也大幅提升了20倍以上,例如淘寶直通車線上的某個問題,之前定位共花費了3人日,現在定位類似問題只需要簡單執行一條命令就可以快速復現。由於有了主動監測報警,新出現的訊息丟失可以得到快速發現和立即解決,相關投訴減少90%以上,提升了客戶滿意度。歷史訊息處理路徑查詢也變得簡單方便,圖6.1和6.2展示了稜鏡提供的console和WebUI兩種查詢工具的列印效果。利用這一工具,業務同學可以簡便、快速地查詢最近20天內storm所有訊息的處理路徑。
console_

6.1 console工具的列印效果

webUI_

6.2 webUi工具的列印效果

  同時,利用這些沉澱下的資料,我們每天進行一次日訊息處理量的全量統計,用郵件、網頁報表的形式將統計結果展示給各業務方,及時發現訊息處理量的異常波動。

7. 總結

  本文介紹了稜鏡這一分散式實時系統的跟蹤校驗系統,以及我們在開發中遇到的困難和相應解決方案。目前,稜鏡系統已經在阿里媽媽內部得到了廣泛應用,使用方在不修改程式碼的情況下就可以享受到稜鏡帶來的歷史訊息快速查詢的好處。
稜鏡的上線,讓Storm由黑盒變成了白盒,為阿里媽媽的開發人員及時發現和定位問題提供了極大的幫助。通過小batch的批處理方案,稜鏡做到了精確的準實時跟蹤校驗。據我們所知,這也是目前業界首創的解決方案。
所以,我們今天將稜鏡的架構和工程中的難點介紹出來,希望可以為其他分散式流處理系統的跟蹤校驗方案提供一些借鑑。


相關文章