Go2sky -- Golang用skywalking实现全链路追踪
一、背景介绍
由于在微服务架构中,服务之间的调用关系多而复杂,所以有必要对它们之间的调用链路进行追踪、分析,判断是哪里出了问题,或者哪里耗时过多。
最近接到了这个需求,添加全链路追踪,所以研究并实践了一下,还不太深刻,若有错误的地方欢迎指正。
二、OpenTracing相关概念介绍
首先,要实现全链路追踪,必须先理解OpenTracing的一些基本概念。OpenTracing为分布式链路追踪制定了一个统一的标准。只要是按照此标准实现的服务,就能够完整的进行分布式追踪。
1. Span
Span可以被翻译为跨度,可以理解为一次方法调用,一个程序块的调用,或者一次RPC/数据库访问。
Span之间是有关系的,child of 和 follow of。比如一次RPC的调用,RPC客户端和服务端的span就形成了父子关系。
2. Trace
Trace表示一个调用链,比如在分布式服务中,一个客户端的请求,在后台可能经过了层层的调用,那么每一次调用就相当于一个span,而这一整条调用链路,可以理解成一个trace。
Trace有一个全局唯一的ID。
三、Go2sky简介
Go2sky是Golang提供给开发者实现SkyWalking agent探针的包,可以通过它来实现向SkyWalking Collector上报数据。
快速入门:GitHub-Go2Sky
1. 创建Reporter、Tracer
SkyWalking支持http和gRpc两种方式收集数据,在Go2sky中,想要上报数据,先创建一个GRPCReporter.
Tracer代表了本程序中的一条调用链路。
本程序中的所有span都会与服务名为example的服务相关联。
2. 创建Span
Span有三种类型:LocalSpan、EntrySpan、ExitSpan。
LocalSpan:可以用来表示本程序内的一次调用。
EntrySpan:用来从下游服务提取context信息。
ExitSpan: 用来向上游服务注入context信息。
在创建span时,上下文参数传入context.Backround() ,就表示它是root span。
3. 创建sub span
在创建LocalSpan和EntrySpan的时候,返回值会返回一个context信息(ctx),通过它来创建sub span,来与root span形成父子关系。
4. End Span
必须要确保结束span,它们才可以被上传给skywalking。
5. 关联Span
我们在程序中创建的span,是怎么关联起来形成一个调用链的呢。
在同一个程序中,向上面那样,创建root span 和 sub span即可。
在不同的程序中,下游服务使用ExitSpan向上游注入context信息,上游服务使用EntrySpan从下游提取context信息。Entry和Exit使得skywalking可以分析,从而生成拓扑图和度量指标。
四、实战 -- 跨程序追踪RPC调用
看到这里,有了基本的概念,以及Go2sky的基本用法,但是仍然不能够对RPC进行有效的追踪。
因为上图中的例子使用的是http请求,它本身就封装了Get和Set方法,可以很轻松的注入和提取context信息。但是RPC请求并没有,想要追踪别的类型跨程序的调用也没有。
所以我们要自己将context信息在进行调用的时候,从下游服务传给上游服务,然后自己定义注入和提取的方法。
下面只贴出了链路追踪部分的代码,其它的比如rpc相关的部分代码省略了(不然又臭又长,还难看)。
1. Client端 (下游服务)
定义请求信息的结构体:
type Req struct {A intHeader string // 添加此字段,用于传递context信息
}
定义context信息的注入方法:
func (p *Req) Set(key, value string) error {p.Header = fmt.Sprintf("%s:%s", key, value)return nil
}
创建reporter和tracer:
r, err = reporter.NewGRPCReporter("192.168.204.130:11800")
if err != nil {logs.Info("[New GRPC Reporter Error]: [%v]", err)return
}// 这个程序中所有的span都会跟服务名叫RTS_Test的服务关联起来
tracer, err = go2sky.NewTracer("RTS_Test", go2sky.WithReporter(r), go2sky.WithInstance("RTS_Test_1"))
if err != nil {logs.Info("[New Tracer Error]: [%v]", err)return
}
tracer.WaitUntilRegister()
rpc调用以及创建span:
在创建ExitSpan的时候,传入了一个函数,函数实现就是我们定义的如何注入context信息的函数。
它会在CreateExitSpan()函数的内部被调用,header的值不需要我们管,它在CreateExitSpan函数内部生成的。我们只需要负责在上游服务中把它提取出来即可。
我目前的理解是,只需要在下游服务中负责把这个header按一定规则拼接,传给上游服务,然后在上游服务中按照规则将header解析出来,skywalking通过分析,即可将上下游的span关联起来。
func OnSnapshot() {// client := GetClinet()// 表示收到客户端请求,因为只追踪后台服务之间的链路,所以这里不需要提取context信息span2, ctx, err := tracer.CreateEntrySpan(context.Background(), "/API/Snapshot", func() (string, error){return "", nil})if err != nil {logs.Info("[Create Exit Span Error]: [%v]", err)return}span2.SetComponent(5200)// 表示rpc调用的span,这里需要向上游服务注入context信息,即参数中的headerreq := Req{3, ""}span1, err := tracer.CreateExitSpan(ctx, "/Service/OnSnapshot", "RTS_Server", func(header string) error{return req.Set(propagation.Header, header)})if err != nil {logs.Info("[Create Exit Span Error]: [%v]", err)return}span1.SetComponent(5200) // Golang程序使用范围是[5000, 6000),还要在skywalking中配置,config目录下的component-libraries.yml文件var res Res// rpc调用err = conn.Call("Req.Snapshot", req, &res)if err != nil {logs.Info("[RPC Call Snapshot Error]: [%v]", err)return} else {logs.Info("[RPC Call Snapshot Success]: [%s]", res)}span1.End()span2.End() // 一定要确保span被结束// s1 := ReportedSpan(span1)// s2 := ReportedSpan(span2)// spans := []go2sky.ReportedSpan{s1, s2}// r.Send(spans)
}
2. Server端 (上游服务)
定义请求信息的结构体:
type ReqBody struct {A intHeader string
}
定义context信息的提取方法:
func (p *ReqBody) Get(key string) string {subs := strings.Split(p.Header, ":")if len(subs) != 2 || subs[0] != key {return ""}return subs[1]
}
创建reporter和tracer:
r, err = reporter.NewGRPCReporter("192.168.204.130:11800")
if err != nil {logs.Info("[New GRPC Reporter Error]: [%v]\n", err)return
}tracer, err = go2sky.NewTracer("Service_Test", go2sky.WithReporter(r), go2sky.WithInstance("Service_Test_1"))
if err != nil {logs.Info("[New Tracer Error]: [%v]\n", err)return
}
tracer.WaitUntilRegister()
创建span:
在创建EntrySpan时,调用Get()方法提取context信息
func (p *Req)Snapshot(req ReqBody, res *Res) error {// 表示收到 rpc 客户端的请求,这里需要提取context信息span1, ctx, err := tracer.CreateEntrySpan(context.Background(), "/Service/OnSnapshot/QueringSnapshot", func() (string, error){return req.Get(propagation.Header), nil})if err != nil {logs.Info("[Create Exit Span Error]: [%v]\n", err)return err}span1.SetComponent(5200)// span1.SetPeer("Service_Test")// 表示去请求了一次数据库span2, err := tracer.CreateExitSpan(ctx, "/database/QuerySnapshot", "APIService", func(header string) error {return nil})span2.SetComponent(5200)time.Sleep(time.Millisecond * 6)*res = "Return Snapshot Info"span2.End()span1.End()// s1 := ReportedSpan(span1)// s2 := ReportedSpan(span2)// spans := []go2sky.ReportedSpan{s1, s2}// r.Send(spans)return nil
}
3. 结果展示
链路追踪:
拓扑图:
Go2sky -- Golang用skywalking实现全链路追踪相关推荐
- Springcloud 集成 Skywalking 实现全链路追踪
下载链接 https://skywalking.apache.org/downloads/ 本地搭建springcloud工程,偷懒可参考gitee https://gitee.com/wangLi1 ...
- skywalking 安装_SkyWalking全链路追踪利器
随着目前系统架构的复杂度越来越高(中台.微服务),并且线上应用的多级监控覆盖到了通讯.应用处理过程监控并且实现端到端的应用监测,线上性能故障的快速定位修复:而传统的监控分析方式已经无法满足我们的需求, ...
- skywalking与pinpoint全链路追踪方案对比
由于公司目前有200多微服务,微服务之间的调用关系错综复杂,调用关系人工维护基本不可能实现,需要调研一套全链路追踪方案,初步调研之后选取了skywalking和pinpoint进行对比; 选取skyw ...
- Skywalking全链路追踪使用说明
1.背景与需求: 随着业务规模的不断增大,系统的复杂度也越来越高,我们的软件架构也进入了分布式的阶段,服务按照不同的维度进行拆分,那么一次请求可能横跨多个服务模块.项目,依赖的中间件也越来越多,其中任 ...
- 使用Skywalking实现全链路监控
https://opentalk.upyun.com/334.html 2017 年 10 月 29 日,又拍云 Open Talk 联合 Spring Cloud 中国社区成功举办了"进击 ...
- go 链路追踪_Golang在七牛全链路追踪中的实践
1.Go在七⽜牛全链路路追踪中的实践 刘凯 七⽜牛云⼤大数据团队(Pandora)架构师 2.⾃自我介绍 INTRODUCTION • 刘凯,七⽜牛,⼤大数据Pandora团队成员 • 2015年年, ...
- 基于 SkyWalking 实现服务链路追踪
https://blog.51cto.com/zero01/2463116 https://skywalking.apache.org/zh/blog/2019-03-29-introduction- ...
- 使用 Skywalking 实现全链路监控
2017 年 10 月 29 日,又拍云 Open Talk 联合 Spring Cloud 中国社区成功举办了"进击的微服务实战派北京站".华为技术专家吴晟作了题为<使用 ...
- 前后端、多语言、跨云部署,全链路追踪到底有多难?
作者|涯海 全链路追踪的价值 链路追踪的价值在于"关联",终端用户.后端应用.云端组件(数据库.消息等)共同构成了链路追踪的轨迹拓扑大图.这张拓扑覆盖的范围越广,链路追踪能够发挥的 ...
- mysql链路跟踪工具_SkyWalking全链路追踪利器
随着目前系统架构的复杂度越来越高(中台.微服务),并且线上应用的多级监控覆盖到了通讯.应用处理过程监控并且实现端到端的应用监测,线上性能故障的快速定位修复:而传统的监控分析方式已经无法满足我们的需求, ...
最新文章
- Win7 wifi热点设置( 转载)
- ngx_lua中的协程调度(三)
- Akka并发编程——第二节:Actor模型(一)
- 计蒜客 A2232.程序设计:蒜厂年会-单调队列(双端队列(STL deque)实现)滑窗维护最小前缀和...
- Linux内核升级,从2.6.18升级到3.2.14
- Android 透明动画实现 详细概述
- 模拟image的ajaxPrefilter与ajaxTransport处理
- 远程注入利用远程线程直接注入
- WINDOWSXP全面优化
- Proteus、Keli对C51芯片实现仿真流水灯
- TPU原理技术与xPU
- VS2019创建COM组件
- 点击编辑按钮,前端table表格行内指定td可修改。(table是动态生成的)
- 你属于哪种性感女人?
- IDEA工具避坑指南(七):git@github.com: Permission denied|You must supply a key in OpenSSH public key format详解
- 『矩阵论笔记』详解最小二乘法(矩阵形式求导)+Python实战
- 华硕VIVO BOOK15s啃苹果之路
- GNU Radio入门之旅
- 给超链接加个手指的图标
- web渗透_一句话木马(webshell)_dvwa环境
热门文章
- Js 把html字符串显示,js Html结构转字符串形式显示代码
- 阿尔伯塔大学计算机科学是哪个校区,阿尔伯塔大学优势专业是什么?
- 基于RWEQ模型的土壤风蚀模数估算及其变化归因分析、RWEQ模型相关的SCI论文撰写技巧
- java处理图片的所有类_Java的图片处理工具类
- 游戏源代码是什么意思_什么是游戏
- 光耦p621引脚图_p421光耦引脚图和代换
- mybaties中resultMap和resultType的区别
- 新手学Unity3d的一些网站及相应学习路线
- 魔百和CM311-1a YST免拆机卡刷精简固件
- css中标准盒模型和怪异盒模型的区别,如何将标准盒模型转换为怪异盒模型