开发者

golang 链路追踪的实现示例

目录
  • 问题
  • 解决方法
  • 链路追踪系统技术选型
  • 安装jaeger
  • 架构
  • 添加jaeger
    • 发送span
    • 嵌套span
  • grpc使用jaeger
    • gin使用jaeger

      分布式链路追踪(Distributed Tracing),也叫分布式链路跟踪,分布式跟踪,分布式追踪等等。

      问题

      场景1:调用链过长,查询很慢

      golang 链路追踪的实现示例

      web-gin由A负责,服务A由B负责,某个接口出现异常了,先查询日志看是哪个地方出错了,发现服务A调用失败,依次找到D

      场景2:接口相应很慢

      golang 链路追踪的实现示例

      解决方法

      (1)打日志:慢(可能不看懂其他人写的日志)

      (2)ELK:可以解决,也是日志需要写入

      (3)第三方链路追踪系统可以解决

      链路追踪系统技术选型

      Java使用zipkin和skywalking比较多,而go使用jaeger多

      zipkinjaegerskywalking
      OpenTracing
      客户端支持语言java、C#、php、python等java、c#、go、php、python等java、.Nhttp://www.devze.comet Core、Nodejs、PHP、python
      存储ES、mysql、Cassandra内存ES、kafka、Cassandra内存ES、H2、mysql、TIDB、shard sphere
      传输协议支持http、MQudp/httpgRPC
      ui丰富程度
      实现方式-代码侵入式拦截请求,侵入拦截请求,侵入字节码注入,无侵入
      扩展性
      trace查询支持支持支持
      性能损失
      选择jaeger:官方支持jaeger
      技术选型原则:
      客户端支持、综合考虑、什么语言开发的

      安装jaeger

      docker run \
        --rm \
        --name jaeger \
        -p6831:6831/udp \
        -p16686:16686 \
        jaegertracing/all-in-one:latest
      

      架构

      golang 链路追踪的实现示例

      Jaeger组成

      1.Jaeger Client - 为不同语言实现了符合 OpenTracing 标准的 SDK。应用程序通过 API 写入数据,client library 把 trace 信息按照应用程序指定的采样策略传递给 jaeger-agent。

      2.Agent - 它是一个监听在 UDP 端口上接收 span 数据的网络守护进程,它会将数据批量发送给 collector。它被设计成一个基础组件,部署到所有的宿主机上。Agent 将 client library 和 collector 解耦,为 client library 屏蔽了路由和发现 collector 的细节。2.Collector - 接收 jaeger-agent 发送来的数据,然后将数据写入后端存储。Collector 被设计成无状态的组件,因此您可以同时运行任意数量的 jaeger-collector。

      3.Data Store - 后端存储被设计成一个可插拔的组件,支持将数据写入 cassandra、elastic search。

      4.Query - 接收查询请求,然后从后端存储系统中检索 trace 并通过 UI 进行展示。 Query 是无状态的,您可以启动多个实例,把它们部署在android nginx 这样的负载均衡器后面。

      分布式追踪系统发展很快,种类繁多,但核心步骤一般有三个:代码埋点,数据存储、查询展示订单调用过程

      golang 链路追踪的实现示例

      添加jaeger

      sudo go get github.com/jaegertracing/jaeger-client-go
      

      发送span

      package main
      
      import (
      	"time"
      
      	"github.com/uber/jaeger-client-go"
      	jaegercfg "github.com/uber/jaeger-client-go/config"
      )
      
      func main() {
      	cfg := jaegercfg.Configuration{
      		Sampler: &jaegercfg.SamplerConfig{
      			Type:  jaeger.SamplerTypeConst,
      			Param: 1, //[0,1] 0不采样1一直采样
      		},
      		Reporter: &jaegercfg.ReporterConfig{
      			LogSpans:           true, //打不打印日志
      			LocalAgentHostPort: "192.168.31.19:6831",
      		},
      		ServiceName: "shop",
      	}
      	tracer, closer, err := cfg.NewTracer(jaegercfg.Logger(jaeger.StdLogger))
      	if err != nil {
      		panic(err)
      	}
      	defer closer.Close()
      	span := tracer.StartSpan("go-grpc-web")
      	time.Sleep(time.Second)
      	defer span.Finish()
      }
      
      

      嵌套span

      package main
      
      import (
      	"time"
      
      	"github.com/opentracing/opentracing-go"
      	"github.com/uber/jaeger-client-go"
      	jaegercfg "github.com/uber/jaeger-client-go/c编程onfig"
      )
      
      func main() {
      	cfg := jaegercfg.Configuration{
      		Sampler: &jaegercfg.SamplerConfig{
      			Type:  jaeger.SamplerTypeConst,
      			Param: 1, //[0,1] 0不采样1一直采样
      		},
      		Reporter: &jaegercfg.ReporterConfig{
      			LogSpans:           true, //打不打印日志
      			LocalAgentHostPort: "39.103.59.35:6831",
      		},
      		ServiceName: "shop",
      	}
      	tracer, closer, err := cfg.NewTracer(jaegercfg.Logger(jaeger.StdLogger))
      	if err != nil {
      		panic(err)
      	}
      	defer closer.Close()
      	parentSpan := tracer.StartSpan("main")
      
      	spanA := tracer.StartSpan("funcA", opentracing.ChildOf(parentSpan.Context()))
      	time.Sleep(time.Millisecond * 500)
      	spanA.Finish()
      
      	spanB := tracer.StartSpan("funcB", opentracing.ChildOf(parentSpan.Context()))
      	time.Sleep(time.Millisecond * 1000)
      	spanB.Finish()
      
      	parentSpan.Finish()
      }
      
      

      grpc使用jaeger

      package main
      
      import (
      android	"context"
      	"fmt"
      	"japter_test/proto"
      
      	"japter_test/otgrpc"
      
      	"github.com/opentracing/opentracing-go"
      	"github.com/uber/jaeger-client-go"
      	jaegercfg "github.com/uber/jaeger-client-go/config"
      	"google.golang.org/grpc"
      )
      
      func main() {
      	cfg := jaegercfg.Configuration{
      		ServiceName: "mxshop",
      		Sampler: &jaegercfg.SamplerConfig{
      			Typejavascript:  jaeger.SamplerTypeConst,
      			Param: 1, //[0,1] 0不采样1一直采样
      		},
      		Reporter: &jaegercfg.ReporterConfig{
      			LogSpans:           true, //打不打印日志
      			LocalAgentHostPort: "39.103.59.35:6831",
      		},
      	}
      	tracer, closer, err := cfg.NewTracer(jaegercfg.Logger(jaeger.StdLogger))
      	if err != nil {
      		panic(err)
      	}
      	opentracing.SetGlobalTracer(tracer)
      	defer closer.Close()
      
      	conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure(), grpc.WithUnaryInterceptor(otgrpc.OpenTracingClientInterceptor(opentracing.GlobalTracer())))
      	if err != nil {
      		panic(err)
      	}
      	defer conn.Close()
      	c := proto.NewGreeterClient(conn)
      	r, err := c.SayHello(context.Background(), &proto.HelloRquest{
      		Name: "bobby",
      	})
      	if err != nil {
      		panic(err)
      	}
      	fmt.Println(r.Message)
      }
      
      

      gin使用jaeger

      拦截器

      package middlewares
      
      import (
      	"GolangStudy/Practice/shop/goods-web/global"
      	"fmt"
      
      	"github.com/gin-gonic/gin"
      	"github.com/opentracing/opentracing-go"
      	"github.com/uber/jaeger-client-go"
      	jaegerConfig "github.com/uber/jaeger-client-go/config"
      )
      
      func Trace() gin.HandlerFunc {
      	return func(ctx *gin.Context) {
      		cfg := jaegerConfig.Configuration{
      			ServiceName: "your_service_name",
      			Sampler: &jaegerConfig.SamplerConfig{
      				Type:  jaeger.SamplerTypeConst,
      				Param: 1, // 1 = always sample
      			},
      			Reporter: &jaegerConfig.ReporterConfig{
      				LogSpans:           true,
      				LocalAgentHostPort: fmt.Sprintf("%s:%d", global.ServerConfig.JaegerInfo.Host, global.ServerConfig.JaegerInfo.Port), // Jaeger Query 服务的地址和端口
      			},
      		}
      		tracer, closer, err := cfg.NewTracer(jaegerConfig.Logger(jaeger.StdLogger))
      		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()
      	}
      }
      
      

      使用

      GoodsRouter := Router.Group("goods").Use(middlewares.Trace())

      到此这篇关于golang 链路追踪的实现示例的文章就介绍到这了,更多相关golang 链路追踪内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)! 

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜