自学内容网 自学内容网

gin集成jaeger中间件实现链路追踪

1. 背景

新业务线带来新项目启动,需要改进原有项目的基础框架和组件能力,以提升后续开发和维护效率。项目搭建主要包括技术选型、框架搭建、基础服务搭建等。这其中就涉及到链路追踪的内容,结合其中的踩坑情况,用一篇文章来说明完整的链路搭建过程。

2. 技术选型

2.1 方案对比

图【1】来自网络,请自行对比验证

图 1

2.2 选型

本项目基于golanggin框架,以及链路中间件对比,选择jaeger作为工具进行集成。

3. 核心实现

3.1 jaeger服务搭建

这里就借助网上的all-in-one的docker方式搭建即可,无需多费力。

docker run --rm --name jaeger \
  -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 4317:4317 \
  -p 4318:4318 \
  -p 14250:14250 \
  -p 14268:14268 \
  -p 14269:14269 \
  -p 9411:9411 \
  jaegertracing/all-in-one:1.60

这里启动了很多端口,详细的自查即可,这里两个比较重要的端口如下:

16686:服务前端端口,ip:port 可访问UI
6831:项目中连接端口

jaeger界面图【2】所示。

图 2

3.2 protoc编译器及语言插件安装

protobuf协议,是一种跨语言、跨平台的数据结构序列化和反序列化框架,类似于thrift协议

1 编写 .proto ⽂件,⽬的是为了定义结构对象(message)及属性内容。
2 使⽤ protoc 编译器编译 .proto ⽂件,⽣成⼀系列接⼝代码,存放在新⽣成头⽂件和源⽂件中。
3 依赖⽣成的接⼝,将编译⽣成的头⽂件包含进我们的代码中,实现对 .proto ⽂件中定义的字段进行设置和获取,和对 message 对象进行序列化和反序列化

安装

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

编写proto文件

syntax = "proto3";

option go_package = "./proto";
package helloworld;

service Greeter {
  rpc SayHello (HelloReq) returns (HelloResp);
}

message HelloReq {
  string name = 1;
}

message HelloResp {
  string message = 1;
}

编译proto

protoc --go_out ../ helloword.proto

3.2 项目实现

项目架构是上层服务http,下层服务rpc,选用protobuf协议(跨语言、跨平台的数据结构序列化和反序列化框架,类似于thrift协议)作为就以简单的helloword为例实现。
核心插件jaeger、opentracing和otgrpc

在上层增加中间件并注册到engine上。

package middleware

import (
"github.com/gin-gonic/gin"
"github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-client-go"
jaegercfg "github.com/uber/jaeger-client-go/config"
)

func Trace() gin.HandlerFunc {
return func(ctx *gin.Context) {
cfg := jaegercfg.Configuration{
ServiceName: "demo", //服务名称
Sampler: &jaegercfg.SamplerConfig{
Type:  jaeger.SamplerTypeConst,
Param: 1,
},
Reporter: &jaegercfg.ReporterConfig{
LogSpans:           true,
LocalAgentHostPort: "xxxx:6831", //jaeger 服务器ip
},
}

tracer, closer, err := cfg.NewTracer()
if err != nil {
panic(err)
}
opentracing.SetGlobalTracer(tracer)
defer closer.Close()

startSpan := tracer.StartSpan(ctx.Request.URL.Path)
defer startSpan.Finish()
ctx.Set("tracer", tracer)
ctx.Set("parentSpan", startSpan)
ctx.Next()
}
}
// rpc调用设置globaltracer
consul := ServerConfig.Consul
conn, err := grpc.Dial(
fmt.Sprintf("consul://%s:%s/%s?wait=14s", consul.Host, consul.Port, ServerName),
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy": "round_robin"}`),
grpc.WithUnaryInterceptor(otgrpc.OpenTracingClientInterceptor(opentracing.GlobalTracer())), //这里把全局tracer传下去
)
// 注册路由中间件
engine.Use(middleware.Trace())

启动项目访问就可以在jaeger上看到链路信息。

图 3

点击进入详情页查看信息,这时候大家发现一个问题,这里只有http层的调用信息,没有rpc层,这也是网上所有介绍的文档里没有说明白的一点。

图 4

真正原因是中间件代码里的tracer和parentSpan没有传递下去。

startSpan := tracer.StartSpan(ctx.Request.URL.Path)
defer startSpan.Finish()
ctx.Set("tracer", tracer)
ctx.Set("parentSpan", startSpan) // 虽然设置了,没有跟随rpc传下去
ctx.Next()

怎么传递呢?(这里是关键)
首先是在rpc服务发现时传递全局tracer

#引入传递tracer的包
go get github.com/lisw358/tts_otgrpc

源码里有一个地方别人做了改动,来实现tracer传递,改动如下:

//=============================自己改源码部分开始
//获取到父span和trace
//此处需要在ctx上有这个key来向下传递tracer和parentSpan
ginConetext := ctx.Value("ginContext") 
switch ginConetext.(type) {
case *gin.Context:
//获取trace
if itrace, ok := ginConetext.(*gin.Context).Get("tracer"); ok {
tracer = itrace.(opentracing.Tracer)
}

//获取父span
if parentSpan, ok := ginConetext.(*gin.Context).Get("parentSpan"); ok {
parentCtx = parentSpan.(*jaeger.Span).Context()
}
}
//=============================自己改源码部分结束

因此全局定义一个ContextWapper,来增加ginContext的设置


func ContextWrapper(c *gin.Context) context.Context {
return context.WithValue(context.Background(), GinContext, c)
}

然后在调用时处理一下context即可

req := &proto.HelloReq{}
req.Name = c.DefaultQuery("name", "guest")

//这里包装了一下context,来保证otgrpc包里能正常判断ginContext变量,来生成子span
res, _ := services.SayHello(global.ContextWrapper(c), req)
c.JSON(0, res.Message)

jaeger链路追踪结果如图【5】所示

图 5

本文完

参考文档

  1. jaeger tracing document
  2. https://chenquan.me/posts/tracing-system-analysis/
  3. https://github.com/lisw358/tts_otgrpc
  4. https://blog.51cto.com/u_15481067/11749036

如有侵权,烦请联系删除


原文地址:https://blog.csdn.net/cjqh_hao/article/details/141993511

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!