谈阿里核心业务监控平台SunFire的技术架构
http://www.infoq.com/cn/articles/alibaba-core-business-monitoring-platform-sunfire
在2016年雙11全球購物狂歡節(jié)中,天貓全天交易額1207億元,前30分鐘每秒交易峰值17.5萬筆,每秒支付峰值12萬筆。承載這些秒級數(shù)據(jù)背后的監(jiān)控產(chǎn)品是如何實現(xiàn)的呢?接下來本文將從阿里監(jiān)控體系、監(jiān)控產(chǎn)品、監(jiān)控技術(shù)架構(gòu)及實現(xiàn)分別進(jìn)行詳細(xì)講述。
阿里有眾多監(jiān)控產(chǎn)品,且各產(chǎn)品分工明確,百花齊放。整個阿里監(jiān)控體系如下圖:
集團(tuán)層面的監(jiān)控,以平臺為主,全部為阿里自主研發(fā)(除引入了第三方基調(diào)、博睿等外部檢測系統(tǒng),用于各地CDN用戶體驗監(jiān)控),這些監(jiān)控平臺覆蓋了阿里集團(tuán)80%的監(jiān)控需求。
此外,每個事業(yè)群均根據(jù)自身特性自主研發(fā)了多套監(jiān)控系統(tǒng),以滿足自身特定業(yè)務(wù)場景的監(jiān)控需求,如廣告的GoldenEye、菜鳥的棱鏡、阿里云的天基、螞蟻的金融云(基于XFlush)、中間件的EagleEye等,這些監(jiān)控系統(tǒng)均有各自的使用場景。
阿里的監(jiān)控規(guī)模早已達(dá)到了千萬量級的監(jiān)控項,PB級的監(jiān)控數(shù)據(jù),億級的報警通知,基于數(shù)據(jù)挖掘、機(jī)器學(xué)習(xí)等技術(shù)的智能化監(jiān)控將會越來越重要
阿里全球運行指揮中心(GOC)基于歷史監(jiān)控數(shù)據(jù),通過異常檢測、異常標(biāo)注、挖掘訓(xùn)練、機(jī)器學(xué)習(xí)、故障模擬等方式,進(jìn)行業(yè)務(wù)故障的自動化定位,并賦能監(jiān)控中心7*24小時專業(yè)監(jiān)控值班人員,使阿里集團(tuán)具備第一時間發(fā)現(xiàn)業(yè)務(wù)指標(biāo)異常,并快速進(jìn)行應(yīng)急響應(yīng)、故障恢復(fù)的能力,將故障對線上業(yè)務(wù)的影響降到最低。
接下來將詳細(xì)講述本文的主角,承載阿里核心業(yè)務(wù)監(jiān)控的SunFire監(jiān)控平臺。
SunFire簡介
SunFire是一整套海量日志實時分析解決方案,以日志、REST 接口、Shell 腳本等作為數(shù)據(jù)采集來源,提供設(shè)備、應(yīng)用、業(yè)務(wù)等各種視角的監(jiān)控能力,從而幫您快速發(fā)現(xiàn)問題、定位問題、分析問題、解決問題,為線上系統(tǒng)可用率提供有效保障。
SunFire利用文件傳輸、流式計算、分布式文件存儲、數(shù)據(jù)可視化、數(shù)據(jù)建模等技術(shù),提供實時、智能、可定制、多視角、全方位的監(jiān)控體系。其主要優(yōu)勢有:
- 全方位實時監(jiān)控:提供設(shè)備、應(yīng)用、業(yè)務(wù)等各種視角的監(jiān)控能力,關(guān)鍵指標(biāo)秒級、普通指標(biāo)分鐘級,高可靠、高時效、低延遲。
- 靈活的報警規(guī)則:可根據(jù)業(yè)務(wù)特征、時間段、重要程度等維度設(shè)置報警規(guī)則,實現(xiàn)不誤報、不漏報。
- 管理簡單:分鐘級萬臺設(shè)備的監(jiān)控部署能力,故障自動恢復(fù),集群可伸縮
- 自定義便捷配置:豐富的自定義產(chǎn)品配置功能,便捷、高效的完成產(chǎn)品配置、報警配置。
- 可視化:豐富的可視化 Dashboard,幫助您定制個性化的監(jiān)控大盤。
- 低資源占用:在完成大量監(jiān)控數(shù)據(jù)可靠傳輸?shù)耐瑫r,保證對宿主機(jī)的 CPU、內(nèi)存等資源極低占用率。
Sunfire技術(shù)架構(gòu)如下:
(點擊放大圖像)
主要模塊實現(xiàn)及功能
針對架構(gòu)圖中的各個組件,其中最關(guān)鍵的為采集(Agent)、計算(Map、Reduce)組件,接下來將對這兩個組件進(jìn)行詳細(xì)介紹。
1. 采集
Agent負(fù)責(zé)所有監(jiān)控數(shù)據(jù)的原始采集,它以 Agent 形式部署在應(yīng)用系統(tǒng)上,負(fù)責(zé)原始日志的采集、系統(tǒng)命令的執(zhí)行。日志原始數(shù)據(jù)的采集,按周期查詢?nèi)罩镜姆?wù),且日志查詢要低耗、智能。Agent上不執(zhí)行計算邏輯。主要具有以下特點:
低耗
采集日志,不可避免要考慮日志壓縮的問題,通常做日志壓縮則意味著它必須做兩件事情:一是磁盤日志文件的內(nèi)容要讀到應(yīng)用程序態(tài);二是要執(zhí)行壓縮算法。
這兩個過程就是CPU消耗的來源。但是它必須做壓縮,因為日志需要從多個機(jī)房傳輸?shù)郊械臋C(jī)房。跨機(jī)房傳輸占用的帶寬不容小覷,必須壓縮才能維持運轉(zhuǎn)。所以低耗的第一個要素,就是避免跨機(jī)房傳輸。SunFire達(dá)到此目標(biāo)的方式是運行時組件自包含在機(jī)房內(nèi)部,需要全量數(shù)據(jù)時才從各機(jī)房查詢合并。
網(wǎng)上搜索zero-copy,會知道文件傳輸其實是可以不經(jīng)過用戶態(tài)的,可以在Linux的核心態(tài)用類似DMA的思想,實現(xiàn)極低CPU占用的文件傳輸。SunFire的Agent當(dāng)然不能放過這個利好,對它的充分利用是Agent低耗的根本原因。以前這部分傳輸代碼是用c語言編寫的sendfile邏輯,集成到Java工程里,后來被直接改造為了Java實現(xiàn)。
最后,在下方的計算平臺中會提到,要求Agent的日志查詢服務(wù)具備“按周期查詢?nèi)罩尽钡哪芰Α_@是目前Agent工程里最大的難題,我們都用過RAF(RandomAccessFile),你給它一個游標(biāo),指定offset,再給它一個長度,指定讀取的文件size,它可以很低耗的扒出文件里的這部分內(nèi)容。然而問題在于:周期≠offset。從周期轉(zhuǎn)換為offset是一個痛苦的過程。
在流式計算里一般不會遇到這個問題,因為在流式架構(gòu)里,Agent是水龍頭,主動權(quán)掌握在Agent手里,它可以從0開始push文件內(nèi)容,push到哪里就做一個標(biāo)記,下次從標(biāo)記繼續(xù)往后push,不斷重復(fù)。這個標(biāo)記就是offset,所以流式不會有任何問題。
而計算平臺周期任務(wù)驅(qū)動架構(gòu)里,pull的方式就無法提供offset,只能提供Term(周期,比如2015-11-11 00:00分)。Agent解決此問題的方式算是簡單粗暴,那就是二分查找法。而且日志還有一個天然優(yōu)勢,它是連續(xù)性的。所以按照對二分查找法稍加優(yōu)化,就能達(dá)到“越猜越準(zhǔn)”的效果(因為區(qū)間在縮小,區(qū)間越小,它里面的日志分布就越平均)。
于是,Agent代碼里的LogFinder組件撐起了這個職責(zé),利用上述兩個利好,實現(xiàn)了一個把CPU控制在5%以下的算法,目前能夠維持運轉(zhuǎn)。其中CPU的消耗不用多說,肯定是來自于猜的過程,因為每一次猜測,都意味著要從日志的某個offset拉出一小段內(nèi)容來核實,會導(dǎo)致文件內(nèi)容進(jìn)入用戶態(tài)并解析。這部分算法依然有很大的提升空間。
日志滾動
做過Agent的同學(xué)肯定都被日志滾動困擾過,各種各樣的滾動姿勢都需要支持。SunFire的pull方式當(dāng)然也會遇到這個問題,于是我們簡單粗暴的窮舉出了某次pull可能會遇到的所有場景,比如:
-
正常猜到了offset
-
整個日志都猜不到offset
-
上次猜到了offset,但是下次再來的時候發(fā)現(xiàn)不對勁(比如滾動了)
這段邏輯代碼窮舉的分支之多,在一開始誰都沒有想到。不過仔細(xì)分析了很多次,發(fā)現(xiàn)每個分支都必不可少。
查詢接口
Agent提供的查詢服務(wù)分為first query和ordinary query兩種。做這個區(qū)分的原因是:一個周期的查詢請求只有第一次需要猜offset,之后只需要順序下移即可。而且計算組件里有大量的和Agent查詢接口互相配合的邏輯,比如一個周期拉到什么位置上算是確定結(jié)束?一次ordinary query得到的日志里如果末尾是截斷的(只有一半)該如何處理…… 這些邏輯雖然縝密,但十分繁瑣,甚至讓人望而卻步。但現(xiàn)狀如此,這些實現(xiàn)邏輯保障了SunFire的高一致性,不用擔(dān)心數(shù)據(jù)不全、報警不準(zhǔn),隨便怎么重啟計算組件,隨便怎么重啟Agent。但這些優(yōu)勢的背后,是值得深思的代碼復(fù)雜度。
路徑掃描
為了讓用戶配置簡單便捷,SunFire提供給用戶選擇日志的方式不是手寫,而是像windows的文件夾一樣可以瀏覽線上系統(tǒng)的日志目錄和文件,讓他雙擊一個心儀的文件來完成配置。但這種便捷帶來的問題就是路徑里若有變量就會出問題。所以Agent做了一個簡單的dir掃描功能。Agent能從應(yīng)用目錄往下掃描,找到同深度文件夾下“合適”的目標(biāo)日志。
2. 計算
由Map、Reduce組成計算平臺,負(fù)責(zé)所有采集內(nèi)容的加工計算,具備故障自動恢復(fù)能力及彈性伸縮能力。計算平臺一直以來都是發(fā)展最快、改造最多的領(lǐng)域,因為它是很多需求的直接生產(chǎn)者,也是性能壓力的直接承擔(dān)者。因此,在經(jīng)過多年的反思后,最終走向了一條插件化、周期驅(qū)動、自協(xié)調(diào)、異步化的道路。主要具有以下幾個特點:
純異步
原來的SunFire計算系統(tǒng)里,線程池繁復(fù),從一個線程池處理完還會丟到下一個線程池里;為了避免并發(fā)bug,加鎖也很多。這其中最大的問題有兩個:CPU密集型的邏輯和I/O密集型混合。
對于第一點,只要發(fā)生混合,無論你怎么調(diào)整線程池參數(shù),都會導(dǎo)致各式各樣的問題。線程調(diào)的多,會導(dǎo)致某些時刻多線程搶占CPU,load飆高;線程調(diào)的少,會導(dǎo)致某些時刻所有線程都進(jìn)入阻塞等待,堆積如山的活兒沒人干。
對于第二點,最典型的例子就是日志包合并。比如一臺Map上的一個日志計算任務(wù),它要收集10個Agent的日志,那肯定是并發(fā)去收集的,10個日志包陸續(xù)(同時)到達(dá),到達(dá)之后各自解析,解析完了data要進(jìn)行merge。這個merge過程如果涉及到互斥區(qū)(比如嵌套Map的填充),就必須加鎖,否則bug滿天飛。
但其實我們重新編排一下任務(wù)就能杜絕所有的鎖。比如上面的例子,我們能否讓這個日志計算任務(wù)的10個Agent的子任務(wù),全部在同一個線程里做?這當(dāng)然是可行的,只要回答兩個問題就行:
- 如果串行,那10個I/O動作(拉日志包)怎么辦?串行不就浪費cpu浪費時間嗎?
- 把它們都放到一個線程里,那我怎么發(fā)揮多核機(jī)器的性能?
第一個問題,答案就是異步I/O。只要肯花時間,所有的I/O都可以用NIO來實現(xiàn),無鎖,事件監(jiān)聽,不會涉及阻塞等待。即使串行也不會浪費CPU。第二個問題,就是一個大局觀問題了。現(xiàn)實中我們面臨的場景往往是用戶配置了100個產(chǎn)品,每個產(chǎn)品都會拆解為子任務(wù)發(fā)送到每臺Map,而一臺Map只有4個核。所以,你讓一個核負(fù)責(zé)25個任務(wù)已經(jīng)足夠榨干機(jī)器性能了,沒必要追求更細(xì)粒度子任務(wù)并發(fā)。因此,計算平臺付出了很大的精力,做了協(xié)程框架。
我們用Akka作為協(xié)程框架,有了協(xié)程框架后再也不用關(guān)注線程池調(diào)度等問題了,于是我們可以輕松的設(shè)計協(xié)程角色,實現(xiàn)CPU密集型和I/O密集型的分離、或者為了無鎖而做任務(wù)編排。接下來,盡量用NIO覆蓋所有的I/O場景,杜絕I/O密集型邏輯,讓所有的協(xié)程都是純跑CPU。按照這種方式,計算平臺已經(jīng)基本能夠榨干機(jī)器的性能。
周期驅(qū)動
所謂周期驅(qū)動型任務(wù)調(diào)度,說白了就是Map/Reduce。Brain被選舉出來之后,定時撈出用戶的配置,轉(zhuǎn)換為計算作業(yè)模型,生成一個周期(比如某分鐘的)的任務(wù), 我們稱之為拓?fù)?Topology), 拓?fù)湟埠苄蜗蟮谋憩F(xiàn)出Map/Reduce多層計算結(jié)構(gòu)的特征。所有任務(wù)所需的信息,都保存在topology對象中,包括計算插件、輸入輸出插件邏輯、Map有幾個、每個Map負(fù)責(zé)哪些輸入等等。這些信息雖然很多,但其實來源可以簡單理解為兩個:一是用戶的配置;二是運維元數(shù)據(jù)。拓?fù)浔话惭b到一臺Reduce機(jī)器(A)上。
A上的Reduce任務(wù)判斷當(dāng)前集群里有多少臺Map機(jī)器,就產(chǎn)生多少個任務(wù)(每個任務(wù)被平均分配一批Agent),這些任務(wù)被安裝到每臺機(jī)器上Map。被安裝的Map任務(wù)其實就是一個協(xié)程,它負(fù)責(zé)了一批Agent,于是它就將每個Agent的拉取任務(wù)再安裝為一個協(xié)程。至此,安裝過程結(jié)束。Agent拉取任務(wù)協(xié)程(也稱之為input輸入?yún)f(xié)程,因為它是數(shù)據(jù)輸入源)在周期到點后,開始執(zhí)行,拉取日志,解析日志,將結(jié)果交予Map協(xié)程;Map協(xié)程在得到了所有Agent的輸入結(jié)果并merge完成后,將merge結(jié)果回報到Reduce協(xié)程(這是一個遠(yuǎn)程協(xié)程消息,跨機(jī)器);Reduce協(xié)程得到了所有Map協(xié)程的匯報結(jié)果后,數(shù)據(jù)到齊,寫入到Hbase存儲,結(jié)束。
上述過程非常簡單,不高不大也不上,但經(jīng)過多年大促的考驗,其實非常的務(wù)實。能解決問題的架構(gòu),就是好的架構(gòu),能簡單,為何要把事情做得復(fù)雜呢?
這種架構(gòu)里,有一個非常重要的特性:任務(wù)是按周期隔離的。也就是說,同一個配置,它的2015-11-11 00:00分的任務(wù)和2015-11-11 00:01分的任務(wù),是兩個任務(wù),沒有任何關(guān)系,各自驅(qū)動,各自執(zhí)行。理想情況下,我們可以做出結(jié)論:一旦某個周期的任務(wù)結(jié)束了,它得到的數(shù)據(jù)必然是準(zhǔn)確的(只要每個Agent都正常響應(yīng)了)。所以采用了這種架構(gòu)之后,SunFire很少再遇到數(shù)據(jù)不準(zhǔn)的問題,當(dāng)出現(xiàn)業(yè)務(wù)故障的時候我們都可以斷定監(jiān)控數(shù)據(jù)是準(zhǔn)確的,甚至秒級都可以斷定是準(zhǔn)確的,因為秒級也就是5秒為周期的任務(wù),和分鐘級沒有本質(zhì)區(qū)別,只是周期范圍不同而已。能獲得這個能力當(dāng)然也要歸功于Agent的“按周期查詢?nèi)罩尽钡哪芰Α?/p>
任務(wù)重試
在上節(jié)描述的Brain->Reduce->Map的任務(wù)安裝流程里,我們對每一個上游賦予一個職責(zé):監(jiān)督下游。當(dāng)機(jī)器發(fā)生重啟或宕機(jī),會丟失一大批協(xié)程角色。每一種角色的丟失,都需要重試恢復(fù)。監(jiān)督主要通過監(jiān)聽Terminated事件實現(xiàn),Terminated事件會在下游掛掉(不論是該協(xié)程掛掉還是所在的機(jī)器掛掉或是斷網(wǎng)等)的時候發(fā)送給上游。由于拓?fù)涫翘崆吧珊们揖邆渫陚涞拿枋鲂畔?#xff0c;因此每個角色都可以根據(jù)拓?fù)涞男畔碇匦律上掠稳蝿?wù)完成重試。
-
若Brain丟失,則Brain會再次選主, Brain讀取最后生成到的任務(wù)周期, 再繼續(xù)生成任務(wù)。
-
若Reduce丟失,每個任務(wù)在Brain上都有一個TopologySupervisor角色, 來監(jiān)聽Reduce協(xié)程的Terminated事件來執(zhí)行重試動作。
-
若Map丟失,Reduce本身也監(jiān)聽了所有Map的Terminated事件來執(zhí)行重試動作。
-
為確保萬無一失,若Reduce沒有在規(guī)定時間內(nèi)返回完成事件給Brain,Brain同樣會根據(jù)一定規(guī)則重試這個任務(wù)。
過程依然非常簡單,而且從理論上是可證的,無論怎么重啟宕機(jī),都可以確保數(shù)據(jù)不丟,只不過可能會稍有延遲(因為部分任務(wù)要重新做)。
輸入共享:在用戶實際使用SunFire的過程中,常常會有這樣的情況:用戶配了幾個不同的配置,其計算邏輯可能是不同的,比如有的是單純計算行數(shù),有的計算平均值,有的需要正則匹配出日志中的內(nèi)容,但這幾個配置可能都用的同一份日志,那么一定希望幾個配置共享同一份拉取的日志內(nèi)容。否則重復(fù)拉取日志會造成極大的資源消耗。那么我們就必須實現(xiàn)輸入共享,輸入共享的實現(xiàn)比較復(fù)雜,主要依賴兩點:
-
其一是依賴安裝流,因為拓?fù)涫翘崆鞍惭b的,因此在安裝到真正開始拉取日志的這段時間內(nèi),我們希望能夠通過拓?fù)湫畔⑴袛喑鲂枰蚕淼妮斎朐?#xff0c;構(gòu)建出輸入源和對應(yīng)Map的映射關(guān)系。
-
其二是依賴Map節(jié)點和Agent之間的一致性哈希,保證Brain在生成任務(wù)時,同一個機(jī)器上的日志,永遠(yuǎn)是分配相同的一個Map節(jié)點去拉取的(除非它對應(yīng)的Map掛了)。
站在Map節(jié)點的視角來看:在各個任務(wù)的Reduce拿著拓?fù)鋪碜缘臅r候,我拿出輸入源(對日志監(jiān)控來說通常可以用一個IP地址和一個日志路徑來描述)和Map之間的關(guān)系,暫存下來,每當(dāng)一個新的Reduce來注冊Map,我都判斷這個Map所需的輸入源是否存在了,如果有,那就給這個輸入源增加一個上游,等到這個輸入源的周期到了,那就觸發(fā)拉取,不再共享了。
其他組件
存儲:負(fù)責(zé)所有計算結(jié)果的持久化存儲,可以無限伸縮,且查詢歷史數(shù)據(jù)保持和查詢實時數(shù)據(jù)相同的低延遲。Sunfire原始數(shù)據(jù)存儲使用的是阿里集團(tuán)的Hbase產(chǎn)品(HBase :Hadoop Database,是一個高可靠性、高性能、面向列、可伸縮的分布式存儲系統(tǒng)),用戶配置存儲使用的是MongoDb。
展示:負(fù)責(zé)提供用戶交互,讓用戶通過簡潔的建模過程來打造個性化的監(jiān)控產(chǎn)品。基于插件化、組件化的構(gòu)建方式,用戶可以快速增加新類型的監(jiān)控產(chǎn)品。
自我管控:即OPS-Agent、Ops-web組件,負(fù)責(zé)海量Agent的自動化安裝監(jiān)測,并且承擔(dān)了整個監(jiān)控平臺各個角色的狀態(tài)檢測、一鍵安裝、故障恢復(fù)、容量監(jiān)測等職責(zé)。
轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/articles/9121106.html
總結(jié)
以上是生活随笔為你收集整理的谈阿里核心业务监控平台SunFire的技术架构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 鏖战双十一-阿里直播平台面临的技术挑战
- 下一篇: 颠覆传统的电商智能助理-阿里小蜜技术揭秘