作者:海友 懷宇 亞平等
可觀測性作為系統高可用的重要保障,已經成為系統建設中不可或缺的一環(huán)。然而隨著業(yè)務邏輯的日益復雜,傳統的ELK方案在日志搜集、篩選和分析等方面愈加耗時耗力,而分布式會話跟蹤方案雖然基于追蹤能力完善了日志的串聯,但更聚焦于調用鏈路,也難以直接應用于高效的業(yè)務追蹤。
1. 背景
1.1 業(yè)務系統日益復雜
隨著互聯網產品的快速發(fā)展,不斷變化的商業(yè)環(huán)境和用戶訴求帶來了紛繁復雜的業(yè)務需求。業(yè)務系統需要支撐的業(yè)務場景越來越廣、涵蓋的業(yè)務邏輯越來越多,系統的復雜度也跟著快速提升。與此同時,由于微服務架構的演進,業(yè)務邏輯的實現往往需要依賴多個服務間的共同協作??偠灾?,業(yè)務系統的日益復雜已經成為一種常態(tài)。
1.2 業(yè)務追蹤面臨挑戰(zhàn)
業(yè)務系統往往面臨著多樣的日??驮V和突發(fā)問題,“業(yè)務追蹤”就成為了關鍵的應對手段。業(yè)務追蹤可以看做一次業(yè)務執(zhí)行的現場還原過程,通過執(zhí)行中的各種記錄還原出原始現場,可用于業(yè)務邏輯執(zhí)行情況的分析和問題的定位,是整個系統建設中重要的一環(huán)。目前在分布式場景下,業(yè)務追蹤的主流實現方式包括兩類,一類是基于日志的ELK方案,一類是基于單次請求調用的會話跟蹤方案。然而隨著業(yè)務邏輯的日益復雜,上述方案越來越不適用于當下的業(yè)務系統。
1.2.1 傳統的ELK方案
日志作為業(yè)務系統的必備能力,職責就是記錄程序運行期間發(fā)生的離散事件,并且在事后階段用于程序的行為分析,比如曾經調用過什么方法、操作過哪些數據等等。在分布式系統中,ELK技術棧已經成為日志收集和分析的通用解決方案。如下圖1所示,伴隨著業(yè)務邏輯的執(zhí)行,業(yè)務日志會被打印,統一收集并存儲至Elasticsearch(下稱ES)[2]。
圖1 業(yè)務系統ELK案
例傳統的ELK方案需要開發(fā)者在編寫代碼時盡可能全地打印日志,再通過關鍵字段從ES中搜集篩選出與業(yè)務邏輯相關的日志數據,進而拼湊出業(yè)務執(zhí)行的現場信息。然而該方案存在如下的痛點:
- 日志搜集繁瑣:雖然ES提供了日志檢索的能力,但是日志數據往往是缺乏結構性的文本段,很難快速完整地搜集到全部相關的日志。
- 日志篩選困難:不同業(yè)務場景、業(yè)務邏輯之間存在重疊,重疊邏輯打印的業(yè)務日志可能相互干擾,難以從中篩選出正確的關聯日志。
- 日志分析耗時:搜集到的日志只是一條條離散的數據,只能閱讀代碼,再結合邏輯,由人工對日志進行串聯分析,盡可能地還原出現場。
綜上所述,隨著業(yè)務邏輯和系統復雜度的攀升,傳統的ELK方案在日志搜集、日志篩選和日志分析方面愈加的耗時耗力,很難快速實現對業(yè)務的追蹤。
1.2.2 分布式會話跟蹤方案
在分布式系統,尤其是微服務系統中,業(yè)務場景的某次請求往往需要經過多個服務、多個中間件、多臺機器的復雜鏈路處理才能完成。為了解決復雜鏈路排查困難的問題,“分布式會話跟蹤方案”誕生。該方案的理論知識由Google在2010年《Dapper》論文[3]中發(fā)表,隨后Twitter開發(fā)出了一個開源版本Zipkin[4]。市面上的同類型框架幾乎都是以Google Dapper論文為基礎進行實現,整體大同小異,都是通過一個分布式全局唯一的id(即traceId),將分布在各個服務節(jié)點上的同一次請求串聯起來,還原調用關系、追蹤系統問題、分析調用數據、統計系統指標。分布式會話跟蹤,是一種會話級別的追蹤能力,如下圖2所示,單個分布式請求被還原成一條調用鏈路,從客戶端發(fā)起請求抵達系統的邊界開始,記錄請求流經的每一個服務,直到向客戶端返回響應為止。
圖2 一次典型的請求全過程(摘自《Dapper》)
分布式會話跟蹤的主要作用是分析分布式系統的調用行為,并不能很好地應用于業(yè)務邏輯的追蹤。下圖3是一個審核業(yè)務場景的追蹤案例,業(yè)務系統對外提供審核能力,待審對象的審核需要經過“初審”和“復審”兩個環(huán)節(jié)(兩個環(huán)節(jié)關聯相同的taskId),因此整個審核環(huán)節(jié)的執(zhí)行調用了兩次審核接口。如圖左側所示,完整的審核場景涉及眾多“業(yè)務邏輯”的執(zhí)行,而分布式會話跟蹤只是根據兩次RPC調用生成了右側的兩條調用鏈路,并沒有辦法準確地描述審核場景業(yè)務邏輯的執(zhí)行,問題主要體現在以下幾個方面:
圖3 分布式會話跟蹤案例
(1) 無法同時追蹤多條調用鏈路
分布式會話跟蹤僅支持單個請求的調用追蹤,當業(yè)務場景包含了多個調用時,將生成多條調用鏈路;由于調用鏈路通過traceId串聯,不同鏈路之間相互獨立,因此給完整的業(yè)務追蹤增加了難度。例如當排查審核場景的業(yè)務問題時,由于初審和復審是不同的RPC請求,所以無法直接同時獲取到2條調用鏈路,通常需要額外存儲2個traceId的映射關系。
(2) 無法準確描述業(yè)務邏輯的全景
分布式會話跟蹤生成的調用鏈路,只包含單次請求的實際調用情況,部分未執(zhí)行的調用以及本地邏輯無法體現在鏈路中,導致無法準確描述業(yè)務邏輯的全景。例如同樣是審核接口,初審鏈路1包含了服務b的調用,而復審鏈路2卻并沒有包含,這是因為審核場景中存在“判斷邏輯”,而該邏輯無法體現在調用鏈路中,還是需要人工結合代碼進行分析。
(3) 無法聚焦于當前業(yè)務系統的邏輯執(zhí)行
分布式會話跟蹤覆蓋了單個請求流經的所有服務、組件、機器等等,不僅包含當前業(yè)務系統,還涉及了眾多的下游服務,當接口內部邏輯復雜時,調用鏈路的深度和復雜度都會明顯增加,而業(yè)務追蹤其實僅需要聚焦于當前業(yè)務系統的邏輯執(zhí)行情況。例如審核場景生成的調用鏈路,就涉及了眾多下游服務的內部調用情況,反而給當前業(yè)務系統的問題排查增加了復雜度。
1.2.3 總結
傳統的ELK方案是一種滯后的業(yè)務追蹤,需要事后從大量離散的日志中搜集和篩選出需要的日志,并人工進行日志的串聯分析,其過程必然耗時耗力。而分布式會話跟蹤方案則是在調用執(zhí)行的同時,實時地完成了鏈路的動態(tài)串聯,但由于是會話級別且僅關注于調用關系等問題,導致其無法很好地應用于業(yè)務追蹤。
因此,無論是傳統的ELK方案還是分布式會話跟蹤方案,都難以滿足日益復雜的業(yè)務追蹤需求。本文希望能夠實現聚焦于業(yè)務邏輯追蹤的高效解決方案,將業(yè)務執(zhí)行的日志以業(yè)務鏈路為載體進行高效組織和串聯,并支持業(yè)務執(zhí)行現場的還原和可視化查看,從而提升定位問題的效率,即可視化全鏈路日志追蹤。
下文將介紹可視化全鏈路日志追蹤的設計思路和通用方案,同時介紹新方案在大眾點評內容平臺的落地情況,旨在幫助有類似需求的業(yè)務系統開發(fā)需求的同學提供一些思路。
2. 可視化全鏈路日志追蹤
2.1 設計思路
可視化全鏈路日志追蹤考慮在前置階段,即業(yè)務執(zhí)行的同時實現業(yè)務日志的高效組織和動態(tài)串聯,如下圖4所示,此時離散的日志數據將會根據業(yè)務邏輯進行組織,繪制出執(zhí)行現場,從而可以實現高效的業(yè)務追蹤。
圖4 業(yè)務系統日志追蹤案例
新方案需要回答兩個關鍵問題:如何高效組織業(yè)務日志,以及如何動態(tài)串聯業(yè)務日志。下文將逐一進行回答。
問題1:如何高效組織業(yè)務日志?
為了實現高效的業(yè)務追蹤,首先需要準確完整地描述出業(yè)務邏輯,形成業(yè)務邏輯的全景圖,而業(yè)務追蹤其實就是通過執(zhí)行時的日志數據,在全景圖中還原出業(yè)務執(zhí)行的現場。
新方案對業(yè)務邏輯進行了抽象,定義出業(yè)務邏輯鏈路,下面還是以“審核業(yè)務場景”為例,來說明業(yè)務邏輯鏈路的抽象過程:
- 邏輯節(jié)點:業(yè)務系統的眾多邏輯可以按照業(yè)務功能進行拆分,形成一個個相互獨立的業(yè)務邏輯單元,即邏輯節(jié)點,可以是本地方法(如下圖5的“判斷邏輯”節(jié)點)也可以是RPC等遠程調用方法(如下圖5的“邏輯A”節(jié)點)。
- 邏輯鏈路:業(yè)務系統對外支撐著眾多的業(yè)務場景,每個業(yè)務場景對應一個完整的業(yè)務流程,可以抽象為由邏輯節(jié)點組合而成的邏輯鏈路,如下圖5中的邏輯鏈路就準確完整地描述了“審核業(yè)務場景”。
一次業(yè)務追蹤就是邏輯鏈路的某一次執(zhí)行情況的還原,邏輯鏈路完整準確地描述了業(yè)務邏輯全景,同時作為載體可以實現業(yè)務日志的高效組織。
圖5 業(yè)務邏輯鏈路案例
問題2:如何動態(tài)串聯業(yè)務日志?
業(yè)務邏輯執(zhí)行時的日志數據原本是離散存儲的,而此時需要實現的是,隨著業(yè)務邏輯的執(zhí)行動態(tài)串聯各個邏輯節(jié)點的日志,進而還原出完整的業(yè)務邏輯執(zhí)行現場。
由于邏輯節(jié)點之間、邏輯節(jié)點內部往往通過MQ或者RPC等進行交互,新方案可以采用分布式會話跟蹤提供的分布式參數透傳能力[5]實現業(yè)務日志的動態(tài)串聯:
- 通過在執(zhí)行線程和網絡通信中持續(xù)地透傳參數,實現在業(yè)務邏輯執(zhí)行的同時,不中斷地傳遞鏈路和節(jié)點的標識,實現離散日志的染色。
- 基于標識,染色的離散日志會被動態(tài)串聯至正在執(zhí)行的節(jié)點,逐漸匯聚出完整的邏輯鏈路,最終實現業(yè)務執(zhí)行現場的高效組織和可視化展示。
與分布式會話跟蹤方案不同的是,當同時串聯多次分布式調用時,新方案需要結合業(yè)務邏輯選取一個公共id作為標識,例如圖5的審核場景涉及2次RPC調用,為了保證2次執(zhí)行被串聯至同一條邏輯鏈路,此時結合審核業(yè)務場景,選擇初審和復審相同的“任務id”作為標識,完整地實現審核場景的邏輯鏈路串聯和執(zhí)行現場還原。
2.2 通用方案
明確日志的高效組織和動態(tài)串聯這兩個基本問題后,本文選取圖4業(yè)務系統中的“邏輯鏈路1”進行通用方案的詳細說明,方案可以拆解為以下步驟:
圖6 通用方案拆解
2.2.1 鏈路定義
“鏈路定義”的含義為:使用特定語言,靜態(tài)描述完整的邏輯鏈路,鏈路通常由多個邏輯節(jié)點,按照一定的業(yè)務規(guī)則組合而成,業(yè)務規(guī)則即各個邏輯節(jié)點之間存在的執(zhí)行關系,包括串行、并行、條件分支。
DSL(Domain Specific Language)是為了解決某一類任務而專門設計的計算機語言,可以通過JSON或XML定義出一系列節(jié)點(邏輯節(jié)點)的組合關系(業(yè)務規(guī)則)。因此,本方案選擇使用DSL描述邏輯鏈路,實現邏輯鏈路從抽象定義到具體實現。
圖7 鏈路的抽象定義和具體實現
邏輯鏈路1-DSL
[
{
"nodeName": "A",
"nodeType": "rpc"
},
{
"nodeName": "Fork",
"nodeType": "fork",
"forkNodes": [
[
{
"nodeName": "B",
"nodeType": "rpc"
}
],
[
{
"nodeName": "C",
"nodeType": "local"
}
]
]
},
{
"nodeName": "Join",
"nodeType": "join",
"joinOnList": [
"B",
"C"
]
},
{
"nodeName": "D",
"nodeType": "decision",
"decisionCases": {
"true": [
{
"nodeName": "E",
"nodeType": "rpc"
}
]
},
"defaultCase": [
{
"nodeName": "F",
"nodeType": "rpc"
}
]
}
]
2.2.2 鏈路染色
“鏈路染色”的含義為:在鏈路執(zhí)行過程中,通過透傳串聯標識,明確具體是哪條鏈路在執(zhí)行,執(zhí)行到了哪個節(jié)點。鏈路染色包括兩個步驟:步驟一:確定串聯標識,當邏輯鏈路開啟時,確定唯一標識,能夠明確后續(xù)待執(zhí)行的鏈路和節(jié)點。
- 鏈路唯一標識 = 業(yè)務標識 + 場景標識 + 執(zhí)行標識 (三個標識共同決定“某個業(yè)務場景下的某次執(zhí)行”)
- 業(yè)務標識:賦予鏈路業(yè)務含義,例如“用戶id”、“活動id”等等。
- 場景標識:賦予鏈路場景含義,例如當前場景是“邏輯鏈路1”。
- 執(zhí)行標識:賦予鏈路執(zhí)行含義,例如只涉及單次調用時,可以直接選擇“traceId”;涉及多次調用時則,根據業(yè)務邏輯選取多次調用相同的“公共id”。
- 節(jié)點唯一標識 = 鏈路唯一標識 + 節(jié)點名稱 (兩個標識共同決定“某個業(yè)務場景下的某次執(zhí)行中的某個邏輯節(jié)點”)
- 節(jié)點名稱:DSL中預設的節(jié)點唯一名稱,如“A”。
步驟二:傳遞串聯標識,當邏輯鏈路執(zhí)行時,在分布式的完整鏈路中透傳串聯標識,動態(tài)串聯鏈路中已執(zhí)行的節(jié)點,實現鏈路的染色。例如在“邏輯鏈路1”中:
- 當“A”節(jié)點觸發(fā)執(zhí)行,則開始在后續(xù)鏈路和節(jié)點中傳遞串聯標識,隨著業(yè)務流程的執(zhí)行,逐步完成整個鏈路的染色。
- 當標識傳遞至“E”節(jié)點時,則表示“D”條件分支的判斷結果是“true”,同時動態(tài)地將“E”節(jié)點串聯至已執(zhí)行的鏈路中。
2.2.3 鏈路上報
“鏈路上報”的含義為:在鏈路執(zhí)行過程中,將日志以鏈路的組織形式進行上報,實現業(yè)務現場的準確保存。
圖8 鏈路上報圖示
如上圖8所示,上報的日志數據包括:節(jié)點日志和業(yè)務日志。其中節(jié)點日志的作用是繪制鏈路中的已執(zhí)行節(jié)點,記錄了節(jié)點的開始、結束、輸入、輸出;業(yè)務日志的作用是展示鏈路節(jié)點具體業(yè)務邏輯的執(zhí)行情況,記錄了任何對業(yè)務邏輯起到解釋作用的數據,包括與上下游交互的入參出參、復雜邏輯的中間變量、邏輯執(zhí)行拋出的異常。
2.2.4 鏈路存儲
“鏈路存儲”的含義為:將鏈路執(zhí)行中上報的日志落地存儲,并用于后續(xù)的“現場還原”。上報日志可以拆分為鏈路日志、節(jié)點日志和業(yè)務日志三類:
- 鏈路日志:鏈路單次執(zhí)行中,從開始節(jié)點和結束節(jié)點的日志中提取的鏈路基本信息,包含鏈路類型、鏈路元信息、鏈路開始/結束時間等。
- 節(jié)點日志:鏈路單次執(zhí)行中,已執(zhí)行節(jié)點的基本信息,包含節(jié)點名稱、節(jié)點狀態(tài)、節(jié)點開始/結束時間等。
- 業(yè)務日志:鏈路單次執(zhí)行中,已執(zhí)行節(jié)點中的業(yè)務日志信息,包含日志級別、日志時間、日志數據等。
下圖就是鏈路存儲的存儲模型,包含了鏈路日志,節(jié)點日志,業(yè)務日志、鏈路元數據(配置數據),并且是如下圖9所示的樹狀結構,其中業(yè)務標識作為根節(jié)點,用于后續(xù)的鏈路查詢。
圖9 鏈路的樹狀存儲結構
3. 大眾點評內容平臺實踐
3.1 業(yè)務特點與挑戰(zhàn)
互聯網時代,內容為王。內容型平臺的核心打法就是搭建內容流水線,保障內容可持續(xù)、健康且有價值地流轉到內容消費者,并最終形成內容“生產→治理→消費→生產”的良性循環(huán)。
大眾點評和美團App擁有豐富多樣的內容,站內外業(yè)務方、合作方有著眾多的消費場景。對于內容流水線中的三方,分別有如下需求:
- 內容的生產方:希望生產的內容能在更多的渠道分發(fā),收獲更多的流量,被消費者所喜愛。
- 內容的治理方:希望作為“防火墻”過濾出合法合規(guī)的內容,同時整合機器和人工能力,豐富內容屬性。
- 內容的消費方:希望獲得滿足其個性化需求的內容,能夠吸引其種草,或輔助其做出消費決策。
生產方的內容模型各異、所需處理手段各不相同,消費方對于內容也有著個性化的要求。如果由各個生產方和消費方單獨對接,內容模型異構、處理流程和輸出門檻各異的問題將帶來對接的高成本和低效率。在此背景下,點評內容平臺應運而生,作為內容流水線的“治理方”,承上啟下實現了內容的統一接入、統一處理和統一輸出:
圖10 點評內容平臺業(yè)務形態(tài)
- 統一接入:統一內容數據模型,對接不同的內容生產方,將異構的內容轉化為內容平臺通用的數據模型。
- 統一處理:統一處理能力建設,積累并完善通用的機器處理和人工運營能力,保證內容合法合規(guī),屬性豐富。
- 統一輸出:統一輸出門檻建設,對接不同的內容消費方,為下游提供規(guī)范且滿足其個性化需求的內容數據。
如下圖11所示,是點評內容平臺的核心業(yè)務流程,每一條內容都會經過這個流程,最終決定在各個渠道下是否分發(fā)。
圖11 點評內容平臺業(yè)務流程
內容是否及時、準確經過內容平臺的處理,是內容生產方和消費方的核心關注,也是日常值班的主要客訴類型。而內容平臺的業(yè)務追蹤建設,主要面臨以下的困難與復雜性:
- 業(yè)務場景多:業(yè)務流程涉及多個不同的業(yè)務場景,且邏輯各異,例如實時接入、人工運營、分發(fā)重算等圖中列出的部分場景。
- 邏輯節(jié)點多:業(yè)務場景涉及眾多的邏輯節(jié)點,且不同內容類型節(jié)點各異,例如同樣是實時接入場景,筆記內容和直播內容在執(zhí)行的邏輯節(jié)點上存在較大差異。
- 觸發(fā)執(zhí)行多:業(yè)務場景會被多次觸發(fā)執(zhí)行,且由于來源不同,邏輯也會存在差異,例如筆記內容被作者編輯、被系統審核等等后,都會觸發(fā)實時接入場景的重新執(zhí)行。
點評內容平臺日均處理百萬條內容,涉及百萬次業(yè)務場景的執(zhí)行、高達億級的邏輯節(jié)點的執(zhí)行,而業(yè)務日志分散在不同的應用中,并且不同內容,不同場景,不同節(jié)點以及多次執(zhí)行的日志混雜在一起,無論是日志的搜集還是現場的還原都相當繁瑣耗時,傳統的業(yè)務追蹤方案越來越不適用于內容平臺。
點評內容平臺亟需新的解決方案,實現高效的業(yè)務追蹤,因此我們進行了可視化全鏈路日志追蹤的建設,下面本文將介紹一下相關的實踐和成果。
3.2 實踐與成果
3.2.1 實踐
點評內容平臺是一個復雜的業(yè)務系統,對外支撐著眾多的業(yè)務場景,通過對于業(yè)務場景的梳理和抽象,可以定義出實時接入、人工運營、任務導入、分發(fā)重算等多個業(yè)務邏輯鏈路。由于點評內容平臺涉及眾多的內部服務和下游依賴服務,每天支撐著大量的內容處理業(yè)務,伴隨著業(yè)務的執(zhí)行將生成大量的日志數據,與此同時鏈路上報還需要對眾多的服務進行改造。因此在通用的全鏈路日志追蹤方案的基礎上,點評內容平臺進行了如下的具體實踐。
(1) 支持大數據量日志的上報和存儲
點評內容平臺實現了圖12所示的日志上報架構,支持眾多服務統一的日志收集、處理和存儲,能夠很好地支撐大數據量下的日志追蹤建設。
圖12 點評內容平臺日志上報架構
日志收集:各應用服務通過機器上部署的log_agent收集異步上報的日志數據,并統一傳輸至Kafka通道中,此外針對少量不支持log_agent的服務,搭建了如圖所示的中轉應用。
日志解析:收集的日志通過Kafka接入到Flink中,統一進行解析和處理,根據日志類型對日志進行分類和聚合,解析為鏈路日志、節(jié)點日志和業(yè)務日志。
日志存儲:完成日志解析后,日志會按照樹狀的存儲模型進行落地存儲,結合存儲的需求分析以及各個存儲選項的特點,點評內容平臺最終選擇HBase作為存儲選型。
整體而言,log_agent + Kafka + Flink + HBase的日志上報和存儲架構能夠很好地支持復雜的業(yè)務系統,天然支持分布式場景下眾多應用的日志上報,同時適用于高流量的數據寫入。
(2) 實現眾多后端服務的低成本改造
點評內容平臺實現了“自定義日志工具包”(即下圖13的TraceLogger工具包),屏蔽鏈路追蹤中的上報細節(jié),實現眾多服務改造的成本最小化。TraceLogger工具包的功能包括:
- 模仿slf4j-api:工具包的實現在slf4j框架之上,并模仿slf4j-api對外提供相同的API,因此使用方無學習成本。
- 屏蔽內部細節(jié),內部封裝一系列的鏈路日志上報邏輯,屏蔽染色等細節(jié),降低使用方的開發(fā)成本。
- 上報判斷:
- 判斷鏈路標識:無標識時,進行兜底的日志上報,防止日志丟失。
- 判斷上報方式:有標識時,支持日志和RPC中轉兩種上報方式。
- 日志組裝:實現參數占位、異常堆棧輸出等功能,并將相關數據組裝為Trace對象,便于進行統一的收集和處理。
- 異常上報:通過ErrorAPI主動上報異常,兼容原日志上報中ErrorAppender。
- 日志上報:適配Log4j2日志框架實現最終的日志上報。
圖13 TraceLogger日志工具包
下面是TraceLogger工具包分別進行業(yè)務日志和節(jié)點日志上報的使用案例,整體的改造成本較低。
業(yè)務日志上報:無學習成本,基本無改造成本。
案例:業(yè)務日志上報
// 替換前:原日志上報
LOGGER.error("update struct failed, param:{}", GsonUtils.toJson(structRequest), e);
// 替換后:全鏈路日志上報
TraceLogger.error("update struct failed, param:{}", GsonUtils.toJson(structRequest), e);
節(jié)點日志上報:支持API、AOP兩種上報方式,靈活且成本低。
案例:節(jié)點日志上報
public Response realTimeInputLink(long contentId) {
// 鏈路開始:傳遞串聯標識(業(yè)務標識 + 場景標識 + 執(zhí)行標識)
TraceUtils.passLinkMark("contentId_type_uuid");
// ...
// 本地調用(API上報節(jié)點日志)
TraceUtils.reportNode("contentStore", contentId, StatusEnums.RUNNING)
contentStore(contentId);
TraceUtils.reportNode("contentStore", structResp, StatusEnums.COMPLETED)
// ...
// 遠程調用
Response processResp = picProcess(contentId);
// ...
}
// AOP上報節(jié)點日志
@TraceNode(nodeName="picProcess")
public Response picProcess(long contentId) {
// 圖片處理業(yè)務邏輯
// 業(yè)務日志數據上報
TraceLogger.warn("picProcess failed, contentId:{}", contentId);
}
3.2.2 成果
基于上述實踐,點評內容平臺實現了可視化全鏈路日志追蹤,能夠一鍵追蹤任意一條內容所有業(yè)務場景的執(zhí)行,并通過可視化的鏈路進行執(zhí)行現場的還原,追蹤效果如下圖所示:
【鏈路查詢功能】:根據內容id實時查詢該內容所有的邏輯鏈路執(zhí)行,覆蓋所有的業(yè)務場景。
圖14 鏈路查詢
【鏈路展示功能】:通過鏈路圖可視化展示業(yè)務邏輯的全景,同時展示各個節(jié)點的執(zhí)行情況。
圖15 鏈路展示
【節(jié)點詳情查詢功能】:支持展示任意已執(zhí)行節(jié)點的詳情,包括節(jié)點輸入、輸出,以及節(jié)點執(zhí)行過程中的關鍵業(yè)務日志。
圖16 節(jié)點詳情
目前,可視化全鏈路日志追蹤系統已經成為點評內容平臺的“問題排查工具”,我們可以將問題排查耗時從小時級降低到5分鐘內;同時也是“測試輔助工具”,利用可視化的日志串聯和展示,明顯提升了RD自測、QA測試的效率。最后總結一下可視化全鏈路日志追蹤的優(yōu)點:
- 接入成本低:DSL配置配合簡單的日志上報改造,即可快速接入。
- 追蹤范圍廣:任意一條內容的所有邏輯鏈路,均可被追蹤。
- 使用效率高:管理后臺支持鏈路和日志的可視化查詢展示,簡單快捷。
4. 總結與展望
隨著分布式業(yè)務系統的日益復雜,可觀測性對于業(yè)務系統的穩(wěn)定運行也愈發(fā)重要[6]。作為大眾點評內容流水線中的復雜業(yè)務系統,為了保障內容流轉的穩(wěn)定可靠,點評內容平臺落地了全鏈路的可觀測建設,在日志(Logging)、指標(Metrics)和追蹤(Tracing)的三個具體方向上都進行了一定的探索和建設。
其中之一就是本文的“可視化全鏈路日志追蹤”,結合日志(Logging)與追蹤(Tracing),我們提出了一套新的業(yè)務追蹤通用方案,通過在業(yè)務執(zhí)行階段,結合完整的業(yè)務邏輯動態(tài)完成日志的組織串聯,替代了傳統方案低效且滯后的人工日志串聯,最終可以實現業(yè)務全流程的高效追蹤以及業(yè)務問題的高效定位。此外,在指標(Metrics)方向上,點評內容平臺實踐落地了“可視化全鏈路指標監(jiān)控”,支持實時、多維度地展示業(yè)務系統的關鍵業(yè)務和技術指標,同時支持相應的告警和異常歸因能力,實現了對業(yè)務系統整體運行狀況的有效把控。
未來,點評內容平臺會持續(xù)深耕,實現覆蓋告警、概況、排錯和剖析等功能的可觀測體系[7],持續(xù)沉淀和輸出相關的通用方案,希望可以為業(yè)務系統(特別是復雜的業(yè)務系統),提供一些可觀測性建設的借鑒和啟發(fā)。
5. 參考文獻
[1] Metrics, tracing, and logging
[2] ELK Stack: Elasticsearch, Logstash, Kibana | Elastic
[3] Dapper, a Large-Scale Distributed Systems Tracing Infrastructure
[4] OpenZipkin · A distributed tracing system
[5] 分布式會話跟蹤系統架構設計與實踐
[6] 鳳凰架構-可觀測性
[7] 萬字破解云原生可觀測性
6. 作者及團隊簡介
海友、懷宇、亞平、立森等,均來自點評事業(yè)部/內容平臺技術團隊,負責點評內容平臺的建設工作。
點評內容平臺技術團隊,支持點評內容生態(tài)的建設,致力于打造支持億級內容的高吞吐、低延時、高可用、靈活可擴展的內容流式處理系統,為點評信息流和搜索等核心內容分發(fā)場景提供豐富且優(yōu)質的內容供給,更好地滿足用戶內容消費訴求。