背景

鏈路跟蹤,我們有很多可選項。常見的有 zipkin,pinpoint,skywalking,jaeger 等。

基本上都是根據谷歌的《Dapper 大規模分佈式系統的跟蹤系統》這篇論文發展出來的。

今天講下 Cat 裏的鏈路跟蹤要如何來實現,沒用過 Cat 的同學可以查看我的這篇文章 《熬夜之作:一文帶你瞭解 Cat 分佈式監控》進行了解。

在 Cat 中可以很方便的看到每個請求的總耗時以及業務操作,數據庫操作的耗時情況。對於服務之間的調用也可以通過埋點的方式進行監控。

如下圖,可以看出請求內發起了一次 RPC 的調用,callRPC 開頭的那條記錄。耗時 11ms, 但是這個 RPC 服務內部耗時花在哪裏了,在這邊不能直接查看,只能去另一個服務中查看,不是很方便。

圖片

詳細的我畫了一張圖說明下現在的問題:

從上圖可以看出,一個請求經過了多個服務,每個服務中對遠程調用或者本地調用都有埋點,這樣就能監控到調用的異常和性能指標。

下面一部分是在 Cat 中我們去查看這些指標的場景,Cat 中的數據展示是以項目維度來展示的,所以每個服務都有自己的監控數據。

如果我想要知道剛剛那次請求,在整個鏈路中哪裏最慢,耗時在哪裏,我得分別去 4 個服務下面才能看到這些信息,不直觀。

實現方式

如下圖所示:

從網關到服務,從服務到服務,都需要將 Trace 信息進行傳遞纔可以將整個鏈路串起來。只有串起來了纔可以在 Cat 中查看到整個鏈路的耗時信息。

本文需要實現的效果就是可以在請求的入口處(網關),查看到這個請求經過的所有服務,每個服務中的耗時情況。

要想將整個請求都串連起來,必須要有一個唯一的請求標識,一般我們稱之爲 traceId。剩餘的工作就是將鏈路相關的信息層層傳遞下去。

首先在每個服務的過濾器中進行請求頭信息的接收,比如從網關到服務 A,那麼服務 A 需要接收這些信息然後傳遞給下一個服務。

HTTP 請求的消息樹構建:

// 構建遠程消息樹
if(request.getHeader(CatConstantsExt.CAT_HTTP_HEADER_ROOT_MESSAGE_ID) != null){
        CatContext catContext = new CatContext();
        catContext.addProperty(Cat.Context.ROOT,request.getHeader(CatConstantsExt.CAT_HTTP_HEADER_ROOT_MESSAGE_ID));
        catContext.addProperty(Cat.Context.PARENT,request.getHeader(CatConstantsExt.CAT_HTTP_HEADER_PARENT_MESSAGE_ID));
        catContext.addProperty(Cat.Context.CHILD,request.getHeader(CatConstantsExt.CAT_HTTP_HEADER_CHILD_MESSAGE_ID));
        Cat.logRemoteCallServer(catContext);
}

將消息樹的信息傳遞給下個服務的話就要看你用的調用方式是什麼,如果用 Feign 或者 RestTemplate 都可以利用攔截器來實現傳遞。

public class FeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        CatContext catContext = new CatContext();
        Cat.logRemoteCallClient(catContext,Cat.getManager().getDomain());
        template.header(CatConstantsExt.CAT_HTTP_HEADER_ROOT_MESSAGE_ID, catContext.getProperty(Cat.Context.ROOT));
        template.header(CatConstantsExt.CAT_HTTP_HEADER_PARENT_MESSAGE_ID, catContext.getProperty(Cat.Context.PARENT));
        template.header(CatConstantsExt.CAT_HTTP_HEADER_CHILD_MESSAGE_ID, catContext.getProperty(Cat.Context.CHILD));
    }
}
如果用的是 D
```ubbo 的話可以用 Dubbo 的 Filter 來實現相同的效果。

最終的效果如下圖,調用了 articles/newest 接口,網關將請求轉發到 article-provider 服務,article-provider 中又調用了 user-provider 的 users/uid 接口獲取用戶信息,最重要的是 user-provider 中有哪些操作的耗時在這裏也能直觀的看到,非常方便。

![](https://s4.51cto.com/images/blog/202008/03/6022de985d2aedb45a4e6ae9dfce385c.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

完整源碼參考:https://github.com/yinjihuan/kitty[1]

關於作者 :尹吉歡,簡單的技術愛好者,《Spring Cloud 微服務-全棧技術與案例解析》, 《Spring Cloud 微服務 入門 實戰與進階》作者, 公衆號 猿天地 發起人。個人微信 jihuan900 ,歡迎勾搭。

後臺回覆 學習資料 領取學習視頻

![](https://s4.51cto.com/images/blog/202008/03/d97280f531de5cd5dd12bd52e7563f76.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
相關文章