前因
随着业务的扩充,微服务项目越来越多,对于分布式架构设计来讲,如何更好的监控每个服务的上下游成为了重点问题, 因为一旦中间某个调用链发生问题,就会导致整个链路连接失败。为了更好、更快的找到链路所在,我们就需要一个完整的链路跟踪系统,本节主要分享的是基于OpenTelemetry的一个链路跟踪库,可以很方便的无缝插拔式接入各种微服务系统中,当然,推荐使用字节开源的微服务分布式框架:Hertz、Kitex,该套框架已经很好的接入很多插件,并且本身提供高性能的功能特性,如果对于微服务有性能要求的,推荐尝试。
前面讲过我们的IDL,并且目前使用idl的两种方式以及使用的场景,接下来,我们直接通过thrift的idl文件来生成一个RPC微服务。
首先第一步,写出这个底层RPC服务的idl逻辑:
namespace go test
struct Request {
1: required string data
2: i64 type
}
struct Msg {
1: i32 code
2: string msg
}
struct Response {
1: Msg msg
2: string data
}
service TestService {
Response Test1(1: Request req)
Response Test2(1: Request req)
}
上面写了一个简单的基于thrift的idl,接下来,我们生成一个基于该idl的微服务,执行如下命令:
kitex -module "hz-kitex-examples" -thrift frugal_tag,template=slim -service test idl/test.thrift
执行上面的命令后,我们会看到在kitex_gen目录下生成一堆文件,这里就是RPC协议通信时,需要建立的一个桥梁,提供调用者与被调用者的连接:
同时,我们还会看到生成对应的被调用者的逻辑:
这里是启动类中对于网络、编解码、连接的设置:
这样,一个简单的RPC底层微服务就写完了。接下来,我们需要写一个对应的客户端进行彼此之间的通信、调用:
在这个rpc client的逻辑里,我们需要定义与server端一样的编解码、网络连接、通信协议方式。那么到目前为止,对于一个完整的基于Kitex的RPC微服务就开发完成了,下面环节,我们就基于该框架进行插拔式服务的链路跟踪。
插拔式链路跟踪,为什么叫插拔式呢?顾名思义,其接入链路跟踪很简单,无需太多的逻辑,即可接入整个服务的连接的链路。本节介绍的链路跟踪技术,主要是基于Opentelemetry协议的Optl,对于该协议技术,大家感兴趣可以参考github的相关资料。
我们先看看RPC server端如何插拔式接入的,很简单,我们直接在server的启动main里加入:
p := provider.NewOpenTelemetryProvider(
provider.WithServiceName(constants.UserServiceName),
provider.WithExportEndpoint("121.37.173.206:4317"),
provider.WithInsecure(),
)
defer p.Shutdown(context.Background())
同时,在初始化new服务端的时候,只要加上:
server.WithSuite(tracing.NewServerSuite()),
server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: constants.UserServiceName}),
这样,对于RPC server端就可以接入Opentelemetry了。
然后,对于调用server的client端,我们看如何接入,也很简单:
client.WithSuite(tracing.NewClientSuite()),
client.WithClientBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: constants.ApiServiceName}),
看到代码是不是感觉很简单,两行code即可搞定,对得起我这文章标题吧。
同时,对于RPC client,也是一个Http server服务,所以可以接入open telemetry:
p := provider.NewOpenTelemetryProvider(
provider.WithServiceName(constants.ApiServiceName),
provider.WithExportEndpoint("121.37.173.206:4317"), //("localhost:4317"),
provider.WithInsecure(),
)
defer func(ctx context.Context, p provider.OtelProvider) {
_ = p.Shutdown(ctx)
}(context.Background(), p)
tracer, cfg := hertztracing.NewServerTracer()
r := server.New(
tracer,
)
r.Use(hertztracing.ServerMiddleware(cfg))
看着是不是也很简单,代码逻辑都是一样的,没啥复杂的业务逻辑,新手都能入门。
最后,我们来看看这个接入微服务链路跟踪后的整个系统的连接链路是啥样的,我们需要简单的展示下,这里是直接使用Jaeger进行UI展示,在调用数次请求之后,我们可以看到如下结果,先来看下我们调用的关系链:
然后经过几次调用后,我们可以看到这样的关系图:
最后,我们可以看到每次调用的链路以及日志信息:
最后,以上就是今天分享的几行代码,就可以轻松的无缝接入链路跟踪,帮助我们很好的看到调用链路关系,以及问题定位。