亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術(shù)文章
文章詳情頁

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

瀏覽:65日期:2022-08-11 10:03:53
目錄為什么要實(shí)現(xiàn)調(diào)用鏈跟蹤?如何實(shí)現(xiàn)?第一步,看圖、看場(chǎng)景,用戶瀏覽器的一次請(qǐng)求行為所走的路徑是什么樣的第二步,實(shí)現(xiàn)。不想看代碼可直接拉最后看結(jié)果和原理測(cè)試一下結(jié)果:為什么要實(shí)現(xiàn)調(diào)用鏈跟蹤?

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

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

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

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

如何實(shí)現(xiàn)?第一步,看圖、看場(chǎng)景,用戶瀏覽器的一次請(qǐng)求行為所走的路徑是什么樣的

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

如上圖、省略了4層和7層的LB,請(qǐng)求直接到gateway->A->B 那如何把個(gè)request關(guān)聯(lián)起來呢?從時(shí)序上來看我們只要在gateway生成一個(gè)traceId然后層層透?jìng)鳎敲疵恳淮蔚膔equest的我們就能通過traceid關(guān)聯(lián)查詢出來了。如何透?jìng)鳌⑷绾斡涗浤兀炕蛘哒f如何透?jìng)鳌⑷绾斡涗涀尭鲬?yīng)用的開發(fā)人員無需關(guān)注呢?

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

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

public class Request<T> implements Serializable { //header:攜帶需要傳遞的信息 private RequestHeader header; //業(yè)務(wù)參數(shù) private T bizModel; //...省略get set}public class RequestHeader implements Serializable { //調(diào)用鏈唯一ID private String traceId; //當(dāng)前用戶Id private String userId; //上游調(diào)用方appId private String callAppId; //...省略get set}

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

@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());//輸出當(dāng)前應(yīng)用的header信息 System.out.println('上游的traceId:'+RequestContext.getHeader().getTraceId());System.out.println('上游的callAppId:'+RequestContext.getHeader().getCallAppId());System.out.println('上游的userId:'+RequestContext.getHeader().getUserId());/*** * 模擬調(diào)用其他應(yīng)用服務(wù) * 通過RPCRequest 來構(gòu)建request對(duì)象 */Request<OtherAppServiceReqDTO> otherAppServiceReqDTORequest =RPCRequest.createRequest(new OtherAppServiceReqDTO());//輸出下游應(yīng)用的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); }

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

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; }}

當(dāng)前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是什么時(shí)候放進(jìn)去的呢?這里就是AOP該發(fā)揮作用的時(shí)候了,直接看代碼

public class ApiHandler { public ApiHandler() { } public Response handleApiMethod(ProceedingJoinPoint pjp, ApiMethod apiMethod) {//獲取上游調(diào)用方的request headerObject[] args = pjp.getArgs();Request request = (Request) args[0];RequestHeader header = request.getHeader();//將header加入到當(dāng)前request 到ThreadLocal保存RequestContext.setHeader(header);Response response = null;try { //構(gòu)建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中當(dāng)前請(qǐng)求的header 對(duì)象 RequestContext.clear();}return response; }}

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

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

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

測(cè)試一下結(jié)果:

1、接口文檔

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

2、執(zhí)行結(jié)果

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

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

以上就是Java 實(shí)現(xiàn)分布式服務(wù)的調(diào)用鏈跟蹤的詳細(xì)內(nèi)容,更多關(guān)于Java 分布式服務(wù)的調(diào)用鏈跟蹤的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 亚洲日韩成人 | 久久久久欧美精品观看 | 精品哟哟哟国产在线不卡 | 亚洲国产精品久久综合 | 伊人中文字幕在线 | 丝袜美腿国产精品视频一区 | 91精品国产亚洲爽啪在线观看 | 黄色小视频免费 | 麻豆国产入口在线观看免费 | 黄在线免费看 | 精品国精品国产自在久国产不卡 | 欧美bbwxxxx| 欧美精品亚洲 | 男人懂的网站 | 国产一级黄色录像 | 中文字幕日韩国产 | 九九久久精品国产 | 色婷婷亚洲 | 亚洲香蕉综合在人在线时看 | 亚洲国产精品自产拍在线播放 | 六月丁香激情网 | 欧美性视频在线激情 | fc2成人免费人成在线观看播放 | 92香蕉视频 | 国产精品自在欧美一区 | 精品日韩一区 | 99在线精品国产不卡在线观看 | 一级一片免费视频播放 | 免费特黄级夫费生活片 | 亚洲国产成人va在线观看 | 可以在线观看的黄色网址 | 亚洲精品欧洲一区二区三区 | xxxvideos3d性动漫 | 曰本女人一级毛片看一级毛 | 中文字幕一级毛片视频 | 国产二区自拍 | 久久精品中文字幕有码日本 | 成人久久久久 | 欧美黑人换爱交换乱理伦片 | 6699久久久久久久77777'7 66av99精品福利视频在线 | 国产精品东北一极毛片 |