卫星系统——酒店后端全链路日志收集工具介绍
背景
隨著酒店業(yè)務(wù)的高速發(fā)展,我們?yōu)橛脩?、商家提供的服?wù)越來越精細,系統(tǒng)服務(wù)化程度、復(fù)雜度也逐漸上升。微服務(wù)化雖然能夠很好地解決問題,但也有副作用,比如,問題定位。
每次問題定位都需要從源頭開始找同事幫我人肉查日志,舉一個簡單的例子:
“這個詳情頁的價格是怎么算出來的?”
一次用戶酒店可訂空房頁(POI詳情頁)訪問,流量最多需要經(jīng)過73個服務(wù)節(jié)點。查問題的時候需要先后找4~5個關(guān)鍵節(jié)點的同學(xué)幫我們登錄十多個不同節(jié)點的機器,查詢具體的日志,溝通成本極大,效率很低。
為了解決這個問題,基礎(chǔ)架構(gòu)的同學(xué)提供了MTrace(詳情可以參考技術(shù)博客:《分布式會話跟蹤系統(tǒng)架構(gòu)設(shè)計與實踐》)協(xié)助業(yè)務(wù)方排查長鏈路問題。
但是與此同時,還有許多不確定性因素,使問題排查過程更加艱難,甚至無果而終:
總結(jié)起來如圖所示:
目標(biāo)
我們的核心訴求有兩個:
然后我們對訴求做了進一步的拆分:
系統(tǒng)
搞清了核心訴求后,我們針對性地做了許多調(diào)研,最終定了一個系統(tǒng)的整體設(shè)計方案,這就是目前已經(jīng)上線并實踐已久的美團點評酒店「衛(wèi)星系統(tǒng)」。
下面,我們就來對系統(tǒng)做詳細介紹,包括一些核心細節(jié)點。
架構(gòu)
如下圖所示,衛(wèi)星系統(tǒng)從橫向分為鏈路和日志兩個部分。
鏈路部分是以MTrace為基礎(chǔ),用支持超時fallback下Trace信息傳遞的Hystrix-Trace插件來覆蓋全部場景,保證鏈路被完整采集。
日志部分在接入端有三大核心步驟,首先是依托于日志攔截組件實現(xiàn)對業(yè)務(wù)代碼零侵入的情況下收集系統(tǒng)中所有日志內(nèi)容,然后根據(jù)統(tǒng)一日志規(guī)范對日志進行格式化處理,最后通過基于logcenter日志傳輸機制實現(xiàn)日志到Kafka的傳輸。
從縱向又分為:
日志采樣方案
接入端是所有數(shù)據(jù)之源,所以方案設(shè)計極為關(guān)鍵。要解決的問題有:采集策略、鏈路完整性保障、日志攔截、日志格式化、日志傳輸。
有的業(yè)務(wù)單臺機器每天日志總量就有百G以上,更有不少業(yè)務(wù)因為QPS過高而選擇平時不打印日志,只在排查問題時通過動態(tài)日志級別調(diào)整來臨時輸出。所以,我們在最初收集日志時必須做出取舍。經(jīng)過分析,發(fā)現(xiàn)在排查問題的時候,絕大多數(shù)情況下發(fā)起人都是自己人(RD、PM、運營),如果我們只將這些人發(fā)起的鏈路日志記下來,那么目標(biāo)日志量將會極大減少,由日志量過大而造成的存儲時間短、查詢時效性差等問題自然得到解決。
所以我們制定了這樣的采集策略:
通過在鏈路入口服務(wù)判斷發(fā)起人是否滿足特定人群(住宿事業(yè)部員工)來決定是否進行日志采集,將采集標(biāo)志通過MTrace進行全鏈路傳遞。這樣就能保證鏈路上所有節(jié)點都能行為一致地去選擇是否進行日志上報,保證鏈路上日志的完整性。
日志攔截
作為核心要素的日志,如何進行收集是一個比較棘手的問題。讓業(yè)務(wù)方強制使用我們的接口進行日志輸出會帶來許多麻煩,一方面會影響業(yè)務(wù)方原有的日志輸出策略;另一方面,系統(tǒng)原有的日志輸出點眾多,涉及的業(yè)務(wù)也五花八門,改動一個點很簡單,但是全面進行改動難保不會出現(xiàn)未知影響。所以,需要盡可能降低對接入方代碼的侵入。
由于目前酒店核心業(yè)務(wù)已全面接入log4j2,通過研究,發(fā)現(xiàn)我們可以注冊全局Filter來遍歷系統(tǒng)所有日志,這一發(fā)現(xiàn),使我們實現(xiàn)了代碼零改動的情況下收集到系統(tǒng)所有日志。
日志格式化
業(yè)務(wù)系統(tǒng)輸出的日志格式不一,比如有的沒有打印TraceID信息,有的沒有打印日志位置信息從而很難進行定位。這主要帶來兩方面的問題,一方面不利于由人主導(dǎo)的排查分析工作,另一方面也不利于后續(xù)的系統(tǒng)優(yōu)化升級,比如對日志的自動化分析報警等等。
針對這些問題,我們設(shè)計了統(tǒng)一日志規(guī)范,并由框架完成缺失內(nèi)容的填充,同時給業(yè)務(wù)方提供了標(biāo)準(zhǔn)化的日志接口,業(yè)務(wù)方可以通過該接口定義日志的元數(shù)據(jù),為后續(xù)支持自動化分析打下基礎(chǔ)。
由框架填充統(tǒng)一日志信息這一過程利用到了log4j2的Plugins機制,通過Properties、Lookups、ContextMap實現(xiàn)業(yè)務(wù)無感知的操作。
日志處理
我們在最終的日志傳輸環(huán)節(jié)利用了日志中心的傳輸機制,使用日志中心的ScribeAppender實現(xiàn)日志傳輸至本地agent,然后上報到遠端Kafka,這樣設(shè)計有幾點好處:
我們的數(shù)據(jù)處理邏輯全部在Storm進行處理,主要包含日志存儲Squirrel(美團點評內(nèi)部基于Redis Cluster研發(fā)的純內(nèi)存存儲)、實時檢索與Trace同步。
目前日志中心ES能保證分鐘級別實時性,但是對于RD排查問題還是不夠,必須支持秒級別實時性。所以我們選擇將特定目標(biāo)用戶的日志直接存入Squirrel,失效時間只有半小時,查詢?nèi)罩緯r結(jié)合ES與Squirrel,這樣既滿足了秒級別實時性,又保證了日志量不會太大,對Squirrel的壓力可以忽略不計。
我們的系統(tǒng)核心數(shù)據(jù)有鏈路與日志,鏈路信息的獲取是通過MTrace服務(wù)獲得,但是MTrace服務(wù)對鏈路數(shù)據(jù)的保存時間有限,無法滿足我們的需求。所以,我們通過延時隊列從MTrace獲取近期的鏈路信息進行落地存儲,這樣就實現(xiàn)了數(shù)據(jù)的閉環(huán),保證了數(shù)據(jù)完整性。
鏈路完整性保障
MTrace組件的Trace傳遞功能基于ThreadLocal,而酒店業(yè)務(wù)大量使用異步化邏輯(線程池、Hystrix),這樣會造成傳遞信息的損失,破壞鏈路完整性。
一方面,通過Sonar檢查和梳理關(guān)鍵鏈路,來確保業(yè)務(wù)方使用類似transmittable-thread-local中的ExecutorServiceTtlWrapper.java、ExecutorTtlWrapper.java的封裝,來將ThreadLocal里的Trace信息,也傳遞到異步線程中(前文提到的MTrace也提供這樣的封裝)。
另一方面,Hystrix的線程池模式會造成線程變量丟失。為了解決這個問題,MTrace提供了Mtrace Hystrix Support Plugin插件實現(xiàn)跨線程調(diào)用時的線程變量傳遞,但是由于Hystrix有專門的timer線程池來進行超時fallback調(diào)用,使得在超時情況下進入fallback邏輯以后的鏈路信息丟失。
針對這個問題,我們深入研究了Hystrix機制,最終結(jié)合Hystrix Command Execution Hook、Hystrix ConcurrencyStrategy、Hystrix Request Context實現(xiàn)了覆蓋全場景的Hystrix-Trace插件,保障了鏈路的完整性。
HystrixPlugins.getInstance().registerCommandExecutionHook(new HystrixCommandExecutionHook() {@Overridepublic <T> void onStart(HystrixInvokable<T> commandInstance) {// 執(zhí)行command之前將trace信息保存至hystrix上下文,實現(xiàn)超時子線程的trace傳遞if (!HystrixRequestContext.isCurrentThreadInitialized()) {HystrixRequestContext.initializeContext();}spanVariable.set(Tracer.getServerSpan());}@Overridepublic <T> Exception onError(HystrixInvokable<T> commandInstance, HystrixRuntimeException.FailureType failureType, Exception e) {// 執(zhí)行結(jié)束后清空hystrix上下文信息HystrixRequestContext context = HystrixRequestContext.getContextForCurrentThread();if (context != null) {context.shutdown();}return e;}@Overridepublic <T> void onSuccess(HystrixInvokable<T> commandInstance) {// 執(zhí)行結(jié)束后清空hystrix上下文信息HystrixRequestContext context = HystrixRequestContext.getContextForCurrentThread();if (context != null) {context.shutdown();}} });HystrixPlugins.getInstance().registerConcurrencyStrategy(new HystrixConcurrencyStrategy() {@Overridepublic <T> Callable<T> wrapCallable(Callable<T> callable) {// 通過自定義callable保存trace信息return WithTraceCallable.get(callable);} });效果展示
比如以排查一次用戶點擊某POI詳情頁的TraceID為例子:
我們可以看到他在MTrace中的調(diào)用鏈路是這樣的:
在衛(wèi)星系統(tǒng)中,展示為如下效果:
可見,在保留了鏈路數(shù)據(jù)的基礎(chǔ)上,系統(tǒng)還將全鏈路節(jié)點日志聚合到了一起,提升了排查效率。
后續(xù)規(guī)劃
目前,系統(tǒng)還處于初級階段,主要用來解決RD在排查問題時的兩大痛點:日志信息的不完整與太分散,現(xiàn)在已經(jīng)滿足了這一需求。但是,全鏈路日志系統(tǒng)能做的不止這些,后續(xù)的主要規(guī)劃有如下幾方面:
作者簡介
- 亞輝,2015年加入美團點評,就職于美團點評酒旅事業(yè)群技術(shù)研發(fā)部酒店后臺研發(fā)組。
- 曾鋆,2013年加入美團點評,就職于美團點評酒旅事業(yè)群技術(shù)研發(fā)部酒店后臺研發(fā)組。
招聘信息
最后發(fā)個廣告,美團點評酒旅事業(yè)群技術(shù)研發(fā)部酒店后臺研發(fā)組長期招聘Java后臺、架構(gòu)方面的人才,有興趣的同學(xué)可以發(fā)送簡歷到xuguanfei#meituan.com。
總結(jié)
以上是生活随笔為你收集整理的卫星系统——酒店后端全链路日志收集工具介绍的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [完结]以C++与Java为例,详解数据
- 下一篇: 最强Java面试题全部合集,涵盖BAT大