圖片
我們的需求是這樣的:
圖片
假設(shè)現(xiàn)在有三個(gè)服務(wù):ServiceA、ServiceB、ServiceC。
ServiceA 對外提供了一個(gè) http 接口 request,在這個(gè)接口會(huì)調(diào)用 ServiceB 的 order 訂單接口創(chuàng)建訂單,同時(shí) serviceB 調(diào)用 serviceC 的 pay 接口。
圖片
整個(gè)調(diào)用關(guān)系如上圖所示。
默認(rèn)情況下 span 中的 attribute 會(huì)記錄當(dāng)前 span 的一些信息,比如:
圖片
這些都是當(dāng)前一些當(dāng)前 span 內(nèi)置的信息,比如當(dāng)前 gRPC 接口的一些基本數(shù)據(jù):服務(wù)名、ip、端口等信息。
但這里并沒有上游的一些信息,雖然我們可以通過 Jaeger 的樹狀圖得知上游是哪個(gè)應(yīng)用調(diào)用過來的,但是一旦某個(gè) span 下有多個(gè)子 span 的調(diào)用,就沒辦法很直觀知道這個(gè)子 span 的上游是由誰發(fā)起的調(diào)用。
比如如下這個(gè)鏈路:
圖片
當(dāng)一個(gè)調(diào)用鏈非常長,同時(shí)也非常復(fù)雜時(shí),沒辦法第一時(shí)間知道某一個(gè) span 的上游到底是誰發(fā)起的,需要手動(dòng)一層層的去折疊,或者全靠眼睛去找。
圖片
為此我們希望的效果是可以通過給每一個(gè)子 span 中加入兩個(gè) attribute,來標(biāo)明它的父調(diào)用來源。
比如在 serviceB 中的所有 span 中都會(huì)加上兩個(gè)標(biāo)簽:來源是 serviceA,同時(shí)是 serviceA 的 request 接口發(fā)起的請求。
而在 serviceC 中同樣可以知道來源是 serviceB 的 Order 接口發(fā)起的調(diào)用。
我啟動(dòng)了三個(gè) demo 應(yīng)用,分別是 create1,create2,create3.
create1 中會(huì)提供一個(gè) request 接口,在這里面調(diào)用 create2 的 create2 接口,create2 的接口里接著調(diào)用 create3 的 create3 接口。
create1:
@RequestMapping("/request") public String request(@RequestParam String name) { HelloRequest request = HelloRequest.newBuilder() .setName(name) .build(); log.info("request: {}", request); String message = myServiceStub.create2(request).getMessage(); Executors.newFixedThreadPool(1).execute(() -> { myServiceStub.create2(request).getMessage(); }); return message; }create2:
@Override public void create2(HelloRequest request, StreamObserver<HelloReply> responseObserver) { HelloReply reply = HelloReply.newBuilder() .setMessage("Create2 ==> " + request.getName()) .build(); log.info("Create2: {}", reply.getMessage()); myMethod(request.getName()); myServiceStub.create3(request); responseObserver.onNext(reply); responseObserver.onCompleted(); }create3:
@Override public void create3(HelloRequest request, StreamObserver<HelloReply> responseObserver) { HelloReply reply = HelloReply.newBuilder() .setMessage("Create3 ==> " + request.getName()) .build(); log.info("Create3: {}", reply.getMessage()); myMethod(request.getName()); responseObserver.onNext(reply); responseObserver.onCompleted(); }java -javaagent:opentelemetry-javaagent-2.4.0-SNAPSHOT.jar /-Dotel.javaagent.extensinotallow=otel-extensions-custom-context-1.0-SNAPSHOT.jar /-Dotel.traces.exporter=otlp /-Dotel.logs.exporter=none /-Dotel.service.name=create2 /-Dotel.exporter.otlp.protocol=grpc /-Dotel.propagators=tracecontext,baggage,demo /-Dotel.exporter.otlp.endpoint=http://127.0.0.1:5317 / -jar target/demo-0.0.1-SNAPSHOT.jar --spring.application.name=create2 --server.port=9191 --grpc.server.port=9292 --grpc.client.myService.address=static://127.0.0.1:9393只是每個(gè)應(yīng)用都需要使用我這邊單獨(dú)打的 agent 包以及一個(gè) extension(tel-extensions-custom-context-1.0-SNAPSHOT.jar) 才能生效。
最終的效果如下:
圖片
在講具體的實(shí)現(xiàn)之前需要先了解幾個(gè) Trace 中的概念,在這里主要用到的是一個(gè)稱為 Baggage 的對象。
在之前的文章中其實(shí)提到過它的原理以及使用場景:從 Dapper 到 OpenTelemetry:分布式追蹤的演進(jìn)之旅
圖片
Baggage 的中文翻譯是:包裹
本文鏈接:http://m.www897cc.com/showinfo-26-96995-0.htmlOpenTelemetry 深度定制:跨服務(wù)追蹤的實(shí)戰(zhàn)技巧
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com