go-kit微服务:服务链路追踪

链路追踪

现代互联网服务一般是使用复杂的、大规模的分布式系统来实现的。这些应用程序每每是由大量的软件模块构建的,并且这些软件模块可能由不一样的团队开发,可能使用不一样的编程语言,而且能够跨多个物理设施跨越数千台机器。在这种环境中,帮助理解系统行为和性能问题推理的工具是很是宝贵的。git

微服务架构是一个分布式架构,实际开发中,咱们按照业务要求划分服务单元,一套系统每每会由多个业务单元构成。在这个场景中,一个请求可能须要经历多个业务单元的处理才能完成响应,若是出现了错误或异常,很难定位。github

为了解决这个问题,谷歌开源了分布式链路追踪组件Drapper,并发表论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》介绍了Drapper的设计思想。在该论文的影响下,Twitter设计、研发并开源了分布式链路追踪系统Zipkin。golang

Zipkin

Zipkin是一个分布式跟踪系统,它能够帮助收集时间数据,以此解决在微服务架构下的延迟问题。它同时提供了分布式系统时间数据的收集和查询功能。Zipkin的架构以下图所示:docker

Zipkin官方架构图

经过架构图可知,Zipkin由Collector、Storage、API、UI共4个组件构成,Reporter由应用系统提供并收集数据,其工做原理大概以下:数据库

  • 在应用程序中嵌入追踪器(Tracer),它使用Span记录应用程序动做的时间和元数据信息;
  • Reporter把Span发送至Zipkin的数据收集器Collector;
  • Collector经过Storage组件把数据存储至数据库;
  • UI组件经过API接口查询追踪数据并显示;

Zipkin经过Trace结构表示对一次请求的跟踪,一次请求由若干服务处理,每一个服务生成一个Span,同一请求的Span之间存在关联关系,在UI组件中以树形式展现。Span的主要数据模型以下所示:编程

字段 类型 说明
traceId string 随机生成,用于惟一标识一个追踪信息,全部的span都包含此信息。
name string span的名称,可以使用method命名,在UI组件中显示
parentId string 父级span的编号,若为空,则表示为根span
id string span的编号
timestamp integer span建立的时间
duration integer span持续时间
annotations Annotation 关联一个事件,用时间戳解释延迟信息
tags Tags span的标签,用于搜索、显示和分析

Zipkin官方已经推出各类常见语言的支持,如C#、go、Java、JavaScript、Ruby、Scala、PHP,另外社区也贡献了Python、C/C++、Lua等语言的支持。bootstrap

实战演练

Step-0:准备工做

本文将延续“go-kit微服务系列”,使用go-kit集成Zipkin实现算术运算服务的链路追踪,这里将包含两个部分:segmentfault

  • 在网关gateway中增长链路追踪采集逻辑,同时在反向代理中增长追踪设置。
  • 在算术运算服务的传输层和Endpoint层增长链路追踪采集逻辑。

go-kit在tracing包中默认添加了zipkin的支持,因此集成工做将会比较轻松。在开始以前,须要下载如下依赖:api

# zipkin官方库
go get github.com/openzipkin/zipkin-go

# 下面三个包都是依赖,按需下载
git clone https://github.com/googleapis/googleapis.git [your GOPATH]/src/google.golang.org/genproto

git clone https://github.com/grpc/grpc-go.git [your GOPATH]/src/google.golang.org/grpc

git clone https://github.com/golang/text.git [your GOPATH]/src/golang.org/text
复制代码

本次演练使用arithmetic_consul_demo中的gatewayregister两个服务,复制该目录并重命名为arithmetic_trace_demo,删除discover浏览器

Step-1:Docker启动Zipkin

  1. 打开文件docker/docker-compose.yml,在consul的基础上增长zipkin配置信息(使用官方推荐的openzipkin/zipkin),最终内容以下所示:
version: '2'

services:
  consul:
    image: progrium/consul:latest
    ports:
      - 8400:8400
      - 8500:8500
      - 8600:53/udp
    hostname: consulserver
    command: -server -bootstrap -ui-dir /ui

  zipkin:
    image: openzipkin/zipkin
    ports:
      - 9411:9411
复制代码
  1. 打开终端切换至docker目录,执行如下命令,启动consul和zipkin。
sudo docker-compose up
复制代码
  1. 启动成功后,打开浏览器输入http://localhost:9411检查是否启动成功。

Step-2:修改gateway

gateway将做为链路追踪的第一站和最后一站,咱们须要截获到达gateway的全部请求,记录追踪信息。gateway做为外部请求的服务端,同时做为算术运算服务的客户端(反向代理内部实现)。

建立追踪器

结合Zipkin的架构图,须要在应用程序中集成Reporter组件,咱们使用官方提供的go包。代码以下(默认设置了zipkin的url):

// 建立环境变量
var (
	// consul环境变量省略
	zipkinURL  = flag.String("zipkin.url", "http://192.168.192.146:9411/api/v2/spans", "Zipkin server url")
	)
flag.Parse()

var zipkinTracer *zipkin.Tracer
{
	var (
		err           error
		hostPort      = "localhost:9090"
		serviceName   = "gateway-service"
		useNoopTracer = (*zipkinURL == "")
		reporter      = zipkinhttp.NewReporter(*zipkinURL)
	)
	defer reporter.Close()
	zEP, _ := zipkin.NewEndpoint(serviceName, hostPort)
	zipkinTracer, err = zipkin.NewTracer(
		reporter, zipkin.WithLocalEndpoint(zEP), zipkin.WithNoopTracer(useNoopTracer),
	)
	if err != nil {
		logger.Log("err", err)
		os.Exit(1)
	}
	if !useNoopTracer {
		logger.Log("tracer", "Zipkin", "type", "Native", "URL", *zipkinURL)
	}
}
复制代码

为全部请求增长链路追踪

咱们使用的传输方式为http,可使用zipkin-go提供的middleware/http包,它采用装饰者模式把咱们的http.Handler进行封装,而后启动监听便可,代码以下所示:

//建立反向代理
proxy := NewReverseProxy(consulClient, zipkinTracer, logger)

tags := map[string]string{
	"component": "gateway_server",
}

handler := zipkinhttpsvr.NewServerMiddleware(
	zipkinTracer,
	zipkinhttpsvr.SpanName("gateway"),
	zipkinhttpsvr.TagResponseSize(true),
	zipkinhttpsvr.ServerTags(tags),
)(proxy)
复制代码

反向代理设置

gateway接收请求后,会建立一个span,其中的traceId将做为本次请求的惟一编号,gateway必须把这个traceId“告诉”算术运算服务,算术运算服务才能为该请求持续记录追踪信息。

ReverseProxy中可以完成这一任务的就是Transport,咱们可使用zipkin-gomiddleware/http包提供的NewTransport替换系统默认的http.DefaultTransport。代码以下所示:

// NewReverseProxy 建立反向代理处理方法
func NewReverseProxy(client *api.Client, zikkinTracer *zipkin.Tracer, logger log.Logger) *httputil.ReverseProxy {

	//建立Director
	director := func(req *http.Request) {
        //省略
	}

	// 为反向代理增长追踪逻辑,使用以下RoundTrip代替默认Transport
	roundTrip, _ := zipkinhttpsvr.NewTransport(zikkinTracer, zipkinhttpsvr.TransportTrace(true))

	return &httputil.ReverseProxy{
		Director:  director,
		Transport: roundTrip,
	}
}
复制代码

这一步很关键!若不设置,会致使整个链路追踪不完整。为了解决这个问题,花费了很多时间,最后仍是经过zipkin-goREADME解开了疑惑。

完成以上过程,就能够编译运行了。

Step-3:修改算术服务

建立追踪器

这一步与gateway的处理方式同样,再也不描述。

追踪Endpoint

go-kit提供了对zipkin-go的封装,可直接调用中间件TraceEndpoint对算术运算服务的两个Endpoint进行设置。代码以下:

endpoint := MakeArithmeticEndpoint(svc)
endpoint = NewTokenBucketLimitterWithBuildIn(ratebucket)(endpoint)
//添加追踪,设置span的名称为calculate-endpoint
endpoint = kitzipkin.TraceEndpoint(zipkinTracer, "calculate-endpoint")(endpoint)

//建立健康检查的Endpoint
healthEndpoint := MakeHealthCheckEndpoint(svc)
healthEndpoint = NewTokenBucketLimitterWithBuildIn(ratebucket)(healthEndpoint)
//添加追踪,设置span的名称为health-endpoint
healthEndpoint = kitzipkin.TraceEndpoint(zipkinTracer, "health-endpoint")(healthEndpoint)
复制代码

追踪Transport

  1. 修改transports.goMakeHttpHandler方法。增长参数zipkinTracer,而后在ServerOption中设置追踪参数。代码以下:
// MakeHttpHandler make http handler use mux
func MakeHttpHandler(ctx context.Context, endpoints ArithmeticEndpoints, zipkinTracer *gozipkin.Tracer, logger log.Logger) http.Handler {
	r := mux.NewRouter()

	zipkinServer := zipkin.HTTPServerTrace(zipkinTracer, zipkin.Name("http-transport"))

	options := []kithttp.ServerOption{
		kithttp.ServerErrorLogger(logger),
		kithttp.ServerErrorEncoder(kithttp.DefaultErrorEncoder),
		zipkinServer,
	}

	//省略代码

	return r
}
复制代码
  1. main.go中调用MakeHttpHandler
//建立http.Handler
r := MakeHttpHandler(ctx, endpts, zipkinTracer, logger)
复制代码

至此,全部的代码修改工做已经完成,下一步就是启动测试了。

Step-4:运行&测试

确保ConsulZipkingatewayregister四个服务已经正常运行,而后使用Postman进行请求测试(与以前相似,为了方便查看数据,可多点几回)。

在浏览器中打开http://localhost:9411,点击“Find Traces”按钮,便可看到以下界面。详细显示了每一个请求执行的时间、span的数量、途径的服务名称等信息。

打开第一个请求,进入该请求的链路追踪界面,以下图所示。

链路追踪

  • 上半部分显示:,该请求的执行时间为10.970毫秒、途径的服务为2个、链路深度为三、span数量为3。
  • 下半部分显示:以树形方式显示span,直观展现每一个span的途径服务、执行时间、span名称等信息。

经过该界面,咱们能够知道请求链路中比较耗时的环节为gateway-service。缘由是:每次请求过来,程序都要到Consul中查询服务实例,动态建立服务地址。

另外,点击树形结构的每一个span,能够查看span的描述信息,这里再也不展开描述。

总结

本文使用go-kit的tracing组件和zipkin-go包,为网关服务和算术运算服务增长了链路追踪功能,以实例方式演示了在go-kit中集成Zipkin的方式。示例比较简单,但愿对你有用!

本文参考

本文首发于本人微信公众号【兮一昂吧】,欢迎扫码关注!

相关文章
相关标签/搜索