十,分布式链路追踪

链路追踪 Zipkin

Zipkin是 Twitter 的一个开源项目,基于 Google Dapper实现。使用它来收集各个服务器上请求链路的跟踪数据,及时地发现系统中出现的延迟问题,找出系统的性能瓶颈。

十,分布式链路追踪_第1张图片

项目中应用

完整代码:

https://github.com/Justin02180218/micro-kit

配置文件

zipkin:
  url: "http://zipkin-server:9411/api/v2/spans"
  service_name: "user-service"
  reporter:
    timeout: 5
    batch_size: 1000
    batch_interval: 3
    max_backlog: 10000

在hosts中配置zipkin-server域名

config.go

type ZipkinConfig struct {
    Url         string `json:"url" yaml:"url"`
    ServiceName string `json:"service_name" yaml:"service_name"`
    Reporter    struct {
        Timeout       int `json:"timeout" yaml:"timeout"`
        BatchSize     int `json:"batch_size" yaml:"batch_size"`
        BatchInterval int `json:"batch_interval" yaml:"batch_interval"`
        MaxBacklog    int `json:"max_backlog" yaml:"max_backlog"`
    }
}

 

pkg/tracers

在 pkg 下新建目录 tracers,创建 zipkin.go 文件: 

十,分布式链路追踪_第2张图片

 

代码如下:

// 创建 Reporter
func NewZipkinReporter(zipkinCfg *configs.ZipkinConfig) reporter.Reporter {
    return zipkinhttp.NewReporter(
        zipkinCfg.Url,
        zipkinhttp.Timeout(time.Duration(zipkinCfg.Reporter.Timeout)*time.Second),
        zipkinhttp.BatchSize(zipkinCfg.Reporter.BatchSize),
        zipkinhttp.BatchInterval(time.Duration(zipkinCfg.Reporter.BatchInterval)*time.Second),
        zipkinhttp.MaxBacklog(zipkinCfg.Reporter.MaxBacklog),
    )
}

// 创建 Tracer
func NewZipkinTracer(serviceName string, reporter reporter.Reporter) *gozipkin.Tracer {
    zEP, _ := gozipkin.NewEndpoint(serviceName, "")
    tracerOptions := []gozipkin.TracerOption{
        gozipkin.WithLocalEndpoint(zEP),
    }
    tracer, err := gozipkin.NewTracer(reporter, tracerOptions...)
    if err != nil {
        fmt.Println(err)
        return nil
    }
    return tracer
}

func Zipkin(tracer *gozipkin.Tracer, name string) endpoint.Middleware {
    return zipkin.TraceEndpoint(tracer, name)
}

func MakeHttpServerOptions(zipkinTracer *gozipkin.Tracer, name string) []http.ServerOption {
    zipkinServiceTrace := zipkin.HTTPServerTrace(zipkinTracer, zipkin.Name(name))
    options := []http.ServerOption{zipkinServiceTrace}
    return options
}

func MakeHttpClientOptions(zipkinTracer *gozipkin.Tracer, name string) []http.ClientOption {
    zipkinClientTrace := zipkin.HTTPClientTrace(zipkinTracer, zipkin.Name(name))
    options := []http.ClientOption{zipkinClientTrace}
    return options
}

func MakeGrpcServerOptions(zipkinTracer *gozipkin.Tracer, name string) []grpc.ServerOption {
    zipkinServiceTrace := zipkin.GRPCServerTrace(zipkinTracer, zipkin.Name(name))
    options := []grpc.ServerOption{zipkinServiceTrace}
    return options
}

func MakeGrpcClientOptions(zipkinTracer *gozipkin.Tracer, name string) []grpc.ClientOption {
    zipkinClientTrace := zipkin.GRPCClientTrace(zipkinTracer, zipkin.Name(name))
    options := []grpc.ClientOption{zipkinClientTrace}
    return options
}

 

endpoint层

修改book-rpc-endpoint.go,以library-user-service为例,其他微服务相同。

func MakeFindBooksEndpoint(instance string, tracer *gozipkin.Tracer) endpoint.Endpoint {
    conn, err := grpc.Dial(instance, grpc.WithInsecure())
    if err != nil {
        fmt.Println(err)
        return nil
    }
    findBooksEndpoint := grpctransport.NewClient(
        conn, "book.Book", "FindBooksByUserID",
        encodeGRPCFindBooksRequest,
        decodeGRPCFindBooksResponse,
        pbbook.BooksResponse{},
        tracers.MakeGrpcClientOptions(tracer, "grpc-transport-findBooks")...,
    ).Endpoint()
    return findBooksEndpoint
}

 

transport层

修改user_transport.go,以library-user-service为例,其他微服务相同。

func NewHttpHandler(ctx context.Context, endpoints *endpoint.UserEndpoints, tracer *gozipkin.Tracer) *gin.Engine {
    r := utils.NewRouter(ctx.Value("ginMod").(string))
    e := r.Group("/api/v1")
    {
        e.POST("register", func(c *gin.Context) {
            kithttp.NewServer(
                endpoints.RegisterEndpoint,
                decodeRegisterRequest,
                utils.EncodeJsonResponse,
                tracers.MakeHttpServerOptions(tracer, "transport-register")...,
            ).ServeHTTP(c.Writer, c.Request)
        })
        ......
    }
}

修改 main.go

以 library-user-service 为例,其他微服务相同。

reporter := tracers.NewZipkinReporter(config.Conf.ZipkinConfig)
defer reporter.Close()
tracer := tracers.NewZipkinTracer(config.Conf.ZipkinConfig.ServiceName, reporter)
findBooksEndpoint := endpoint.MakeFindBooksEndpoint
grpcClient := registers.GRPCClient(config.Conf, findBooksEndpoint, tracer, logger)
hystrix.ConfigureCommand("Find books", hystrix.CommandConfig{Timeout: 1000})
grpcClient = circuitbreakers.Hystrix("Find books", "book-rpc-service currently unavailable")(grpcClient)
grpcClient = tracers.Zipkin(tracer, "grpc-endpoint-findBooks")(grpcClient)

......

userEndpoints := &endpoint.UserEndpoints{
    RegisterEndpoint:          tracers.Zipkin(tracer, "endpoint-register")(ratelimit(endpoint.MakeRegisterEndpoint(userService))),
    FindByIDEndpoint:          tracers.Zipkin(tracer, "endpoint-findByID")(ratelimit(endpoint.MakeFindByIDEndpoint(userService))),
    FindByEmailEndpoint:       tracers.Zipkin(tracer, "endpoint-findByEmail")(ratelimit(endpoint.MakeFindByEmailEndpoint(userService))),
    FindBooksByUserIDEndpoint: tracers.Zipkin(tracer, "endpoint-findBooks")(ratelimit(endpoint.MakeFindBooksByUserIDEndpoint(userService))),
    HealthEndpoint:            tracers.Zipkin(tracer, "endpoint-health")(ratelimit(endpoint.MakeHealthEndpoint(userService))),
}

启动 Zipkin

使用 Docker 启动 zipkin

docker pull openzipkin/zipkin

docker run -d -p 9411:9411 --name zipkin openzipkin/zipkin

启动服务,通过网关访问 library-user-service 微服务的 findBooksByUserID 接口。

在浏览器地址栏输入:http://zipkin-server:9411/

点击 "RUN QUERY" 按钮 

十,分布式链路追踪_第3张图片

继续点击第一行的 "SHOW" 按钮

十,分布式链路追踪_第4张图片

 

下一篇文章,我们在各个微服务中加入服务监控功能。

完整代码:

https://github.com/Justin02180218/micro-kit


更多【分布式专辑】【架构实战专辑】系列文章,请关注公众号

你可能感兴趣的