誰說Cat不能做鏈路跟蹤的,給我站出來


背景

鏈路跟蹤,我們有很多可選項。常見的有 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));
    }
}

如果用的是 Dubbo 的話可以用 Dubbo 的 Filter 來實現相同的效果。

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM