Jaeger插件开发及背后的思考

本文涉及的产品
对象存储 OSS,20GB 3个月
文件存储 NAS,50GB 3个月
对象存储 OSS,内容安全 1000次 1年
简介: 本文主要介绍Jaeger最新的插件化后端的接口以及开发方法,让大家能够一步步的根据文章完成一个Jaeger插件的开发。此外SLS也推出了对于Jaeger的支持,欢迎大家试用。

随着云原生 + 微服务的推广和落地,服务监控也变得越来越重要了。中等规模的微服务场景下,运维同学已经无法通过日志还原请求的调用轨迹和请求所经过服务的执行耗时,更不用说去定位和分析服务异常根因,研发运维同学需要一个服务监控工具,它可以还原每次请求的服务调用轨迹以及服务执行时间,并以图的形式展现出来。分布式链路追踪系统孕育而生。


近些年市面上有大量优秀的商业产品,这些商业产品通常也叫APM(应用性能监控);比如国内商业公司有阿里云ARMS,听云,博瑞,云智慧等等,国外优秀的商业公司有AppDynamic,DynaTrace等等,它们在产品方面做非常完善,能够适配各种场景。同样地,开源也有非常优秀的解决方案。比如说 CNCF Jaeger,Apache SkyWalking,Cat, Pinpoint等。Jaeger作为CNCF毕业的顶级项目, 在云原生场景下,通常会成为运维同学首选监控解决方案。


Jaeger项目是Uber 2015 年开发的。2017 年,Jaeger 纳入云原生计算基金会(CNCF)的孵化项目,2019 年,Jaeger 正式毕业。下图是Jaeger架构图。图中包含两中架构模式,两种架构上大体一样,区别在于添加了Kafka作为缓冲,以解决峰值流量过载的问题。Jaeger Jaeger组件包括 :Client,Agent,Collector,DB,UI等组件,另外Jaeger支持还多种后端存储,其中包括:内存,Badger,Cassandra,ElasticSearch,gRPC插件。


今天我们就来说一说gRPC插件,这个强大且容易被人遗忘的功能。简单点来说,gRPC插件提供了一种能够将Trace数据从Jaeger系统中导出的能力。通过这个能力,开发同学可以很轻松的将Trace对接到一个具备Trace存储和分析的后端服务,这些服务可以对Trace进行二次分析加工,比如说异常根因分析,异常检测和告警等,帮助运维和开发同学更好的发现和定位系统潜在的问题

jaeger插件开发流程

为了更好的了解jaeger插件开发,需要先补充gRPC插件的底层实现原理,Jaeger gRPC插件是使用HashiCorp/go-plugin框架实现的。接下我们将介绍Go Plugin以及插件的开发流程。


Go Plugin由HashiCorp公司开源,它遵循设计模式中的开闭原则,通过接口固定上层业务逻辑,通过改变调用不同的RPC服务接口来改实现对业务的扩展。 目前Go Plugin包含两类插件:RPC Plugin和 GRPCPlugin,两类插件Client的底层调用不一样。一个通过net/rpc调用,一个是grpc服务调用,两个插件都提供了两个方法,Server和Client方法。Service方法的完成的功能是充当服务端的stub,服务端接受到请求后,调用接口服务端接口的实现。Client方法充当了一个工厂方法,为客户端生成接口的实现对象。

Go Plugin在启动过程中会启动一个子进程,让子进程开启RPC/gRPC服务,主进程直接通过RPC/gRPC接口达到插件的方式,它支持多版本服务(后面会讲到)并存,它本身并不提供服务的高可用相关的解决方案,这块需要用户自己去提供。讲了这么多,接下来简单的介绍Go Plugin的开发的过程

插件开发

下面介绍Go Plugin中的Example下的KV例子,KV例子定义了两个方法,Put和 Get方法,KV例子包含多个协议版本,本文以gRPC为例。

定义服务接口

typeKVinterface {
// KV接口是KV插件定义的接口Put(keystring, value []byte) errorGet(keystring) ([]byte, error)
}


实现接口客户端

// KV接口客户端实现,typeGRPCClientstruct{ 
// 接口的客户端封装了gRPC服务clientproto.KVClient}
func (m*GRPCClient) Put(keystring, value []byte) error {
// 调用gRPC服务接口_, err :=m.client.Put(context.Background(), &proto.PutRequest{
...    })
returnerr}
func (m*GRPCClient) Get(keystring) ([]byte, error) {
// 本身调用KV的gRPC服务resp, err :=m.client.Get(context.Background(), &proto.GetRequest{
...    })
....returnresp.Value, nil


实现接口服务端

typeGRPCServerstruct {
ImplKV}
// 实现KV gRPC服务func (m*GRPCServer) Put(ctxcontext.Context,req*proto.PutRequest) (*proto.Empty, error) {
// 接受到请求后,便会调用接口的服务端实现return&proto.Empty{}, m.Impl.Put(req.Key, req.Value)
}
func (m*GRPCServer) Get(ctxcontext.Context, req*proto.GetRequest) (*proto.GetResponse, error) {
// 接受到请求后,便会调用接口的服务端实现v, err :=m.Impl.Get(req.Key)
return&proto.GetResponse{Value: v}, err}
typeKVstruct{}
func (KV) Put(keystring, value []byte) error {
// 具体业务实现}
func (KV) Get(keystring) ([]byte, error) {
// 具体业务实现}


实现go plugin插件接口

// 实现GrpcPlugin接口typeKVGRPCPluginstruct {
plugin.PluginImplKV//KV接口的实现, }
func (pKVGRPCPlugin) GRPCClient(ctxcontext.Context, brokerplugin.GRPCBroker, c*grpc.ClientConn) (interface{}, error) {
// 注意返回为接口客户端实现return&GRPCClient{client: proto.NewKVClient(c)}, nil}
func (pKVGRPCPlugin) GRPCServer(brokerplugin.GRPCBroker, s*grpc.Server) error {
// 注册gRpc服务proto.RegisterKVServer(s, &GRPCServer{Impl: p.Impl})
returnnil}


插件使用

上面介绍了插件的开发,这部分将介绍插件是如何使用的,插件使用分为两个部分,插件服务端和插件的客户端部分


插件服务端

上面部分提到,go plugin启动时会启动在本地一个子进程,这里的子进程指的就是插件的服务端,插件服务端需要是一个包含main方法的可执行文件。下面介绍开始简单介绍插件服务端使用

  1. 编写一个main函数,并将插件的客户端实现注册到go-plugin中,如下:
plugin.Serve(&plugin.ServeConfig{
// shakeConfig包含查件版本和认证信息HandshakeConfig: shared.Handshake,
Plugins: map[string]plugin.Plugin{
// 插件名字"kv_grpc": &shared.KVGRPCPlugin{Impl: &KV{}},
    },
GRPCServer: plugin.DefaultGRPCServer,
})
  1. 使用go build 编译成可执行文件


插件客户端

插件客户端流程主要包括,创建插件的Client,启动插件服务端,获取插件的接口实现,调用服务接口

client :=plugin.NewClient(&plugin.ClientConfig{
// shakeConfig包含查件版本和认证信息HandshakeConfig: shared.Handshake,
//插件名字和插件的实例的映射关系Plugins:         shared.PluginMap,
// 这里填写插件可执行文件的路径Cmd:             exec.Command("sh", "-c", os.Getenv("KV_PLUGIN")),
// 插件支持的协议。AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC, plugin.ProtocolNetRPC},
})// 获取插件的client端,在这步,go plugin通过Cmd穿过来的参数启动子进程,同时做插件版本和认证信息的校验rpcClient, err :=client.Client()
// 获取接口客户端的对象raw, err :=rpcClient.Dispense("kv_grpc")
kv :=raw.(shared.KV)
// 执行命令result, err :=kv.Get(os.Args[1])


jaeger插件接口规范

通过上面的介绍,我们已经可以了解到,Jaeger已经帮我们实现了插件的客户端&服务端和接口的客户端,我们只需完成接口的服务端开发,一个gRPC插件的开发完成了。Jaeger在gRPC插件预留了2个插件接口,StorePlugin和ArchiveStorePlugin,两者区别在于StorePlugin比ArchiveStorePlugin多了DependencyReader接口的定义,DependencyReader接口用来查询服务间依赖关系。同时这两个插件接口都暴露了SpanReader和SpanWriter接口,用于Trace/Span的读写操作。

SpanReader

// 读取所有的operation NamefuncGetOperations(ctxcontext.Context, queryspanstore.OperationQueryParameters) ([]spanstore.Operation, error)
// 读取所有的应用名称funcGetServices(ctxcontext.Context) ([]string, error) 
// 通过符合条件的TracefuncFindTraces(ctxcontext.Context, query*spanstore.TraceQueryParameters) ([]*model.Trace, error) 
// 通过符合条件的Trace IDfuncFindTraceIDs(ctxcontext.Context, query*spanstore.TraceQueryParameters) ([]model.TraceID, error) 
// 通过Trace ID获取具体Trace详情funcGetTrace(ctxcontext.Context, traceIDmodel.TraceID) (*model.Trace, error)

SpanWriter

// 写入TracefuncWriteSpan(ctxcontext.Context, span*model.Span) error

DependencyReader

// 读取应用之间的依赖关系,用于绘应用拓扑图和DAG图funcGetDependencies(ctxcontext.Context, endTstime.Time, lookbacktime.Duration) ([]model.DependencyLink, error)

开发SLS Jaeger插件


SLS现已推出分布式链路追踪(Trace)的统一存储和分析方案,目前支持接入Jaeger,Apache SkyWalking,OpenTelemetry,Zipkin等多种追踪数据接入。感兴趣的可以点击查看Demo

SLS的Jaeger插件里的代码逻辑这里就不赘述。目前插件代码现在已经开源,GitHub地址:https://github.com/aliyun/aliyun-log-jaeger 欢迎大家加⭐️拍砖,仓库也提供了一个一键Run的Demo示例,欢迎使用,使用方面的文档已经在Github上提供,下面给大家演示一下效果以及开发Jaeger插件开发背后的意义。



插件背后的思考

整个插件至此开发完成,同时,我们也需要思考一下插件的背后给我们带来了什么。用户利用trace所带来的信息价值,Trace数据采集上来仅仅只是系统监控的开始,挖掘Trace隐藏的信息是构建监控系统最重要的能力。同样的,再利用Trace所带来的的信息价值同时,如何持续地保障这种能力也是我们思考的重心


“海恩法则”指出:每一起严重事故的背后,必然有29次轻微事故和300起未遂先兆以及1000起事故隐患。 “海恩法则”告诉我们这样一个道理:每一起安全事故的背后看似偶然,其实都是各种因素积累到一定程度的必然结果, 业务系统每天都再生产大量的Trace数据,这些Trace数据用人的肉眼是无法了解系统运行的状态的信息,更别去发现系统一些隐藏起来的问题。这时就需要系统提供大数据场景下的分析的能力。SLS做日志起家,每天处理数PB级别的日志量,另外也提供一堆的日志分析的算子,加工处理的工具,为用户分析系统背后的故事。Trace我们可以理解为是一种特定的日志,只是这个日志带了关联的上下文(TraceID,parentSpanID,SpanID),相信SLS在处理Trace日志的也会游刃有余,


作为Jaeger作为一个可观察性/监控系统的组成部分,是定位和发现业务系统问题的重要数据来源,我们需要保证监控系统比业务系统活的更久。一旦监控系统先于业务系统down掉,此时的监控可以说是完全没有意义。而Jaeger作为一个开源项目,它本身只提供解决方案,并不会提供部署规模的评估方案和服务如何保证高可用的方案,这种情况下怎么去提供高可用和高性能的后端服务?谁去为监控系统提供最后一层保障? SLS作为一个云服务,其最大的一个特点就是高性能、弹性和免运维,让用户轻松应对激增流量或者规模评估不准确的问题,SLS服务本身提供99.9%的可用性以及11个9的数据可靠性。

总结

构建完备的监控体系体系,不仅要保证监控系统的可用性,还需要强大的分析能力。分析能力帮助运维同学快速的定位和发现故障,提高系统的可用性。而Jaeger插件为我们提供接入多种分析系统的扩展能力,这样的扩展能力能够让专业的分析团队提供专业的分析能力,让运维和开发团队的更加专注业务运维。


参考

  1. https://github.com/jaegertracing/jaeger/issues/422
  2. https://www.jaegertracing.io/docs/1.24/architecture/
  3. https://github.com/hashicorp/go-plugin

进一步参考

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
6月前
|
存储 数据采集 监控
SkyWalking全景解析:从原理到实现的分布式追踪之旅
SkyWalking全景解析:从原理到实现的分布式追踪之旅
1221 1
|
1月前
|
存储 前端开发 安全
Tauri 开发实践 — Tauri 原生能力
本文介绍了如何使用 Tauri 框架构建桌面应用,并详细解释了 Tauri 提供的原生能力,包括文件系统访问、系统托盘、本地消息通知等。文章通过一个具体的文件下载示例展示了如何配置 Tauri 来使用文件系统相关的原生能力,并提供了完整的代码实现。最后,文章还提供了 Github 源码链接,方便读者进一步学习和参考。
72 1
Tauri 开发实践 — Tauri 原生能力
|
存储 Prometheus Kubernetes
OpenTelemetry 简析
OpenTelemetry 是 CNCF 的一个可观测性项目,旨在提供可观测性领域的标准化方案,解决观测数据的数据模型、采集、处理、导出等的标准化问题,提供与三方 vendor 无关的服务。 2021.02.10,OpenTelemetry 的 tracing spec 达到 1.0 版本 (link),基于这个里程碑,笔者对 OpenTelemetry 进行了探索,判断在可观测性领域带来的价值和发展前景。 下面给出笔者对 OpenTelemetry 的理解,抛砖引玉。由于笔者能力有限,理解不当的地方请大家指正。
OpenTelemetry 简析
|
1月前
|
开发工具 Android开发
【Wing】背后的插件们
【Wing】背后的插件们
|
6月前
|
Dart Java Android开发
Flutter插件开发:开发与使用的技术解析
【4月更文挑战第26天】本文详细介绍了Flutter插件开发,包括创建插件项目、编写原生代码(Android和iOS)、注册与使用插件。通过Flutter命令行工具生成插件,使用MethodChannel进行Dart与原生平台的通信。示例展示了如何获取设备信息并展示在Flutter应用中。文章还提到插件测试与发布,强调了兼容性与性能的重要性,指出Flutter插件是扩展应用功能的关键。
|
6月前
|
机器学习/深度学习 运维 监控
有人想让我讲讲应用性能管理(APM)工具
有人想让我讲讲应用性能管理(APM)工具
357 2
|
前端开发 Cloud Native JavaScript
《深入分布式追踪:OpenTracing 实践手册》
《深入分布式追踪:OpenTracing 实践手册》
207 0
|
存储 JavaScript 数据可视化
大型网站重构指南 第1.2部分:Nodejs 系统可观测性 OpenTelemetry+SigNoz
大型网站重构指南 第1.2部分:Nodejs 系统可观测性 OpenTelemetry+SigNoz
738 0
大型网站重构指南 第1.2部分:Nodejs 系统可观测性 OpenTelemetry+SigNoz
|
存储 监控 前端开发
APM开源方案-SigNoz初体验
最近在调研APM相关的开源方案,发现ATA上这类的文章比较少,准备搞一系列APM的“初体验”文章,那么先从最近github势头较热的SigNoz开始SigNoz简介SigNoz是一套开源APM方案,用于监控应用指标和链路,可以看到调用情况、异常、trace上下链路,也可以自己定义Dashboard。官方对于SigNoz介绍很全面了,不赘述啦。值得注意的是,SigNoz支持OpenTelemetry
6388 2
APM开源方案-SigNoz初体验
|
监控 JavaScript Dubbo
pinpoint插件开发实践
Pinpoint是一款全链路分析工具,提供了无侵入式的调用链监控、方法执行详情查看、应用状态信息监控等功能。基于Google Dapper论文进行的实现。
5782 0