go 链路追踪_【go-micro实践】jaeger分布式链路追踪
安装jaeger
jaeger提供一个all in one 的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 9411:9411
jaegertracing/all-in-one:1.6
复制代码
OpenTracing
OpenTracing通过提供平台无关、厂商无关的API,使得开发人员能够方便的添加(或更换)追踪系统的实现。 OpenTracing提供了用于运营支撑系统的和针对特定平台的辅助程序库。
jaeger兼容OpenTracing API,所以我们使用OpenTracing的程序库可以方便的替换追踪工具。
OpenTracing中文文档
jaeger使用
封住一下jaeger的初始化操作方便使用,详细用法可以查看 jaeger-client-go
// lib/tracer
// NewTracer 创建一个jaeger Tracer
func NewTracer(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)
// Initialize tracer with a logger and a metrics factory
tracer, closer, err := cfg.NewTracer(
jaegercfg.Reporter(reporter),
)
return tracer, closer, err
}
func main() {
t, io, err := tracer.NewTracer("tracer", "")
if err != nil {
log.Fatal(err)
}
defer io.Close()
opentracing.SetGlobalTracer(t)
}
复制代码
opentracing.SetGlobalTracer(t) 方法执行会将jaeger tracer注册到全局,接下来只需要使用opentracing 的标准API便可以了。
如果不想使用jaeger了,想替换成其他分布式追踪工具,只需要工具支持opentracing标准,并将main函数的SetGlobalTracer操作替换即可,其他文件都不需要更改。
micro链路追踪插件
micro自带的opentracing插件
在micro自带的插件中已经有opentracing的插件了,包含server,client等,不过这个插件只能go-micro构建的微服务(api,srv)中使用。因为micro网关有一个独立的插件系统,但是并没有提供opentracing相关的插件。
micro/go-plugins/wrapper/trace/opentracing/opentracing.go
我们可以在构建服务的时候直接使用,只需要在服务初始化时增加一行函数就可以了。
service := micro.NewService(
micro.Name(name),
micro.Version("latest"),
micro.WrapHandler(ocplugin.NewHandlerWrapper(opentracing.GlobalTracer())),
)
复制代码
srv/user/main.go 目录下的user 服务是一个完整的使用实例。
为micro网关增加opentracing插件
实现原理
外部HTTP请求首先经过API网关,网关生成第一个SpanContexts并且通过HTTP头传递到聚合层的API服务,这边需要我们实现一个插件去做这件事,原理很简单,拦截每一次请求添加信息就可以了。
查看micro自带的opentracing插件,可以发现是通过golang的context传递,micro的RPC已经封装好了通过context在跨进程服务间传递SpanContexts机制,所以我们需要在API服务层实现一个插件,从HTTP头中取出SpanContexts并按照micro自带的方式注入golang context。
// micro opentracing插件中wHandlerWrappe
// NewHandlerWrapper accepts an opentracing Tracer and returns a Handler Wrapper
func NewHandlerWrapper(ot opentracing.Tracer) server.HandlerWrapper {
return func(h server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
name := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
ctx, span, err := traceIntoContext(ctx, ot, name)
if err != nil {
return err
}
defer span.Finish()
return h(ctx, req, rsp)
}
}
}
复制代码
micro API网关插件
lib/wrapper/tracer/opentracing/stdhttp/stdhttp.go
和实现JWT鉴权插件一样,实现一个HTTP中间件通过mciro的插件机制全局注册就可以实现拦截每次请求并处理。
// TracerWrapper tracer wrapper
func TracerWrapper(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
spanCtx, _ := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(r.Header))
sp := opentracing.GlobalTracer().StartSpan(r.URL.Path, opentracing.ChildOf(spanCtx))
defer sp.Finish()
if err := opentracing.GlobalTracer().Inject(
sp.Context(),
opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(r.Header)); err != nil {
log.Println(err)
}
sct := &status_code.StatusCodeTracker{ResponseWriter: w, Status: http.StatusOK}
h.ServeHTTP(sct.WrappedResponseWriter(), r)
ext.HTTPMethod.Set(sp, r.Method)
ext.HTTPUrl.Set(sp, r.URL.EscapedPath())
ext.HTTPStatusCode.Set(sp, uint16(sct.Status))
if sct.Status >= http.StatusInternalServerError {
ext.Error.Set(sp, true)
}
})
}
复制代码Tracer相关的概念可以查看这个文档
opentracing.GlobalTracer().Extract 方法提取HTTP头中的spanContexts
opentracing.ChildOf 方法基于提取出来的spanContexts生成新的child spanContexts
opentracing.GlobalTracer().StartSpan 方法生成一个新的span
github.com/opentracing/opentracing-go/ext 通过ext可以为追踪添加一些tag来展示更多信息,比如URL,请求类型(GET,POST...), 返回码
sp.Finish() 结束这一个span
API服务(使用gin)插件
lib/wrapper/tracer/opentracing/gin2micro/gin2micro.go
// TracerWrapper tracer 中间件
func TracerWrapper(c *gin.Context) {
md := make(map[string]string)
spanCtx, _ := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(c.Request.Header))
sp := opentracing.GlobalTracer().StartSpan(c.Request.URL.Path, opentracing.ChildOf(spanCtx))
defer sp.Finish()
if err := opentracing.GlobalTracer().Inject(sp.Context(),
opentracing.TextMap,
opentracing.TextMapCarrier(md)); err != nil {
log.Log(err)
}
ctx := context.TODO()
ctx = opentracing.ContextWithSpan(ctx, sp)
ctx = metadata.NewContext(ctx, md)
c.Set(contextTracerKey, ctx)
c.Next()
statusCode := c.Writer.Status()
ext.HTTPStatusCode.Set(sp, uint16(statusCode))
ext.HTTPMethod.Set(sp, c.Request.Method)
ext.HTTPUrl.Set(sp, c.Request.URL.EscapedPath())
if statusCode >= http.StatusInternalServerError {
ext.Error.Set(sp, true)
}
}
// ContextWithSpan 返回context
func ContextWithSpan(c *gin.Context) (ctx context.Context, ok bool) {
v, exist := c.Get(contextTracerKey)
if exist == false {
ok = false
return
}
ctx, ok = v.(context.Context)
return
}
复制代码
基本操作流程和给micro编写的插件相同,但是有两点不同。其一,因为我使用gin开发API服务,所以基于gin的API。其二,因为micro内部提供通过golang context传递spanContexts的机制,所以将这边会将child spanContexts注入到gin 的context,在API服务通过micro提供RPC接口(生成的XX.micro.go文件中调用函数第一个参数都是context)调用其他服务时传入提取的context,如下:
...
ctx, ok := gin2micro.ContextWithSpan(c)
if ok == false {
log.Log("get context err")
}
res, err := s.helloC.Call(ctx, &helloS.Request{Name: "xuxu"})
...
复制代码
完整的实现细节可以查看,github仓库中 lib/wrapper/tracer/opentracing, 这里。
完整体验
项目完整代码地址
go 链路追踪_【go-micro实践】jaeger分布式链路追踪相关推荐
- jaeger分布式链路追踪
推荐去官网系统的了解一下 https://www.jaegertracing.io 随着应用容器化和微服务的兴起,借由Docker和 Kubernetes 等工具, 服务的快速开发和部署成为可能,构建 ...
- java全链路监控_使用SkyWalking+elasticsearch实现全链路监控
面对以上情况, 我们就需要一些可以帮助理解系统行为.用于分析性能问题的工具,以便发生故障的时候,能够快速定位和解决问题.这时候分布式追踪系统就该闪亮登场了. 一.分布式追踪系统skywalking 1 ...
- od 追踪_裁判员行为规范【基本功】——追踪裁判违例宣判练习 /五秒违例
当打出一个违例手势后,固定它,并在你的脑海里默念一两秒.要求有力,干脆,清晰和果断的手势. 手势程序:⑴停表手势,(2)取消得分手势 / 口语并用 / 如需要),⑶对应的违例手势 / 口语并用,⑷比赛 ...
- 儿童手表运动轨迹和路径追踪_如何将智能手表或健身追踪器用作静音闹钟
儿童手表运动轨迹和路径追踪 When you need to wake up without disturbing everyone around you a silent vibration-bas ...
- od 追踪_裁判员行为规范【基本功】——追踪裁判违例宣判练习 / 脚踢球违例
当打出一个违例手势后,固定它,并在你的脑海里默念一两秒.要求有力,干脆,清晰和果断的手势. 手势程序:⑴停表手势,(2)取消得分手势 / 口语并用 / 如需要),⑶对应的违例手势 / 口语并用,⑷比赛 ...
- od 追踪_裁判员行为规范【基本功】——追踪裁判违例宣判练习 / 带球走违例
当打出一个违例手势后,固定它,并在你的脑海里默念一两秒.要求有力,干脆,清晰和果断的手势. 手势程序:⑴停表手势,(2)取消得分手势 / 口语并用 / 如需要),⑶对应的违例手势 / 口语并用,⑷比赛 ...
- od 追踪_裁判员行为规范【基本功】——追踪裁判违例宣判练习 / 两次运球违例...
当打出一个违例手势后,固定它,并在你的脑海里默念一两秒.要求有力,干脆,清晰和果断的手势. 手势程序:⑴停表手势,(2)取消得分手势 / 口语并用 / 如需要),⑶对应的违例手势 / 口语并用,⑷比赛 ...
- Pinpoint详解(分布式链路追踪、链路监控)
英文原文:https://naver.github.io/pinpoint/1.8.4/techdetail.html 说明:[]中内容为方便解释自己加的 在这篇文章中,我们描述了Pinpoint的技 ...
- 分布式服务追踪与调用链系统
如何构建新一代SkyWalking服务追踪框架 1.生产环境调用接口报错了,如何定位? 2.微服务服务追踪框架构设计原理 3.Sleuth+zipkin实现分布式服务追踪 4.SkyWalking超强 ...
最新文章
- 【CV】使用Keras和迁移学习从人脸图像中预测体重指数BMI
- oracle查询 :一个角色包括的系统权限,对象权限,Oracle有多少种角色,某个用户有什么角色
- Linux命令工作中常用的总结
- fat32 linux 打包工具_一个方便的用于创建树莓派 SD 卡镜像的程序 | Linux 中国
- SVN:show log问题
- python wordcloud下载_Python数据可视化之Wordcloud
- 地图结合资料 提供全新网络服务
- 通过OpenSSL创建自签名证书在Flask实现HTTPS
- 有点理解Google为什么要退出中国市场了
- Ctrl+Shift+F 输入法变成繁体 输入法简体繁体切换
- 帆软折线图设置红色警戒线
- linux搭建http代理服务器
- 如何将一个div水平垂直居中?6种方法做推荐
- 在传统软件公司十年深恶痛绝的感受
- 一名合格的Java后端工程师或架构师必须要掌握 Spring Framework、Spring Boot、Spring Cloud
- 天梯赛:L2-016 愿天下有情人都是失散多年的兄妹 (25 分)
- 自定义view实现涂鸦(画板)功能
- 域控服务器的dns配置,如何配置额外域控制器上的DNS?
- Zotero(1)---文献管理软件Zotero安装教程
- 亿级用户体量,千万级日活用户,《王者荣耀》高并发背后的故事!
热门文章
- 博客搭建攻略(三):创造收益
- ajax为什么会全局刷新,为什么发送ajax请求页面也会刷新呢?
- TP-GAN 侧脸修复
- libxml/xmlversion.h: No such file or directory
- Python 进程之间共享数据(全局变量)
- python与caffe改变通道顺序
- python 逻辑回归
- dw读取access中的图片_怎样从Access数据库中读取图片?解决办法
- maven java 可执行jar_Maven项目打包成可执行Jar文件
- html 字号自适应,自适应网页中字体大小自适应屏幕 - YangJunwei