分布式鏈路追蹤(全鏈路追蹤)是分布式系統或者微服務架構中服務監控、性能優化的有效手段。分布式鏈路追蹤有 Jaeger, Zipkin, SkyWalking 等方案,我們詳細講解它們的架構原理;
- 分布式鏈路追蹤方案選型
- 分布式鏈路追蹤實踐
- 分布式鏈路追蹤 SDK
?向 DevOps 的診斷與分析系統
- Logging - 集中式?志系統: ?于記錄離散的事件。例如,應?程序的調試信息或錯誤信息。它是我們診斷問題的依據。
- Tracing - 分布式追蹤系統: ?于記錄請求范圍內的信息。例如,?次遠程?法調?的執?過程和耗時。它是我們排查系統性能問題的利器。
- Metrics - 集中式度量系統: ?于記錄可聚合據。的數例如,隊列的當前深度可被定義為?個度量值,在元素?隊或出隊時被更新;HTTP 請求個數可被定義為?個計數器,新請求到來時進?累加。
所以 Logging,Metrics 和 Tracing 有各?專注的部分。
全鏈路 - 分布式追蹤
方案對比:
Drapper:google的Drapper--未開源,最早的APM
CAT:?眾點評跨服務的跟蹤功能與點評內部的RPC框架集成,這部分未開源且項?在2014.1已經停?維護。服務粒度的監控,通過代碼埋點的?式來實現監控,?如: 攔截器,注解,過濾器等,對代碼的侵?性較?,集成成本較?。
Hydra:京東Hydra與dubbo框架集成,對于服務級別的跟蹤統計,現有業務可以?縫接?。對于細粒度的興趣點,需要業務?員?動添加.開源項?已于2013年6?停?維護
PinPoint-naver:字節碼探針技術,代碼?侵?,體系完善不易修改,?持java,技術棧?持dubbo.其他語?社區?援中
Zipkin:java?便集成于springcloud,社區?持的插件也包括dubbo,rabbit,mysql,httpclient等(https://github.com/openzipkin/brave/tree/master/instrumentation),同時?持php,go,js等語?客戶端,界?功能較為簡單,本身?告警功能,可能需要?次開發。代碼?侵度?。
Jaeger:Uber-Jaeger?持java/c++/go/node/php,在界?上較為完善(對?zipkin),但是也?告警功能。代碼?侵度?。dubbo?前?插件?持,可?次開發。
Skywalking:華為開源,類似于PinPoint,?前還在apache孵化中,?上吞吐量對?中強于pinpoint (實際未驗證), 本身?持dubbo
Jaeger
架構設計
Jaeger是Uber開發的?套分布式追蹤系統,受啟發于 dapper 和OpenZipkin,兼容 OpenTracing 標準,CNCF的開源項?。
Jaeger 架構設計:
Jaeger Client - 為不同語?實現了符合 OpenTracing 標準的 SDK。應?程序通過 API 寫?數據,client library 把 trace 信息按照應?程序指定的采樣策略傳遞給 jaeger-agent。
Agent - 是?個監聽在 UDP 端?上接收 span 數據的?絡守護進程,它會將數據批量發送給 collector。它被設計成?個基礎組件,推薦部署到所有的宿主機上。Agent 將 client library 和 collector 解耦,為 client library 屏蔽了路由和發現 collector 的細節。
Collector - 接收 jaeger-agent 發送來的數據,然后將數據寫?后端存儲。Collector 被設計成?狀態的組件,因此您可以同時運?任意數量的 jaeger-collector。
Data Store - 后端存儲被設計成?個可插拔的組件,?持將數據寫? cassandra、elastic search。
Query - 接收查詢請求,然后從后端存儲系統中檢索 trace 并通過 UI 進?展示。Query 是?狀態的,您可以啟動多個實例,把它們部署在 nginx 這樣的負載均衡器后?。
Agent 初始化類圖
TUDPTransport:基于Thrift框架的UDP傳輸類。
TBufferedServer:基于TUDPTransport的UDP服務器類。
Processor:消息處理類,提供Serve和Stop兩個接?。
ThriftProcessor:消息傳遞類,?于異步的將從UDPServer
這邊接收到的span消息,送?AgentProcessor處理。
AgentProcessor:根據協議區分jaeger和zipkin消息,接收
并處理method為emitBatch的消息,發送?Reporter。
HTTPServerConfiguration:?于配置HTTPServer。
HTTPServer?于接收Collector的HTTP配置消息,配置采樣
率等信息
Agent初始化序列圖
CreateReporter:app/builder.go 中提供createMainReporter接?,在接?中調?Builder.CreateReporter接?。CreateReporter接?在 app/report/tchannel/builder.go中實現。CreateReporter接?中創建了?個tchannel類型的Reporter。
NewAgentProcessor:根據zipkin和jaeger兩種協議類型,agent會創建各?的AgentProcessor。Jaeger類型的AgentProcessor實現在 thrift-gen/agent/agent.go。得到傳回的對象后作為handler傳? ThriftProcessor。
getUDPServer:創建基于 thrift 的 UDP 服務器,并作為?參傳? ThriftProcessor。
GetHTTPServer:創建基于HTTP的服務器,?于處理 Collector下發的配置,設置采樣率等信息。
Agent數據流序列圖
Serve:Agent為不同協議的ThriftProcessor創建多個協程,并調?其Serve接?。
processBuffer:在ThriftProcessor的Serve接?中根據配置創建多個協程?于并發處理span消息。
DataRecd:TBufferedServer在Buffer池的機制,避免了空間反復的 new 和 delete。此處將?完的數據包返回TBufferedServer,以便下次接收數據時再次使?。
Process:ThriftProcessor將接收到的數據轉換成對應的協議格式后,傳遞到AgentProcessor中。
Process:AgentProcessor 解析消息 Method 頭,如果為 EmitBatch 則調?對應回調進?處理。當前只?持EmitBatch消息。
綜上所述,可以看出來Agent模塊主要通過tchannel接收本機的UDP消息(實為span消息),再傳遞?thrift框架的Reporter,發送?Collector。在Agent消息處理過程中,都為?進制協議消息,?明?。Agent不對消息內容做任何修改。
SkyWalking
SkyWalking 架構設計
SkyWalking 的核?是數據分析和度量結果的存儲平臺,通過 HTTP 或 gRPC ?式向SkyWalking Collecter 提交分析和度量數據,SkyWalking Collecter 對數據進?分析和聚合,存儲到 Elasticsearch、H2、MySQL、TiDB 等其?即可,最后我們可以通過 SkyWalking UI 的可視化界?對最終的結果進?查看。SkyWalking ?持從多個來源和多種格式收集數據:多種語?的 Skywalking Agent 、Zipkin v1/v2 、Istio 勘測、Envoy 度量等數據格式。
- SkyWalking 是針對分布式系統的 APM 系統,也被稱為分布式追蹤系統全?動探針監控,不需要修改應?程序代碼。(查看?持的中間件和組件庫列表:https://github.com/apache/incubator/skywalking )
- ?持?動探針監控, 提供了?持 OpenTracing 標準的SDK。覆蓋范圍擴?到 OpenTracing-Java ?持的組件。 (查看OpenTracing組件?持表:https://github.com/opentracing-contrib/meta )
- ?動監控和?動監控可以同時使?,使??動監控彌補?動監控不?持的組件,甚?私有化組件。純 Java 后端分析程序,提供 RESTful 服務,可為其他語?探針提供分析能?。?性能純流式分析。
SkyWalking 邏輯上分為四部分: 探針, 平臺后端, 存儲和?戶界?。
探針:基于不同的來源可能是不?樣的, 但作?都是收集數據, 將數據格式化為 SkyWalking 適?的格式
平臺后端:是?個?持集群模式運?的后臺, ?于數據聚合, 數據分析以及驅動數據流從探針到?戶界?的流程. 平臺后端還提供了各種可插拔的能?, 如不同來源數據(如來? Zipkin)格式化, 不同存儲系統以及集群管理. 你甚?還可以使?觀測分析語?來進??定義聚合分析
存儲:是開放式的. 你可以選擇?個既有的存儲系統, 如 ElasticSearch, H2 或 MySQL 集群
(Sharding-Sphere 管理), 也可以選擇??實現?個存儲系統. 當然, 我們?常歡迎你貢獻新的存儲系統實現?戶界?:對于 SkyWalking 的最終?戶來說?常炫酷且強?. 同樣它也是可定制以匹配你已存在的后端的
探針限制
進程內傳播在?多數情況下成為可能。許多?級編程語?(如 Java, .NET)都是?于構建業務系統. ?部分業務邏輯代碼對于每?個請求來說都運?在同?個線程內, 這使得傳播是基于線程 ID 的, 以確保上下?是安全的.僅僅對某些框架和庫奏效。因為是代理來在運?時修改代碼的, 這也意味著代理插件開發者事先就要知道 所要修改的代碼是怎么樣的. 因此, 在這種探針下通常會有?個已?持的列表清單.?持服務列表: https://github.com/apache/skywalking/blob/master/docs/en/setup/service-agent/java-agent/Supported-list.md
跨線程可能并?總是奏效 如上所述, 每個請求的代碼?都運?在?個線程之內, 對于業務代碼來說尤其如此. 但是在其他?些場景下, 它們也會在不同線程下?作, ?如指派任務到其他線程, 任務池, 以及批處理. 對于?些語?, 可能還提供了協程或類似的概念如 Goroutine, 使得開發者可以低開銷地來執?異步操作, 在這些場景下, ?動打點可能會遇到?些問題。
動態探針技術
字節碼增加技術(有的叫動態探針技術)來實現?侵?式的調?鏈采集。其核?實現原來還是基于JVM的javaagent機制來實現:
"-javaagent:$AGENT_PATH/-bootstrap-$VERSION.jar "
來指定skywalking agent加載路徑,在啟動的時候agent將在加載應?class?件之前做攔截并修改字節碼,在class?法調?的前后加上鏈路采集邏輯,從?實現鏈路采集功能。
javaAgent的底層機制主要依賴JVMTI ,JVMTI全稱JVM Tool Interface,是JVM暴露出來的?些供?戶擴展的接?集合。JVMTI是基于事件驅動的,JVM每執?到?定的邏輯就會調??些事件的回調接?(如果有的話),這些接?可以供開發者擴展??的邏輯。但JVMTI都是?些接?合集,需要有接?的實現,這就?到了java的instrument,可以理解instrument是JVMTI的?種實現,為JVM提供外掛?持。
javaagent具體實現
使?:java -javaagent:myagent.jar=mode=test Test
javaagent 的主要功能如下:
? 可以在加載 class ?件之前做攔截,對字節碼做修改
? 可以在運?期對已加載類的字節碼做變更,但是這種情況下會有很多的限制,后?會詳細說
? 還有其他?些?眾的功能
?獲取所有已經加載過的類
?獲取所有已經初始化過的類(執?過 clinit ?法,是上?的?個?集)
?獲取某個對象的??
?將某個 jar 加?到 bootstrap classpath ?作為?優先級被 bootstrapClassloader 加載
?將某個 jar 加?到 classpath ?供 AppClassloard 去加載
?設置某些 native ?法的前綴,主要在查找 native ?法的時候做規則匹配
JVMTI 全稱 JVM Tool Interface,是 JVM 暴露出來的?些供?戶擴展的接?集合。JVMTI 是基于事件驅動的,JVM 每執?到?定的邏輯就會調
??些事件的回調接?(如果有的話),這些接?可以供開發者擴展??的邏輯。?如最常?的,我們想在某個類的字節碼?件讀取之后、類
定義之前修改相關的字節碼,從?使創建的 class 對象是我們修改之后的字節碼內容,那就可以實現?個回調函數賦給 jvmtiEnv(JVMTI 的運
?時,通常?個 JVMTIAgent 對應?個 jvmtiEnv,但是也可以對應多個)的回調?法集合?的 ClassFileLoadHook,這樣在接下來的類?件加
載過程中都會調?到這個函數中。
instrument agent
instrument agent 實現了Agent_OnLoad和Agent_OnAttach兩?法,也就是說在使?時,agent既可以在啟動時加載,也可以在運?時動態加
載。其中啟動時加載還可以通過類似-javaagent:myagent.jar的?式來間接加載 instrument agent,運?時動態加載依賴的是 JVM 的 attach 機制
( JVM Attach 機制實現),通過發送 load 命令來加載 agent。
在啟動時加載 instrument agent
啟動時加載 instrument agent,具體過程都在InvocationAdapter.c
的Agent_OnLoad
?法?,這?簡單描述下過程:
創建并初始化 JPLISAgent
監聽 VMInit 事件,在 vm 初始化完成之后做下?的事情:
創建 InstrumentationImpl 對象
監聽 ClassFileLoadHook 事件
調? InstrumentationImpl 的loadClassAndCallPremain
?法,在這個?法?會調? javaage
在運?時加載 instrument agent
上?會通過 JVM 的 attach 機制來請求?標 JVM 加載對應的 agent,過程?致如下:
創建并初始化 JPLISAgent
解析 javaagent ? MANIFEST.MF ?的參數
創建 InstrumentationImpl 對象
監聽 ClassFileLoadHook 事件
調? InstrumentationImpl 的loadClassAndCallAgentmain?法,在這個?法?會調? javaagent ? MANIFEST.MF ?指定的Agent-Class類的
agentmain?法
Zipkin
Zipkin 組件設計
Zipkin是?個分布式追蹤系統。它有助于收集解決微服務架構中延遲
問題所需的時序數據。它管理這些數據的收集和查找。Zipkin的設計
基于 Google Dapper論?。
共有四個組件構成了 Zipkin:
- collector
- storage
- search
- web UI
Reporter是裝配應?中?于向 Zipkin 發送數據的組件。Reporter 通過
Transport 發送追蹤數據到 Zipkin 的 Collector,Collector 持久化數據
到 Storage 中。之后,API 從 Storage 中查詢數據提供給 UI。
Zipkin 架構設計
Transport:
裝配庫發送的跨度必須由裝配的服務傳輸到 Collector。 有三種主要的傳輸類型:
HTTP、Scribe 和 Kafka。更多信息查看跨度接收器。Collector:
?旦追蹤數據抵達 Zipkin Collector 守護進程,Zipkin Collector 為了查詢,會對其進
?校驗、存儲和索引。Storage:
Zipkin 最初是構建在將數據存儲在 Cassandra 中,因為 Cassandra 易跨站,?持
靈活的 schema,并且在 Twitter 內部被?規模使?。然?,我們將這個組件做成了
可插拔式的。在 Cassandra 之外,我們原??持 ElasticSearch 和 MySQL??勺鳛?br> 第三?擴展提供給其它后端。
Zipkin 查詢服務:
?旦數據被存儲索引,我們就需要?種?式提取它。查詢守護進程提供了?個簡單
的 JSON API 查詢和獲取追蹤數據。API 的主要消費者就是 Web UI。
Web UI:
我們創建了?個?戶圖形界?為追蹤數據提供了?個漂亮的視圖。Web UI 提供了基
于服務、時間和標記(annotation)查看追中數據的?法。注意:UI 沒有內置的身
份認證功能。
總結
- 非侵入性,并且對 JAVA, .NET 等語言支持,可以選擇 SkyWalking, 接入成本較小 ;
- 如果采用 OpenTracing 集成接入,可以選擇 Jaeger 或者 Zipkin ,侵入性比較大,接入成本中等;
- Service Mesh Tracing 接入 (如 istio tracing ),侵入性較小,接入成本較小 ;
在生產中使用,需要看團隊研發力量和需求,1-3 種方案均可以實施。
下一章和大家分享 自研 分布式鏈路追蹤 SDK 。
- By 斜桿青年