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