go-micro集成链路跟踪的方法和中间件原理

前几天有个同学想了解下如何在go-micro中做链路跟踪,这几天正好看到wrApper这块,wrapper这个东西在某些框架中也称为中间件,里边有个opentracing的插件,正好用来做链路追踪 。opentracing是个规范,还需要搭配一个具体的实现,比如zipkin、jeager等,这里选择zipkin 。

go-micro集成链路跟踪的方法和中间件原理

文章插图
 
链路跟踪实战安装zipkin通过Docker快速启动一个zipkin服务端:
docker run -d -p 9411:9411 openzipkin/zipkin程序结构为了方便演示,这里把客户端和服务端放到了一个项目中,程序的目录结构是这样的:
go-micro集成链路跟踪的方法和中间件原理

文章插图
 
  • main.go 服务端程序 。
  • client/main.go 客户端程序 。
  • config/config.go 程序用到的一些配置,比如服务的名称和监听端口、zipkin的访问地址等 。
  • zipkin/ot-zipkin.go opentracing和zipkin相关的函数 。
安装依赖包需要安装go-micro、opentracing、zipkin相关的包:
go get go-micro.dev/v4@latestgo get github.com/go-micro/plugins/v4/wrapper/trace/opentracinggo get -u github.com/openzipkin-contrib/zipkin-go-opentracing编写服务端首先定义一个服务端业务处理程序:
type Hello struct {}func (h *Hello) Say(ctx context.Context, name *string, resp *string) error {*resp = "Hello " + *namereturn nil}这个程序只有一个方法Say,输入name,返回 "Hello " + name 。
然后使用go-micro编写服务端框架程序:
func main() {tracer := zipkin.GetTracer(config.SERVICE_NAME, config.SERVICE_HOST)defer zipkin.Close()tracerHandler := opentracing.NewHandlerWrapper(tracer)service := micro.NewService(micro.Name(config.SERVICE_NAME),micro.Address(config.SERVICE_HOST),micro.WrapHandler(tracerHandler),)service.Init()micro.RegisterHandler(service.Server(), &Hello{})if err := service.Run(); err != nil {log.Println(err)}}这里NewService的时候除了指定服务的名称和访问地址,还通过micro.WrapHandler设置了一个用于链路跟踪的HandlerWrapper 。
这个HandlerWrapper是通过go-micro的opentracing插件提供的,这个插件需要传入一个tracer 。这个tracer可以通过前边安装的 zipkin-go-opentracing 包来创建,我们把创建逻辑封装在了config.go中:
func GetTracer(serviceName string, host string) opentracing.Tracer {// set up a span reporterzipkinReporter = zipkinhttp.NewReporter(config.ZIPKIN_SERVER_URL)// create our local service endpointendpoint, err := zipkin.NewEndpoint(serviceName, host)if err != nil {log.Fatalf("unable to create local endpoint: %+vn", err)}// initialize our tracernativeTracer, err := zipkin.NewTracer(zipkinReporter, zipkin.WithLocalEndpoint(endpoint))if err != nil {log.Fatalf("unable to create tracer: %+vn", err)}// use zipkin-go-opentracing to wrap our tracertracer := zipkinot.Wrap(nativeTracer)opentracing.InitGlobalTracer(tracer)return tracer}service创建完毕之后,还要通过 micro.RegisterHandler 来注册前边编写的业务处理程序 。
最后通过 service.Run 让服务运行起来 。
编写客户端再来看一下客户端的处理逻辑:
func main() {tracer := zipkin.GetTracer(config.CLIENT_NAME, config.CLIENT_HOST)defer zipkin.Close()tracerClient := opentracing.NewClientWrapper(tracer)service := micro.NewService(micro.Name(config.CLIENT_NAME),micro.Address(config.CLIENT_HOST),micro.WrapClient(tracerClient),)client := service.Client()go func() {for {<-time.After(time.Second)result := new(string)request := client.NewRequest(config.SERVICE_NAME, "Hello.Say", "FireflySoft")err := client.Call(context.TODO(), request, result)if err != nil {log.Println(err)continue}log.Println(*result)}}()service.Run()}这段代码开始也是先NewService,设置客户端程序的名称和监听地址,然后通过micro.WrapClient注入链路跟踪,这里注入的是一个ClientWrapper,也是由opentracing插件提供的 。这里用的tracer和服务端tracer是一样的,都是通过config.go中GetTracer函数获取的 。
然后为了方便演示,启动一个go routine,客户端每隔一秒发起一次RPC请求,并将返回结果打印出来 。运行效果如图所示:
go-micro集成链路跟踪的方法和中间件原理

文章插图
 
zipkin中跟踪到的访问日志:
go-micro集成链路跟踪的方法和中间件原理

文章插图
【go-micro集成链路跟踪的方法和中间件原理】 
Wrap原理分析Wrap从字面意思上理解就是封装、嵌套,在很多的框架中也称为中间件,比如gin中,再比如ASP.NET Core中 。这个部分就来分析下go-micro中Wrap的原理 。


推荐阅读