天天看點

分布式鍊路元件 SOFATracer 埋點機制解析 | SOFAChannel#15 直播整理

,有趣實用的分布式架構頻道。

回顧視訊以及 PPT 檢視位址見文末。歡迎加入直播互動釘釘群 : 21992058,不錯過每場直播。

分布式鍊路元件 SOFATracer 埋點機制解析 | SOFAChannel#15 直播整理

本文根據 SOFAChannel#15 直播分享整理,主題:分布式鍊路元件 SOFATracer 埋點機制解析。

大家好,我是宋國磊,花名衛恒,是 SOFATracer 的開源負責人。今天要和大家分享的是分布式鍊路元件 SOFATracer 埋點機制解析,将通過具體 Demo 示範快速上手 SOFATracer,同時介紹 SOFATracer 功能點,并詳細介紹其核心關鍵「埋點機制」的原理。

SOFATracer 是螞蟻金服開源的基于

OpenTracing 規範

的分布式鍊路跟蹤系統,其核心理念就是通過一個全局的 TraceId 将分布在各個服務節點上的同一次請求串聯起來。通過統一的 TraceId 将調用鍊路中的各種網絡調用情況以日志的方式記錄下來同時也提供遠端彙報到

Zipkin

進行展示的能力,以此達到透視化網絡調用的目的。

SOFATracer:

https://github.com/sofastack/sofa-tracer

SOFATracer 作為 SOFAStack 中的分布式鍊路元件,也伴随着 SOFAStack 走過了兩年的時間,在此首先對兩年來對 SOFATracer 保持關注并且參與社群建設的同學表示感謝,也希望大家能夠繼續關注 SOFAStack 的發展,也歡迎更多的同學加入到 SOFAStack 的社群參與中來。

今天的分享内容主要将會圍繞以下三個部分展開:

  • SOFATracer 功能點詳細介紹;
  • SOFATracer 埋點機制原理詳解;
  • 快速上手 SOFATracer 示範;

關于 SOFATracer 更多的問題也歡迎在 Github 上跟我們交流。

SOFATracer 簡介

分布式鍊路元件 SOFATracer 埋點機制解析 | SOFAChannel#15 直播整理

首先簡單介紹一下 SOFATracer。上圖展示的是 SOFATracer 目前所包括的基本能力和所支援的插件。下面虛線框中綠色背景部分,是 SOFATracer 提供的基本功能,具體可以參考

官方文檔

描述。上面虛線框中是 SOFATracer 目前所支援的元件,大概分了以下幾種類型:用戶端、Web、資料存儲、消息、RPC、Spring Cloud。

之前社群也發起過

剖析 | SOFATracer 架構

的源碼解析系列文章,在此系列中對 SOFATracer 所提供的能力及實作原理都做了比較全面的分析,有興趣的同學可以看下。

今天主要聊一下埋點機制。不同元件的埋點機制也是有很大的差異,SOFATracer 是如何實作對上述元件進行埋點的,下面就詳細分析下不同元件的埋點機制。

埋點機制

目前 SOFATracer 已經支援了對以下開源元件的埋點支援:Spring MVC、RestTemplate、HttpClient、OkHttp3、JDBC、Dubbo(2.6/2.7)、SOFARPC、Redis、MongoDB、Spring Message、Spring Cloud Stream (基于 Spring Message 的埋點)、RocketMQ、Spring Cloud FeignClient、Hystrix。

大多數能力提供在 3.x 版本,2.x 版本從官方 issue 中可以看到後續将不再繼續提供新的功能更新;這也是和 SpringBoot 宣布不再繼續維護 1.x 版本有關系。

标準 Servlet 規範埋點原理

SOFATracer 支援對标準 Servlet 規範的 Web MVC 埋點,包括普通的 Servlet 和 Spring MVC 等,基本原理就是基于 Servelt 規範所提供的 javax.servlet.Filter 過濾器接口擴充實作。

過濾器位于 Client 和 Web 應用程式之間,用于檢查和修改兩者之間流過的請求和響應資訊。在請求到達 Servlet 之前,過濾器截獲請求。在響應送給用戶端之前,過濾器截獲響應。多個過濾器形成一個 FilterChain,FilterChain 中不同過濾器的先後順序由部署檔案 web.xml 中過濾器映射的順序決定。最先截獲用戶端請求的過濾器将最後截獲 Servlet 的響應資訊。

Web 應用程式一般作為請求的接收方,在 SOFATracer 中應用是作為 Server 存在的,其在解析 SpanContext 時所對應的事件為 sr (server receive)。

SOFATracer 在 sofa-tracer-springmvc-plugin 插件中解析及産生 Span 的過程大緻如下:

  • Servlet Filter 攔截到 request 請求;
  • 從請求中解析 SpanContext;
  • 通過 SpanContext 建構目前 MVC 的 Span;
  • 給目前 Span 設定 tag、log;
  • 在 Filter 處理的最後,結束 Span;

當然這裡面還會設計到其他很多細節,比如給 Span 設定哪些 tag 屬性、如果處理異步線程透傳等等。本次分享就不展開細節探讨,有興趣的同學可以自行閱讀代碼或者和我們交流。

Dubbo 埋點原理

Dubbo 埋點在 SOFATracer 中實際上提供了兩個插件,分别用于支援 Dubbo 2.6.x 和 Dubbo 2.7.x;Dubbo 埋點也是基于 Filter ,此 Filter 是 Dubbo 提供的 SPI 擴充-

調用攔截擴充

機制實作。

像 Dubbo 或者 SOFARPC 等 RPC 架構的埋點,通常需要考慮的點比較多。首先, RPC 架構分用戶端和服務端,是以在埋點時 RPC 的用戶端和服務端必須要有所區分;再者就是 RPC 的調用方式包括很多種,如常見的同步調用、異步調用、oneway 等等,調用方式不同,所對應的 Span 的結束時機也不同,重要的是基本所有的 RPC 架構都會使用線程池用來發起和處理請求,那麼如何保證 SOFATracer 在多線程環境下不串也很重要。

另外 Dubbo 2.6.x 和 Dubbo 2.7.x 在異步回調處理上差異比較大,Dubbo 2.7.x 中提供了 onResponse 方法(後面又更新為 Listener,包括 onResponse 和 onError 兩個方法);而 Dubbo 2.6.x 中則并未提供相應的機制,隻能通過對 Future 的寫死處理來完成埋點和上報。

這個問題 Zipkin Brave 對 Dubbo 2.6.x 的埋點時其實也沒有考慮到,在做 SOFATracer 支援 Dubbo 2.6.x 時發現了這個 bug,并做了修複。

SOFATracer 中提供的 DubboSofaTracerFilter 類:

分布式鍊路元件 SOFATracer 埋點機制解析 | SOFAChannel#15 直播整理

SOFATracer 中用于處理 Dubbo 2.6.x 版本中異步回調處理的核心代碼:

Dubbo 異步處理依賴 ResponseFuture 接口,但是 ResponseFuture 在核心鍊路上并非是以資料或者 list 的形式存在,是以在鍊路上隻會存在一個 ResponseFuture,是以如果我自定義一個類來實作 ResponseFuture 接口是沒法達到預期目的的,因為運作期會存在覆寫 ResponseFuture 的問題。是以在設計上,SOFATracer 會通過 ResponseFuture 建構一個新的 FutureAdapter出來用于傳遞。
分布式鍊路元件 SOFATracer 埋點機制解析 | SOFAChannel#15 直播整理

HTTP 用戶端埋點原理

HTTP 用戶端埋點包括 HttpClient、OkHttp、RestTemplate 等,此類埋點一般都是基于攔截器機制來實作的,如 HttpClient 使用的 HttpRequestInterceptor、HttpResponseInterceptor;OkHttp 使用的 okhttp3.Interceptor;RestTemplate 使用的 ClientHttpRequestInterceptor。

以 OkHttp 為例,簡單分析下 HTTP 用戶端埋點的實作原理:

分布式鍊路元件 SOFATracer 埋點機制解析 | SOFAChannel#15 直播整理

DataSource 埋點原理

和标準 Servlet 規範實作一樣,所有基于 javax.sql.DataSource 實作的 DataSource 均可以使用 SOFATracer 進行埋點。因為 DataSource 并沒有提供像 Servlet 那樣的過濾器或者攔截器,是以 SOFATracer 中沒法直接通過正常的方式(Filter/SPI 擴充攔截/攔截器等)進行埋點,而是使用了代理模式的方式來實作的。

分布式鍊路元件 SOFATracer 埋點機制解析 | SOFAChannel#15 直播整理

上圖為 SOFATracer 中 DataSource 代理類實作的類繼承結構體系;可以看出,SOFATracer 中自定義了一個 BaseDataSource 抽象類,該抽象類繼承 javax.sql.DataSource 接口,SmartDataSource 作為 BaseDataSource 的唯一子類,也就是 SOFATracer 中所使用的代理類。是以如果你使用了 sofa-tracer-datasource-plugin 插件的話,可以看到最終運作時的 Datasource 類型是 com.alipay.sofa.tracer.plugins.datasource.SmartDataSource。

分布式鍊路元件 SOFATracer 埋點機制解析 | SOFAChannel#15 直播整理

Interceptor 主要包括以下三種類型:

分布式鍊路元件 SOFATracer 埋點機制解析 | SOFAChannel#15 直播整理

以 StatementTracerInterceptor 為例 StatementTracerInterceptor 将将會攔截到所有 PreparedStatement 接口的方法,代碼如下:

分布式鍊路元件 SOFATracer 埋點機制解析 | SOFAChannel#15 直播整理

總體思路是,DataSource 通過組合的方式自定義一個代理類(實際上也可以了解為擴充卡模式中的對象适配模型方式),對所有目标對象的方式進行代理攔截,在執行具體的 SQL 或者連接配接操作之前建立 DataSource 的 Span,在操作結束之後結束 Span,并進行上報。

消息埋點

消息架構元件包括很多,像常見的 RocketMQ、Kafka 等;除了各個元件自己提供的用戶端之外,像 Spring 就提供了很多消息元件的封裝,包括 Spring Cloud Stream、Spring Integration、Spring Message 等等。SOFATracer 基于 Spring Message 标準實作了對常見消息元件和 Spring Cloud Stream 的埋點支援,同時也提供了基于 RocketMQ 用戶端模式的埋點實作。

Spring Messaging 埋點實作原理

spring-messaging 子產品為內建 Messaging API 和消息協定提供支援。這裡我們先看一個 pipes-and-filters 架構模型:

分布式鍊路元件 SOFATracer 埋點機制解析 | SOFAChannel#15 直播整理

spring-messaging 的 support 子產品中提供了各種不同的 Message Channel 實作和 Channel Interceptor 支援,是以在對 spring-messaging 進行埋點時我們自然就會想到去使用 Channel Interceptor。

分布式鍊路元件 SOFATracer 埋點機制解析 | SOFAChannel#15 直播整理

可以看到 ChannelInterceptor 實作了消息傳遞全生命周期的管控,通過暴露出來的方法,可以輕松的實作各個階段的擴充埋點。

RocketMQ 埋點實作原理

RocketMQ 本身是提供了對 Opentracing 規範支援的,由于其支援的版本較高,與 SOFATracer 所實作的 Opentracing 版本不一緻,是以在一定程度上不相容;是以 SOFATracer(opentracing 0.22.0 版本)自身又單獨提供了 RocketMQ  的插件。

RocketMQ 埋點其實是通過兩個 hook 接口來完成,實際上在 RocketMQ 的官方文檔中貌似并沒有提到這兩個點。

分布式鍊路元件 SOFATracer 埋點機制解析 | SOFAChannel#15 直播整理

首先是 SendMessageHook 接口,SendMessageHook 接口提供了兩個方法,sendMessageBefore 和 sendMessageAfter,SOFATracer 在實作埋點時,sendMessageBefore 中用來解析和建構 Span,sendMessageAfter 中用于拿到結果然後結束 Span。

同樣的,ConsumeMessageHook 中也提供了兩個方法(consumeMessageBefore 和 consumeMessageAfter),可以提供給 SOFATracer 來從消息中解析出透傳的 SOFATracer 資訊然後再将 SOFATracer 資訊透傳到下遊鍊路中去。

Redis 埋點原理

SOFATracer 中的 Redis 埋點是基于 spring-data-redis 實作的,沒有針對具體的 Redis 用戶端來埋點。另外  Redis 埋點部分參考的是開源社群

opentracing-spring-cloud-redis-starter

中的實作邏輯。

Redis 的埋點實作與 DataSource 的埋點實作基本思路是一緻的,都是通過一層代理來是實作的攔截。sofa-tracer-redis-plugin 中對所有的 Redis 操作都通過 RedisActionWrapperHelper 進行了一層包裝,在執行具體的指令前後通過 SOFATracer 自己提供的 API 進行埋點操作。代碼如下:

分布式鍊路元件 SOFATracer 埋點機制解析 | SOFAChannel#15 直播整理

除此之外 MongoDB 的埋點也是基于 Spring Data 實作,埋點的實作思路和 Redis 基本相同,這裡就不在單獨分析。

總結

本次分享主要對螞蟻金服分布式鍊路元件 SOFATracer 以及其埋點機制做了簡要的介紹;從各個元件的埋點機制來看,整體思路就是對元件操作進行包裝,在請求或者指令執行的前後進行 Span 建構和上報。目前一些主流的鍊路跟蹤元件像 Brave 也是基于此思路,差別在于 Brave 并非是直接基于 OpenTracing 規範進行編碼,而是其自己封裝了一整套 API ,然後通過面向 OpenTracing API 進行一層适配;另外一個非常流行的 SkyWalking 則是基于 Java agent 實作,埋點實作的機制上與 SOFATracer 和 Brave 不同。

以上就是本期分享的全部内容,如果大家對 SOFATracer 感興趣,也可以在群内或者 Github 上與我們交流。

本期視訊回顧以及 PPT 檢視位址

https://tech.antfin.com/community/live/1167/data/986