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

栏目: 后端 · 发布时间: 5年前

内容简介:现代互联网服务通常是使用复杂的、大规模的分布式系统来实现的。这些应用程序往往是由大量的软件模块构建的,而且这些软件模块可能由不同的团队开发,可能使用不同的编程语言,并且可以跨多个物理设施跨越数千台机器。在这种环境中,帮助理解系统行为和性能问题推理的工具是非常宝贵的。微服务架构是一个分布式架构,实际开发中,我们按照业务要求划分服务单元,一套系统往往会由多个业务单元构成。在这个场景中,一个请求可能需要经历多个业务单元的处理才能完成响应,如果出现了错误或异常,很难定位。为了解决这个问题,谷歌开源了分布式链路追踪组

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

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

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

Zipkin

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

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

通过架构图可知,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#、 goJava 、JavaScript、 Ruby 、Scala、PHP,另外社区也贡献了 Python 、C/C++、 Lua 等语言的支持。

实战演练

Step-0:准备工作

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

gateway

go-kit在 tracing 包中默认添加了 zipkin 的支持,所以集成工作将会比较轻松。在开始之前,需要下载以下依赖:

# 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的数量、途径的服务名称等信息。

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

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

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

通过该界面,我们可以知道请求链路中比较耗时的环节为 gateway-service 。原因是:每次请求过来,程序都要到Consul中查询服务实例,动态创建服务地址。

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

总结

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


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Sovereign Individual

The Sovereign Individual

James Dale Davidson、William Rees-Mogg / Free Press / 1999-08-26 / USD 16.00

Two renowned investment advisors and authors of the bestseller The Great Reckoning bring to light both currents of disaster and the potential for prosperity and renewal in the face of radical changes ......一起来看看 《The Sovereign Individual》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具