图片
我们的需求是这样的:
图片
假设现在有三个服务:ServiceA、ServiceB、ServiceC。
ServiceA 对外提供了一个 http 接口 request,在这个接口会调用 ServiceB 的 order 订单接口创建订单,同时 serviceB 调用 serviceC 的 pay 接口。
图片
整个调用关系如上图所示。
默认情况下 span 中的 attribute 会记录当前 span 的一些信息,比如:
图片
这些都是当前一些当前 span 内置的信息,比如当前 gRPC 接口的一些基本数据:服务名、ip、端口等信息。
但这里并没有上游的一些信息,虽然我们可以通过 Jaeger 的树状图得知上游是哪个应用调用过来的,但是一旦某个 span 下有多个子 span 的调用,就没办法很直观知道这个子 span 的上游是由谁发起的调用。
比如如下这个链路:
图片
当一个调用链非常长,同时也非常复杂时,没办法第一时间知道某一个 span 的上游到底是谁发起的,需要手动一层层的去折叠,或者全靠眼睛去找。
图片
为此我们希望的效果是可以通过给每一个子 span 中加入两个 attribute,来标明它的父调用来源。
比如在 serviceB 中的所有 span 中都会加上两个标签:来源是 serviceA,同时是 serviceA 的 request 接口发起的请求。
而在 serviceC 中同样可以知道来源是 serviceB 的 Order 接口发起的调用。
我启动了三个 demo 应用,分别是 create1,create2,create3.
create1 中会提供一个 request 接口,在这里面调用 create2 的 create2 接口,create2 的接口里接着调用 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
只是每个应用都需要使用我这边单独打的 agent 包以及一个 extension(tel-extensions-custom-context-1.0-SNAPSHOT.jar) 才能生效。
最终的效果如下:
图片
在讲具体的实现之前需要先了解几个 Trace 中的概念,在这里主要用到的是一个称为 Baggage 的对象。
在之前的文章中其实提到过它的原理以及使用场景:从 Dapper 到 OpenTelemetry:分布式追踪的演进之旅
图片
Baggage 的中文翻译是:包裹
本文链接://www.dmpip.com//www.dmpip.com/showinfo-26-96995-0.htmlOpenTelemetry 深度定制:跨服务追踪的实战技巧
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com