1. 程式人生 > >[原始碼分析] OpenTracing之跟蹤Redis

[原始碼分析] OpenTracing之跟蹤Redis

# [原始碼分析] OpenTracing之跟蹤Redis [toc] ## 0x00 摘要 本文將通過研究OpenTracing的Redis埋點外掛來進一步深入理解OpenTracing。 ## 0x01 總體邏輯 ### 1.1 相關概念 Tracer是用來管理Span的統籌者,負責建立span和傳播span。它表示從頭到尾的一個請求的呼叫鏈,是一次完整的跟蹤,從請求到伺服器開始,伺服器返回response結束,跟蹤每次rpc呼叫的耗時。它的識別符號是“traceID”。 Span是一個更小的單位,表示一個RPC呼叫過程。一個“trace”包含有許多跨度(span),每個跨度捕獲呼叫鏈內的一個工作單元(系統或服務節點),並由“spanId”標識。 每個跨度具有一個父跨度,並且一個“trace”的所有跨度形成有向無環圖(DAG)。 ### 1.2 埋點外掛 對一個應用的跟蹤要關注的無非就是 `客戶端——>web 層——>rpc 服務——>dao 後端儲存、cache 快取、訊息佇列 mq 等這些基礎元件`。OpenTracing 外掛的作用實際上也就是對不同元件進行埋點,以便基於這些元件採集應用的鏈路資料。 不同元件有不同的應用場景和擴充套件點,因此針對不同的框架,需要開發對應的OpenTracing API 外掛用來實現自動埋點。 對於Redis來說各種外掛更是層出不窮,所以OpenTracing 對與 Redis 各種外掛也做了不同處理,比如 Jedis,Redisson,Spring Data Redis 2.x。本文主要是以 Redisson 為例說明,最後用spring-cloud-redis進行補充對照**。 ### 1.3 總體邏輯 總體思路是使用代理模式。因為 Redis 並沒有提供像 Servlet 那樣的過濾器或者攔截器,所以 Redis OpenTracing 外掛沒有進行常規埋點,而是通過組合的方式自定義若干代理類,比如 TracingRedissonClient 和 TracingRList .....。 - TracingRedissonClient 代理了 Redis Client。 - TracingRList 代理了Redis List 資料結構。 - 還有其他類代理其他Redis資料結構,比如TracingRMap。 這些代理類將具體完成Tracing 功能。比如代理類 TracingRedissonClient 包含了兩個成員變數: - private final RedissonClient redissonClient; 是真正的 Redis Client。 - private final TracingRedissonHelper tracingRedissonHelper; 是具體針對 Redission 的Tracing 功能類,比如構建Span。 最後各種代理對 Redis 進行攔截: - 在執行具體的連線操作之前建立相關的 Span。 - 在操作結束之後結束 Span,並進行上報。 具體可以見下圖 ```java +--------------------------+ +-------------------------+ +-------------------------+ | TracingRedissonClient | | TracingRMap | | TracingRList | | +----------------------+ | | +---------------------+ | | +---------------------+ | | | RedissonClient | | | | RMap | | | | RList | | .... | | | | | | | | | | | | | | TracingRedissonHelper| | | |TracingRedissonHelper| | | |TracingRedissonHelper| | | +----------------------+ | | +---------------------+ | | +---------------------+ | +--------------------------+ +-------------------------+ +-------------------------+ | | | | | | | | | | | | | v | | +---------------+-----------------+ | +-----------> | TracingRedissonHelper | <--------+ | +-----------------------------+ | | | Tracer +-----+ | +-----------------------------+ | | +---------------------------------+ | | +---------------------------------+ | | TracingConfiguration | | | +----------------------------+ | | | | Tracer <-------+ | +----------------------------| | +---------------------------------+ ``` 下圖是為了手機觀看。 ![](https://img2020.cnblogs.com/blog/1850883/202009/1850883-20200912110338696-948482231.png) ## 0x02 示例程式碼 我們使用程式碼自帶的test來做說明。我們可以看到有兩個代理類 `TracingRedissonClient` 和 `TracingRList`。 - beforeClass 起到了系統啟動的作用。 - 首先定義了一個tracer(這裡是MockTracer,真正使用時候會用到其他Tracer)。 - 然後使用這個Tracer來構建一個代理類 `TracingRedissonClient`。 - 後續各種測試操作都是使用這個client在進行Redis操作。 - 會通過代理類 `TracingRedissonClient` 得到一個 `org.redisson.api.RList` 以備後續操作。這個 RList 實際是OpenTracing 進行修改的另一個代理類 `TracingRList`。 - 會對這個 `TracingRList` 進行操作 :`list.add("key");` - 針對 Redisson 的非同步操作,也進行了操作測試。 具體程式碼如下: ```java public class TracingRedissonTest { private static final MockTracer tracer = new MockTracer(); private static RedisServer redisServer; private static RedissonClient client; @BeforeClass public static void beforeClass() { redisServer = RedisServer.builder().setting("bind 127.0.0.1").build(); redisServer.start(); Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); client = new TracingRedissonClient(Redisson.create(config), new TracingConfiguration.Builder(tracer).build()); } @Test public void test_list() {