go-micro V2 从零开始(八)集成链路追踪工具jaeger

本文相关代码:gitee


前言

这一章我们继续使用go-plugins库中插件,以Wrapper方式集成链路追踪工具jaeger


步骤

一、jaeger

1.1 简介

Jaeger是一个GO语言开发的微服务链路追踪工具,用于分布式系统监控和故障排除,他的主要特性包括:

  • 分布式上下文传播
  • 分布式事务监控
  • 根本原因分析
  • 服务依赖关系分析
  • 性能/延迟优化

以上内容翻译自jaeger官方文档,更多内容请查阅官网:jaeger

1.2 启动

演示原因,这里以官方文档默认docker命令启动服务:

docker run -d --name jaeger \
  -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
  -p 5775:5775/udp \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 14268:14268 \
  -p 14250:14250 \
  -p 9411:9411 \
  jaegertracing/all-in-one:1.20

浏览器输入localhost:16686即可进入管理界面:
在这里插入图片描述


二、OpenTracing

2.1 简介

go-plugins库并没有开发专门的jaeger插件,而是引入了OpenTracing

OpenTracing我理解是一套标准的追踪接口,通过提供平台无关、厂商无关的API,使得开发人员能够方便的添加(或更换)追踪系统的实现。而 jaeger兼容OpenTracing API,所以我们使用OpenTracing的程序库就可以方便的接入jaeger。

OpenTracing中文文档: https://wu-sheng.gitbooks.io/opentracing-io/content/

OpenTracing插件:https://github.com/micro/go-plugins/tree/master/wrapper/trace/opentracing/v2

2.2 配置

由于我们的服务都将注册到同一个jaeger中(否则也谈不上链路追踪)配置大同小异,创建common文件夹为所有服务提供统一配置函数,这里我们提取了jaeger配置函数和之前的mongo配置函数:
在这里插入图片描述
jaeger.go:

package tracer

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

// 配置jaeger
func NewJaegerTracer(serviceName string, addr string) (opentracing.Tracer, io.Closer, error) {
	cfg := jaegercfg.Configuration{
		ServiceName: serviceName,
		Sampler: &jaegercfg.SamplerConfig{
			Type:  jaeger.SamplerTypeConst,
			Param: 1,
		},
		Reporter: &jaegercfg.ReporterConfig{
			LogSpans:            true,
			BufferFlushInterval: 1 * time.Second,
		},
	}

	sender, err := jaeger.NewUDPTransport(addr, 0)
	if err != nil {
		return nil, nil, err
	}

	reporter := jaeger.NewRemoteReporter(sender)
	tracer, closer, err := cfg.NewTracer(
		jaegercfg.Reporter(reporter),
	)

	return tracer, closer, err
}

三、代码改造

查看opentracing插件代码,插件中提供了4种wrapper,分别用于不同服务类型:

  • WrapHandler() server中间件
  • WrapCall() call中间件
  • WrapClient() client中间件
  • WrapSubscriber() 订阅中间件

下面我们重点演示server、client和Subscriber的引入方法

3.1 WrapHandler

task-srv服务为例,修改main.go:

package main

import (
	...
	// 引入插件
	"github.com/micro/go-plugins/wrapper/trace/opentracing/v2"
	// 引入公共的自定义配置函数
	"go-todolist/common/tracer"
	...
)

// 所有port都是服务默认端口,ip请根据实际情况配置
const (
	// 项目服务名和注册到Jaeger的服务名一致,保障更容易定位到具体服务
	ServerName = "go.micro.service.task"
		
	...
	
	// 服务地址
	JaegerAddr = "172.18.0.58:6831"
)

// task-srv服务
func main() {
	...

	// 配置jaeger连接
	jaegerTracer, closer, err := tracer.NewJaegerTracer(ServerName, JaegerAddr)
	if err != nil {
		log.Fatal(err)
	}
	defer closer.Close()

	// New Service
	service := micro.NewService(
		micro.Name(ServerName),
		
		...
		
		// 配置链路追踪为jaeger
		micro.WrapHandler(opentracing.NewHandlerWrapper(jaegerTracer)),
	)

	...
}

3.2 WrapClient

task-api服务为例,之前我们已经在main.go中注册了一个WrapClient——hystrix,现在再增加opentracing,注意插件是注册在调用服务上而不是web服务上:

package main

import (
	...
	// 引入插件
	"github.com/micro/go-plugins/wrapper/trace/opentracing/v2"
	// 引入公共的自定义配置函数
	"go-todolist/common/tracer"
	...
)

const (
	// 项目服务名和注册到Jaeger的服务名一致,保障更容易定位到具体服务
	ServerName = "go.micro.api.task"
	...
	// 服务地址
	JaegerAddr = "172.18.0.58:6831"
)

// task-srv服务的restful api映射
func main() {
	// 配置jaeger连接
	jaegerTracer, closer, err := tracer.NewJaegerTracer(ServerName, JaegerAddr)
	if err != nil {
		log.Fatal(err)
	}
	defer closer.Close()

	...
	
	app := micro.NewService(
		micro.Name("go.micro.client.task"),
		...
		micro.WrapClient(
			// 引入hystrix包装器
			hystrix.NewClientWrapper(),
			// 配置链路追踪为jaeger
			opentracing.NewClientWrapper(jaegerTracer),
		),
	)
}

3.3 WrapSubscriber

网上教程大多只提到server和client,很少提到消息服务,虽然他们注册方式大同小异,但我觉得还是有必要演示一下。
achievement-srv服务为例,修改main.go:

package main

import (
	...
	// 引入插件
	"github.com/micro/go-plugins/wrapper/trace/opentracing/v2"
	// 引入公共的自定义配置函数
	"go-todolist/common/tracer"
	...
)

// 这里是我内网的mongo地址,请根据你得实际情况配置,推荐使用dockers部署
const (
	// 项目服务名和注册到Jaeger的服务名一致,保障更容易定位到具体服务
	ServerName = "go.micro.service.achievement"
	
	...
	
	// 服务地址
	JaegerAddr = "172.18.0.58:6831"
)

// achievement-srv服务
func main() {
	...
	
	// 配置jaeger连接
	jaegerTracer, closer, err := tracer.NewJaegerTracer(ServerName, JaegerAddr)
	if err != nil {
		log.Fatal(err)
	}
	defer closer.Close()
	
	// New Service
	service := micro.NewService(
		micro.Name(ServerName),
		
		...
		
		// 配置链路追踪为jaeger
		micro.WrapSubscriber(opentracing.NewSubscriberWrapper(jaegerTracer)),
	)
	...
}

3.4 Finished接口web api

之前task-api只实现了一个Search接口,这边为了测试消息队列的追踪,我们再实现一下任务完成的Finished接口。
提取之前main.go中的Router方法到新建的handler/router.go:

package handler

import (
	"github.com/gin-gonic/gin"
	pb "go-todolist/task-srv/proto/task"
)

var service pb.TaskService

func Router(g *gin.Engine, taskService pb.TaskService) {
	service = taskService
	v1 := g.Group("/task")
	{
		v1.GET("/search", Search)
		v1.POST("/finished", Finished)
	}
}

func Search(c *gin.Context) {
	...
}

func Finished(c *gin.Context) {
	req := new(pb.Task)
	if err := c.BindJSON(req); err != nil {
		c.JSON(200, gin.H{
			"code": "500",
			"msg":  "bad param",
		})
		return
	}
	if resp, err := service.Finished(c, req); err != nil {
		c.JSON(200, gin.H{
			"code": "500",
			"msg":  err.Error(),
		})
	} else {
		c.JSON(200, gin.H{
			"code": "200",
			"data": resp,
		})
	}
}

四、验证

使用postman访问finished接口:
在这里插入图片描述
再次打开jaeger管理界面,点击左下角Find Traces按钮,就会看到之前的调用记录:
在这里插入图片描述
可以看到所有涉及的微服务都已被记录,点击这个条目还能看到详细信息,这里就不赘述了。


总结

本章我们展示了在不同服务中通过OpenTracing集成jaeger服务。
如果你还看过其他教程,应该还会看到如何将jaeger集成到micro api网关中,这涉及到micro包的plugin插件接口开发,不能简单集成go-plugins插件,而且那些教程实测并不能很好的实现链路整合,后期如果我找到好的实现方案了会单独写文分享。


支持一下

原创不易,买杯咖啡,谢谢:p

支持一下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值