吉安市建设局图审中心网站,微信网站与响应式网站,wordpress缩略图只生成full,淘宝客网站主咱们以前单体应用里面有很多的应用和功能#xff0c;依赖各个功能之间相互调用#xff0c;使用公共的代码包等等#xff0c;排查问题#xff0c;使用类似于 gdb/dlv 工具或者直接查看代码日志#xff0c;进行定位和分析
但是现在我们基本上都是微服务架构了#xff0c;将…咱们以前单体应用里面有很多的应用和功能依赖各个功能之间相互调用使用公共的代码包等等排查问题使用类似于 gdb/dlv 工具或者直接查看代码日志进行定位和分析
但是现在我们基本上都是微服务架构了将以前的单体架构拆成了一个个独立的微服务现在就变成了多个微服务之间的相互调用的关系
在一个业务链条中中间可能涉及到几个十几个甚至几十个微服务的交互和配合如果中间某一环出现了问题那么我们是很难排查的排查问题耗时耗力且效率极其低下
服务数量多链路复杂排查困难大佬们就想出了一个办法使用分布式链路追踪来处理这个问题
本文分别从以下几个方面来聊聊关于分布式链路追踪的技术知识
什么是分布式链路追踪 分布式链路追踪的基础原理 目前常用的分布式链路追踪组件 Jaeger 的基本架构和使用演示
✔什么是分布式链路追踪
分布式链路追踪见名知意这是用在分布式系统中用于追踪服务调用链路的
文章开头有说到微服务架构中存在大量的微服务且维护的团队不尽相同使用的语言也不太一致
线上部署几百上千台服务器若链路出现了问题性能出现了瓶颈我们如何排查 如何有效的解决呢
分布式链路追踪他就可以将一次分布式请求还原成调用链路将一次分布式请求的调用状况集中展示且他还提供友好的 UI 界面咱们直接在页面上就能直观的看到每一个服务的耗时请求到具体哪台服务器上以及服务相应的状态等等。
在技术上通常使用
Tracing 表示链路追踪
主要是用于单个请求的处理流程包括服务调用和服务处理时长等信息
目前分布式上使用的比较多的是 Jaeger
Logging 日志记录
主要是用来记录离散的日志事件。可以理解为你程序打印出来的一些日志
对于日志记录我们一般会使用 ELK 这是 elastic 公司提供的一套解决方案其中每一个字母代表一个开源组件
E Elasticsearch
L Logstash
KKibana
Metrics 数据聚合
用于聚合数据的通常是有时间顺序的数据
对于数据聚合和统计系统我们一般使用 Prometheus 普罗米修斯来进行处理
可以看到上述这三个概念是相辅相成的仅仅只使用一种方式是没有办法完全满足我们需求的在实际生产过程中会将上述进行两两组合来达到我们期望的效果。
Tracing 与 Logging 组合
既有链路追踪又有日志
那么我们就可以达到的效果是在我们每一个请求阶段可以看到详细的标签数据对应的日志数据以及错误原因
Tracing 与 Metrics 组合
既有链路追踪又有数据统计
那我们就可以去做单个请求中的可计量数据比如说我们的接口调用次数以及调用时长等等
Logging 与 Metrics 组合
既有日志数据又有数据统计
咱们就可以去做数据聚合事件去统计某一段时间某一类接口的请求总数报错次数成功率等等。
✔分布式链路追踪的基础原理
那知道上述的一些应用场景之后是否会对分布式链路追踪的技术原理有那么一点兴趣了呢那么我们开始吧。
无论分布式链路追踪组件有多少他们都有三个核心的步骤。
代码 埋点 数据存储 查询展示
市面上那么多链路追踪主线那么自然是要遵循一个统一的规范的这个规范就是 OpenTracing
OpenTracing 可以理解为就是一个标准化的库它位于应用程序和链路追踪程序之间它解决了分布式追踪 API 不兼容的问题我们可以理解为是这样的。 无论哪一种链路追踪组件一定会有如下这样的做法 通过上图就可以看到
需要在应用程序中做埋点数据上报到对应的链路追踪组件的收集器上并对数据存储 另外一条路便是前端 UI 来查询数据进行展示
✔链路追踪如何实现
架构基本上也知道了那么它具体的实现细节是什么样的呢
链路追踪中一条链路也就可以理解为是一个 Trace 树一个树上面有多个 Span 基本单元
Span 基本单元有自己的唯一标识通常是 UUID还有其他的一些信息例如时间戳键值对ParentID 以及当前的 SpanID 等等信息。 可以看到整个链路其实就是一个有向无环图。
我们可以看到一条调用链的第1 个 Span 它的 ParentID是空的这一个 Span 就被称为RootSpan 那其他的 Span 自身的 ParentID 就是上一个 SpanID自己的 SpanID 就是下一个 Span 的 ParentID
✔目前常用的分布式链路追踪组件
目前常用的分布式链路追踪组件有这些
Twitter Zpikin Jaeger SkyWalking Pinpoint
其中 Twitter Zpikin 的架构和实现相对简单Jaeger 也是借鉴了google 的 Dapper 论文和 OpenZipkin 的启发
接下来的两个并没有提供 golang 版本的库因此就不过多赘述了接下来主要着重介绍的是
Jaeger
✔Jaeger 的基本架构
Jaeger Uber 开源的分布式链路追踪系统它用于微服务的监控和排查并且支持分布式上下文传播和分布式事务的监控报错分析服务的调用网络分析和性能/延迟优化
它的服务端的代码就是 GO 语言实现的自然也提供了 GO 语言版本的客户端代码库
github.com/uber/jaeger-client-go
Jaeger 的基本架构图是这样的 可以看到 Jaeger 的架构图与上述 OpenTracing 的规范大同小异只不过自身服务端处理的有一些变动整体方向上按照规范来的
Jaeger 是支持多个存储后端且原生支持 OpenTracing 规范拥有可视化友好的UI界面支持云原生部署且还能兼容 Zipkin 格式的请求
官方文档上也可以看到关于支持的存储后端有这些 ✔Jaeger 使用
现在自己的虚拟机上面装一个 Jaeger 的服务端官方有提供一键 docker 运行的版本叫做 All-in-One 这个仅仅是用来实验如果是要放在正式环境请参考官方文档进行环境部署
https://www.jaegertracing.io/docs/1.12/deployment/
$ docker run -d --name jaeger \-e COLLECTOR_ZIPKIN_HTTP_PORT9411 \-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.12安装完毕之后我们直接访问 Jaeger 的前端即可前端暴露的端口是 16686 http://localhost:16686 Jaeger demo
咱们简单写一个 Jaeger 的例子仅仅是在一个应用中模拟 test1 - testtest1-1 的一个链路
package mainimport (logtimejaegerCfg github.com/uber/jaeger-client-go/configgithub.com/opentracing/opentracing-gogithub.com/uber/jaeger-client-gocontext
)func main() {// 初始 log 日志log.SetFlags(log.LstdFlags | log.Lshortfile)// 配置 Jaegercfg : jaegerCfg.Configuration{Sampler: jaegerCfg.SamplerConfig{Type: jaeger.SamplerTypeConst,Param: 1,},Reporter: jaegerCfg.ReporterConfig{LogSpans: true,LocalAgentHostPort: 127.0.0.1:6831,},}// 创建一个全局的 Jaeger tracercloser, err : cfg.InitGlobalTracer(testSvr,)if err ! nil {log.Printf(InitGlobalTracer error: %s, err.Error())return}var ctx context.TODO()span1, ctx : opentracing.StartSpanFromContext(ctx, test1)// 模拟业务处理time.Sleep(time.Second)span11, _ : opentracing.StartSpanFromContext(ctx, test1-1)// 模拟业务处理time.Sleep(time.Second)span11.Finish()span1.Finish()defer closer.Close()
}通过程序代码我们可以知道
是给 Jaeger 的 6831 这个端口发送 ****Udp 包 Jaeger 是 opentracing.StartSpanFromContext 在上下文上传入我们当前的 operationName 来进行处理的效果可以见后续的图
运行代码的时候如果你的环境里面不是 golang 1.18 的话则会出现这样的报错此时需要先卸载当前环境中的 golang再去安装新版本的 golang 如果不是先卸载再安装那么会出现一些库报错的问题例如这样 环境 ok 之后我们直接访问环境地址上16686端口就可以看到如下页面
选择 Service 为 testSvr 查看具体的 Trace 此处可以看到调用关系为 test1 调用了 test1-1其中 test1 自身处理事项耗时 1s等待 test1-1 处理事项 1s因此整个链路耗时 2s
对于链路追踪咱们需要知道的是原理知道原理之后编码都是很简单的事情上述仅是一个简单的 demo主要是展示如何去使用这个链路追踪组件
实际业务中我们会对微服务之间的交互进行链路追踪并且会从前端请求进来就会开始记录
这个时候我们涉及到 http 中的代码 埋点grpc 中的代码埋点自然 Jaeger 都是有相应的中间件和拦截器来进行使用的实际上都是对 ctx 上下文上面做文章这里就不过多赘述了将 Jaeger 的代码下载到本地稍微阅读一下就可以知道了
使用链路追踪我们就可以很清晰的看到一条完整的调用链每一个环节耗时多少整体来看性能的瓶颈在哪里就可以做到一清二楚先用起来了吧看看源码
会使用到这些库
github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing
github.com/uber/jaeger-client-go/config
github.com/opentracing/opentracing-go
github.com/uber/jaeger-client-go感谢阅读欢迎交流点个赞关注一波 再走吧
欢迎点赞关注收藏
朋友们你的支持和鼓励是我坚持分享提高质量的动力 好了本次就到这里
技术是开放的我们的心态更应是开放的。拥抱变化向阳而生努力向前行。
我是阿兵云原生欢迎点赞关注收藏下次见~
文中提到的技术点感兴趣的可以查看这些文章
瞧一瞧 gRPC的拦截器 最常用的限流算法以及如何在http中间件中加入流控 都在还说链路跟踪那么 go-zero 的链路跟踪是咋样的 k8s 服务升级为啥 pod 会部署到我们不期望的节点上看来你还不懂污点和容忍度 【LFU】一文让你弄清 Redis LFU 页面置换算法 【LRU】一文让你弄清 Redis LRU 页面置换算法 可以进入地址进行体验和学习https://xxetb.xet.tech/s/3lucCI