最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java 實現(xiàn)分布式服務的調(diào)用鏈跟蹤

 更新時間:2021年06月07日 08:50:33   作者:果果果果果  
分布式服務中完成某一個業(yè)務動作,需要服務之間的相互協(xié)作才能完成,在這一次動作引起的多服務的聯(lián)動我們需要用1個唯一標識關聯(lián)起來,關聯(lián)起來就是調(diào)用鏈的跟蹤。本文介紹了Java 實現(xiàn)分布式服務的調(diào)用鏈跟蹤的步驟

為什么要實現(xiàn)調(diào)用鏈跟蹤?

隨著業(yè)務的發(fā)展,所有的系統(tǒng)最終都會走向服務化體系,微服務的目的一是提高系統(tǒng)的穩(wěn)定性,二是提高持續(xù)交付的效率,為什么能提高這兩項不是今天討論的內(nèi)容。

當然這也不是絕對的,如果業(yè)務還在MVP驗證,團隊規(guī)模小個人覺得完全沒必要微服務化、單體應用是比較好的選擇。作者是有經(jīng)歷過從單體應用到1000+應用的增長經(jīng)歷,也是見證了公司從初創(chuàng)到上市的過程,對于系統(tǒng)階段和業(yè)務階段的匹配還是有比較深的感受的。

服務拆分后帶來的問題是什么呢?服務的依賴關系復雜后,對于問題的排查也增加了復雜度,當然站在更高的角度來看拆分帶來的不只是排錯復雜性的提升,工程效率、組織協(xié)作也都會帶來新的挑戰(zhàn)。

回到主題,如何快速查詢整個請求鏈路上的日志并呈現(xiàn)出來是解決排查問題復雜度的根本方法,這就是今天我們要講的內(nèi)容,如何自己來實現(xiàn)一個全鏈路跟蹤。

如何實現(xiàn)?

第一步,看圖、看場景,用戶瀏覽器的一次請求行為所走的路徑是什么樣的

如上圖、省略了4層和7層的LB,請求直接到gateway->A->B 那如何把個request關聯(lián)起來呢?從時序上來看我們只要在gateway生成一個traceId然后層層透傳,那么每一次的request的我們就能通過traceid關聯(lián)查詢出來了。
如何透傳、如何記錄呢?或者說如何透傳、如何記錄讓各應用的開發(fā)人員無需關注呢?

第二步,實現(xiàn)。不想看代碼可直接拉最后看結果和原理

如何傳遞,這里我們使用定義統(tǒng)一的Request類,所有的api層需要使用這個規(guī)范,代碼如下:

public class Request<T> implements Serializable {
    //header:攜帶需要傳遞的信息
    private RequestHeader header;
    //業(yè)務參數(shù)
    private T bizModel;
    //...省略get set
}
public class RequestHeader implements Serializable {

    //調(diào)用鏈唯一ID
    private String traceId;
    //當前用戶Id
    private String userId;
    //上游調(diào)用方appId
    private String callAppId;
    //...省略get set
}

有了這個Request之后,我們在網(wǎng)關層每次都生成traceId, 然后在各服務之間傳遞就能做到調(diào)用鏈的關聯(lián)了。我們繼續(xù)看個各應用應該如何定義服務和使用

    @ApiMethod
    @PostMapping("/test")
    @ApiOperation(value = "test", notes = "", response = String.class)
    public Response<ExampleRespDTO> test(@RequestBody Request<ExampleReqDTO> req) {
        ExampleRespDTO exampleRespDTO = new ExampleRespDTO();
        exampleRespDTO.setName(req.getBizModel().getName());

        //輸出當前應用的header信息
         System.out.println("上游的traceId:"+RequestContext.getHeader().getTraceId());
        System.out.println("上游的callAppId:"+RequestContext.getHeader().getCallAppId());
        System.out.println("上游的userId:"+RequestContext.getHeader().getUserId());


        /***
         * 模擬調(diào)用其他應用服務
         * 通過RPCRequest 來構建request對象
         */
        Request<OtherAppServiceReqDTO>  otherAppServiceReqDTORequest =RPCRequest.createRequest(new OtherAppServiceReqDTO());

        //輸出下游應用的header信息
        System.out.println("調(diào)用下游的traceId:"+otherAppServiceReqDTORequest.getHeader().getTraceId());
        System.out.println("調(diào)用下游的callAppId:"+otherAppServiceReqDTORequest.getHeader().getCallAppId());
        System.out.println("調(diào)用下游的userId:"+otherAppServiceReqDTORequest.getHeader().getUserId());

        return Response.successResponse(exampleRespDTO);
    }

看完上面代碼的同學,應該看到了有一個模擬調(diào)用其他服務的地方,這里主要解決的是服務和服務之間的調(diào)用header傳遞的問題,這里封裝了一個createRequest的方法,其主要內(nèi)容還是把當前應用的requestHeader 賦值給請求其他服務的request上。這也是一個測試接口,最后面有測試的結果

public class RPCRequest {
    public static <T> Request<T> createRequest(T requestData){
        Request<T> request = new Request();
        RequestHeader requestHeader=new RequestHeader();
        requestHeader.setTraceId(RequestContext.getHeader().getTraceId());
        requestHeader.setUserId(RequestContext.getHeader().getUserId());
        requestHeader.setCallAppId(AppConfig.CURRENT_APP_ID);
        request.setHeader(requestHeader);
        request.setBizModel(requestData);
        return request;
    }
}

當前request中的header存在什么地方呢,我們看一下RequestContext的代碼

public class RequestContext {
  private static ThreadLocal<RequestHeader> threadLocal=new ThreadLocal<>();
   public static void setHeader(RequestHeader header){
       threadLocal.set(header);
   }
   public static RequestHeader getHeader(){
       return threadLocal.get();
   }
   public static void clear(){
       threadLocal.remove();
   }
}

header是什么時候放進去的呢?這里就是AOP該發(fā)揮作用的時候了,直接看代碼

public class ApiHandler {
    public ApiHandler() {
    }

    public Response handleApiMethod(ProceedingJoinPoint pjp, ApiMethod apiMethod) {
        //獲取上游調(diào)用方的request header
        Object[] args = pjp.getArgs();
        Request request = (Request) args[0];
        RequestHeader header = request.getHeader();
        //將header加入到當前request 到ThreadLocal保存
        RequestContext.setHeader(header);
        Response response = null;
        try {
            //構建response header
            ResponseHeader responseHeader = new ResponseHeader();
            responseHeader.setTraceId(RequestContext.getHeader().getTraceId());
            //執(zhí)行service方法
            response = (Response) pjp.proceed(args);
            response.setHeader(responseHeader);

        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }finally {
            //清除ThreadLocal中當前請求的header 對象
            RequestContext.clear();
        }
        return response;

    }
}

不想看代碼的,直接看下圖,原理比較簡單,淺黃色為AOP作用,接口執(zhí)行前和執(zhí)行后,其中reqeuest和header的定義在第1段代碼

這里沒有介紹如何收集數(shù)據(jù)和查詢展示,比較簡單的辦法是使用logback打本地日志,然后通過agent抽到集中式日志進行查詢展示,例如ELK。

測試一下結果:

1、接口文檔

2、執(zhí)行結果

以上就是Java 實現(xiàn)分布式服務的調(diào)用鏈跟蹤的詳細內(nèi)容,更多關于Java 分布式服務的調(diào)用鏈跟蹤的資料請關注腳本之家其它相關文章!

相關文章

  • Spring Boot與ActiveMQ整合的步驟

    Spring Boot與ActiveMQ整合的步驟

    今天小編就為大家分享一篇關于Spring Boot與ActiveMQ整合的步驟,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • java使用監(jiān)聽器實現(xiàn)一個統(tǒng)計網(wǎng)站在線人數(shù)的示例

    java使用監(jiān)聽器實現(xiàn)一個統(tǒng)計網(wǎng)站在線人數(shù)的示例

    本文主要介紹了java使用監(jiān)聽器實現(xiàn)一個統(tǒng)計網(wǎng)站在線人數(shù)的示例,具有一定的參考價值,有需要的朋友可以了解一下。
    2016-10-10
  • 普通java項目集成kafka方式

    普通java項目集成kafka方式

    文章介紹了如何在非Spring Cloud或Spring Boot項目中配置和使用Kafka,提供了一個簡單的Kafka配置讀取類,可以靈活地從不同配置中讀取屬性,并提供默認值
    2024-11-11
  • 2020最新版SSM框架整合教程

    2020最新版SSM框架整合教程

    這篇文章主要介紹了2020最新版SSM框架整合教程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • Java Scala之模式匹配與隱式轉(zhuǎn)換

    Java Scala之模式匹配與隱式轉(zhuǎn)換

    在Java中我們有switch case default這三個組成的基礎語法,在Scala中我們是有match和case組成 default的作用由case代替,本文詳細介紹了Scala的模式匹配與隱式轉(zhuǎn)換,感興趣的可以參考本文
    2023-04-04
  • 基于Spring Security的Oauth2授權實現(xiàn)方法

    基于Spring Security的Oauth2授權實現(xiàn)方法

    這篇文章主要介紹了基于Spring Security的Oauth2授權實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-09-09
  • SpringMVC HttpMessageConverter消息轉(zhuǎn)換器

    SpringMVC HttpMessageConverter消息轉(zhuǎn)換器

    ??HttpMessageConverter???,報文信息轉(zhuǎn)換器,將請求報文轉(zhuǎn)換為Java對象,或?qū)ava對象轉(zhuǎn)換為響應報文。???HttpMessageConverter???提供了兩個注解和兩個類型:??@RequestBody,@ResponseBody???,??RequestEntity,ResponseEntity??
    2023-04-04
  • Struts2學習手冊之文件上傳基礎教程

    Struts2學習手冊之文件上傳基礎教程

    Struts2提供的文件上傳下載機制十分簡便,使得我們寫很少的代碼,下面這篇文章主要給大家介紹了關于Struts2學習手冊之文件上傳的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2018-05-05
  • Java?Stream流使用最多的方式示例詳解

    Java?Stream流使用最多的方式示例詳解

    在 Java 編程中,Stream 流提供了一種高效、便捷的方式來處理集合數(shù)據(jù),本文將詳細介紹 Java 中 Stream 流的用法,包括基礎用法、中級用法、高級用法以及一些特殊方法的使用,感興趣的朋友一起看看吧
    2024-12-12
  • Java實戰(zhàn)之課程信息管理系統(tǒng)的實現(xiàn)

    Java實戰(zhàn)之課程信息管理系統(tǒng)的實現(xiàn)

    這篇文章主要介紹了如何利用Java實現(xiàn)課程信息管理系統(tǒng),文中采用到的技術有:Springboot、SpringMVC、MyBatis、FreeMarker等,感興趣的可以了解一下
    2022-04-04

最新評論

墨竹工卡县| 五华县| 喜德县| 抚宁县| 静宁县| 静宁县| 永丰县| 柳河县| 中方县| 高台县| 姜堰市| 杂多县| 张家口市| 正宁县| 勃利县| 旺苍县| 班戈县| 岳普湖县| 伊春市| 伊宁县| 射洪县| 兰州市| 林芝县| 西乡县| 梁山县| 伊春市| 修文县| 高邮市| 大庆市| 札达县| 建始县| 辽中县| 大竹县| 通道| 永州市| 沽源县| 台山市| 米林县| 朝阳县| 东山县| 丁青县|