分布式跟蹤系統(tǒng)的四大功能模塊如何協(xié)同工作
了解分布式跟蹤中的主要體系結構決策,以及各部分如何組合在一起。
早在十年前,認真研究過分布式跟蹤基本上只有學者和一小部分大型互聯(lián)網(wǎng)公司中的人。對于任何采用微服務的組織來說,它如今成為一種籌碼。其理由是確立的:微服務通常會發(fā)生讓人意想不到的錯誤,而分布式跟蹤則是描述和診斷那些錯誤的最好方法。
也就是說,一旦你準備將分布式跟蹤集成到你自己的應用程序中,你將很快意識到對于不同的人來說“分布式跟蹤”一詞意味著不同的事物。此外,跟蹤生態(tài)系統(tǒng)里擠滿了具有相似內容的重疊項目。本文介紹了分布式跟蹤系統(tǒng)中四個(可能)獨立的功能模塊,并描述了它們間將如何協(xié)同工作。
分布式跟蹤:一種思維模型
大多數(shù)用于跟蹤的思維模型來源于 Google 的 Dapper 論文。OpenTracing 使用相似的術語,因此,我們從該項目借用了以下術語:
Tracing
- 跟蹤:事物在分布式系統(tǒng)運行的過程描述。
- 跨度:一種命名的定時操作,表示工作流的一部分。跨度可接受鍵值對標簽以及附加到特定跨度實例的細粒度的、帶有時間戳的結構化日志。
- 跨度上下文:攜帶分布式事務的跟蹤信息,包括當它通過網(wǎng)絡或消息總線將服務傳遞給服務時。跨度上下文包含跟蹤標識符、跨度標識符以及跟蹤系統(tǒng)所需傳播到下游服務的任何其他數(shù)據(jù)。
如果你想要深入研究這種思維模式的細節(jié),請仔細參照 OpenTracing 技術規(guī)范。
四大功能模塊
從應用層分布式跟蹤系統(tǒng)的觀點來看,現(xiàn)代軟件系統(tǒng)架構如下圖所示:
Tracing
現(xiàn)代軟件系統(tǒng)的組件可分為三類:
- 應用程序和業(yè)務邏輯:你的代碼。
- 廣泛共享庫:他人的代碼
- 廣泛共享服務:他人的基礎架構
這三類組件有著不同的需求,驅動著監(jiān)控應用程序的分布式跟蹤系統(tǒng)的設計。最終的設計得到了四個重要的部分:
- 跟蹤檢測 API:修飾應用程序代碼
- 線路協(xié)議:在 RPC 請求中與應用程序數(shù)據(jù)一同發(fā)送的規(guī)定
- 數(shù)據(jù)協(xié)議:將異步信息(帶外)發(fā)送到你的分析系統(tǒng)的規(guī)定
- 分析系統(tǒng):用于處理跟蹤數(shù)據(jù)的數(shù)據(jù)庫和交互式用戶界面
為了更深入的解釋這個概念,我們將深入研究驅動該設計的細節(jié)。如果你只需要我的一些建議,請?zhí)D至下方的四大解決方案。
需求,細節(jié)和解釋
應用程序代碼、共享庫以及共享式服務在操作上有顯著的差別,這種差別嚴重影響了對其進行檢測的請求操作。
檢測應用程序代碼和業(yè)務邏輯
在任何特定的微服務中,由微服務開發(fā)者編寫的大部分代碼是應用程序或者商業(yè)邏輯。這部分代碼規(guī)定了特定區(qū)域的操作。通常,它包含任何特殊、獨一無二的邏輯判斷,這些邏輯判斷首先證明了創(chuàng)建新型微服務的合理性。基本上按照定義,該代碼通常不會在多個服務中共享或者以其他方式出現(xiàn)。
也即是說你仍需了解它,這也意味著需要以某種方式對它進行檢測。一些監(jiān)控和跟蹤分析系統(tǒng)使用黑盒代理自動檢測代碼,另一些系統(tǒng)更想使用顯式的白盒檢測工具。對于后者,抽象跟蹤 API 提供了許多對于微服務的應用程序代碼來說更為實用的優(yōu)勢:
- 抽象 API 允許你在不重新編寫檢測代碼的條件下?lián)Q新的監(jiān)視工具。你可能想要變更云服務提供商、供應商和監(jiān)測技術,而一大堆不可移植的檢測代碼將會為該過程增加有意義的開銷和麻煩。
- 事實證明,除了生產(chǎn)監(jiān)控之外,該工具還有其他有趣的用途。現(xiàn)有的項目使用相同的跟蹤工具來驅動測試工具、分布式調試器、“混沌工程”故障注入器和其他元應用程序。
- 但更重要的是,若將應用程序組件提取到共享庫中要怎么辦呢?由上述內容可得到結論:
檢測共享庫
在大多數(shù)應用程序中出現(xiàn)的實用程序代碼(處理網(wǎng)絡請求、數(shù)據(jù)庫調用、磁盤寫操作、線程、并發(fā)管理等)通常情況下是通用的,而非特別應用于某個特定應用程序。這些代碼會被打包成庫和框架,而后就可以被裝載到許多的微服務上并且被部署到多種不同的環(huán)境中。
其真正的不同是:對于共享代碼,其他人則成為了使用者。大多數(shù)用戶有不同的依賴關系和操作風格。如果嘗試去使用該共享代碼,你將會注意到幾個常見的問題:
- 你需要一個 API 來編寫檢測。然而,你的庫并不知道你正在使用哪個分析系統(tǒng)。會有多種選擇,并且運行在相同應用下的所有庫無法做出不兼容的選擇。
- 由于這些包封裝了所有網(wǎng)絡處理代碼,因此從請求報頭注入和提取跨度上下文的任務往往指向 RPC 庫。然而,共享庫必須了解到每個應用程序正在使用哪種跟蹤協(xié)議。
- 最后,你不想強制用戶使用相互沖突的依賴項。大多數(shù)用戶有不同的依賴關系和操作風格。即使他們使用 gRPC,綁定的 gRPC 版本是否相同?因此任何你的庫附帶用于跟蹤的監(jiān)控 API 必定是免于依賴的。
因此,一個(a)沒有依賴關系、(b)與線路協(xié)議無關、(c)使用流行的供應商和分析系統(tǒng)的抽象 API 應該是對檢測共享庫代碼的要求。
檢測共享式服務
最后,有時整個服務(或微服務集合體)的通用性足以使許多獨立的應用程序使用它們。這種共享式服務通常由第三方托管和管理,例如緩存服務器、消息隊列以及數(shù)據(jù)庫。
從應用程序開發(fā)者的角度來看,理解共享式服務本質上是黑盒子是極其重要的。它不可能將你的應用程序監(jiān)控注入到共享式服務。恰恰相反,托管服務通常會運行它自己的監(jiān)控方案。
四個方面的解決方案
因此,抽象的跟蹤應用程序接口將會幫助庫發(fā)出數(shù)據(jù)并且注入/抽取跨度上下文。標準的線路協(xié)議將會幫助黑盒服務相互連接,而標準的數(shù)據(jù)格式將會幫助分離的分析系統(tǒng)合并其中的數(shù)據(jù)。讓我們來看一下部分有希望解決這些問題的方案。
跟蹤 API:OpenTracing 項目
如你所見,我們需要一個跟蹤 API 來檢測應用程序代碼。為了將這種工具擴展到大多數(shù)進行跨度上下文注入和提取的共享庫中,則必須以某種關鍵方式對 API 進行抽象。
OpenTracing 項目主要針對解決庫開發(fā)者的問題,OpenTracing 是一個與供應商無關的跟蹤 API,它沒有依賴關系,并且迅速得到了許多監(jiān)控系統(tǒng)的支持。這意味著,如果庫附帶了內置的本地 OpenTracing 工具,當監(jiān)控系統(tǒng)在應用程序啟動連接時,跟蹤將會自動啟動。
就個人而言,作為一個已經(jīng)編寫、發(fā)布和操作開源軟件十多年的人,在 OpenTracing 項目上工作并最終解決這個觀察性的難題令我十分滿意。
除了 API 之外,OpenTracing 項目還維護了一個不斷增長的工具列表,其中一些可以在這里找到。如果你想?yún)⑴c進來,無論是通過提供一個檢測插件,對你自己的 OSS 庫進行本地測試,或者僅僅只想問個問題,都可以通過 Gitter 向我們打招呼。
線路協(xié)議: HTTP 報頭 trace-context
為了監(jiān)控系統(tǒng)能進行互操作,以及減輕從一個監(jiān)控系統(tǒng)切換為另外一個時帶來的遷移問題,需要標準的線路協(xié)議來傳播跨度上下文。
w3c 分布式跟蹤上下文社區(qū)小組在努力制定此標準。目前的重點是制定一系列標準的 HTTP 報頭。該規(guī)范的最新草案可以在此處找到。如果你對此小組有任何的疑問,郵件列表和Gitter 聊天室是很好的解惑地點。
(LCTT 譯注:本文原文發(fā)表于 2018 年 5 月,可能現(xiàn)在社區(qū)已有不同進展)
數(shù)據(jù)協(xié)議 (還未出現(xiàn)!!)
對于黑盒服務,在無法安裝跟蹤程序或無法與程序進行交互的情況下,需要使用數(shù)據(jù)協(xié)議從系統(tǒng)中導出數(shù)據(jù)。
目前這種數(shù)據(jù)格式和協(xié)議的開發(fā)工作尚處在初級階段,并且大多在 w3c 分布式跟蹤上下文工作組的上下文中進行工作。需要特別關注的是在標準數(shù)據(jù)模式中定義更高級別的概念,例如 RPC 調用、數(shù)據(jù)庫語句等。這將允許跟蹤系統(tǒng)對可用數(shù)據(jù)類型做出假設。OpenTracing 項目也通過定義一套標準標簽集來解決這一事務。該計劃是為了使這兩項努力結果相互配合。
注意當前有一個中間地帶。對于由應用程序開發(fā)者操作但不想編譯或以其他方式執(zhí)行代碼修改的“網(wǎng)絡設備”,動態(tài)鏈接可以幫助避免這種情況。主要的例子就是服務網(wǎng)格和代理,就像 Envoy 或者 NGINX。針對這種情況,可將兼容 OpenTracing 的跟蹤器編譯為共享對象,然后在運行時動態(tài)鏈接到可執(zhí)行文件中。目前 C++ OpenTracing API 提供了該選項。而 JAVA 的 OpenTracing 跟蹤器解析也在開發(fā)中。
這些解決方案適用于支持動態(tài)鏈接,并由應用程序開發(fā)者部署的的服務。但從長遠來看,標準的數(shù)據(jù)協(xié)議可以更廣泛地解決該問題。
分析系統(tǒng):從跟蹤數(shù)據(jù)中提取有見解的服務
最后不得不提的是,現(xiàn)在有足夠多的跟蹤監(jiān)視解決方案。可以在此處找到已知與 OpenTracing 兼容的監(jiān)控系統(tǒng)列表,但除此之外仍有更多的選擇。我更鼓勵你研究你的解決方案,同時希望你在比較解決方案時發(fā)現(xiàn)本文提供的框架能派上用場。除了根據(jù)監(jiān)控系統(tǒng)的操作特性對其進行評級外(更不用提你是否喜歡 UI 和其功能),確保你考慮到了上述三個重要方面、它們對你的相對重要性以及你感興趣的跟蹤系統(tǒng)如何為它們提供解決方案。
結論
最后,每個部分的重要性在很大程度上取決于你是誰以及正在建立什么樣的系統(tǒng)。舉個例子,開源庫的作者對 OpenTracing API 非常感興趣,而服務開發(fā)者對 trace-context 規(guī)范更感興趣。當有人說一部分比另一部分重要時,他們的意思通常是“一部分對我來說比另一部分重要”。
然而,事實是:分布式跟蹤已經(jīng)成為監(jiān)控現(xiàn)代系統(tǒng)所必不可少的事物。在為這些系統(tǒng)進行構建模塊時,“盡可能解耦”的老方法仍然適用。在構建像分布式監(jiān)控系統(tǒng)一樣的跨系統(tǒng)的系統(tǒng)時,干凈地解耦組件是維持靈活性和前向兼容性地最佳方式。
感謝你的閱讀!現(xiàn)在當你準備好在你自己的應用程序中實現(xiàn)跟蹤服務時,你已有一份指南來了解他們正在談論哪部分部分以及它們之間如何相互協(xié)作。