关于微服务:微服务线上问题排查困难不知道问题出在哪一环那是你还不会分布式链路追踪

101次阅读

共计 4781 个字符,预计需要花费 12 分钟才能阅读完成。

咱们以前单体利用外面有很多的利用和性能,依赖各个性能之间互相调用,应用公共的代码包等等,排查问题,应用相似于 gdb/dlv 工具或者间接查看代码日志 进行定位和剖析

然而当初咱们基本上都是 微服务架构 了,将以前的单体架构拆成了一个个独立的微服务,当初就变成了多个微服务之间的互相调用的关系

在一个业务链条中,两头可能波及到几个,十几个甚至几十个微服务的交互和配合,如果两头某一环呈现了问题,那么咱们是很难排查的,排查问题耗时耗力,且效率极其低下

服务数量多,链路简单,排查艰难,大佬们就想出了一个方法,应用分布式链路追踪来解决这个问题

本文别离从以下几个方面来聊聊对于 分布式链路追踪 的技术常识:

  • 什么是分布式链路追踪

<!—->

  • 分布式链路追踪的根底原理

<!—->

  • 目前罕用的分布式链路追踪组件

<!—->

  • Jaeger 的根本架构和应用演示

✔什么是分布式链路追踪

分布式链路追踪,见名知意,这是用在分布式系统中,用于追踪服务调用链路的

文章结尾有说到,微服务架构中,存在大量的微服务,且保护的团队不尽相同,应用的语言也不太统一

线上部署几百上千台服务器,若链路呈现了问题,性能呈现了瓶颈,咱们如何排查,如何无效的解决呢?

分布式链路追踪他就能够将一次分布式申请还原成调用链路,将一次分布式申请的调用情况集中展现,且他还提供敌对的 UI 界面,咱们间接在页面上就能直观的看到每一个服务的耗时申请到具体哪台服务器上以及服务相应的状态等等👀👀。

在技术上通常应用

  • Tracing 示意链路追踪

次要是用于单个申请的解决流程,包含服务调用和服务解决时长等信息

目前分布式上应用的比拟多的是 Jaeger

  • Logging 日志记录

次要是用来记录离散的日志事件。能够了解为你程序打印进去的一些日志

对于日志记录,咱们个别会应用 ELK,这是 elastic 公司提供的一套解决方案,其中每一个字母代表一个开源组件

E: Elasticsearch

L: Logstash

K:Kibana

  • 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 应用

  1. 当初本人的虚拟机下面装一个 Jaeger 的服务端,官网有提供一键 docker 运行的版本,叫做 All-in-One,这个仅仅是用来试验,如果是要放在正式环境,请参考官网文档进行环境部署

https://www.jaegertracing.io/docs/1.12/deployment/

$ 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.12

装置结束之后,咱们间接拜访 Jaeger 的前端即可,前端裸露的端口是 16686, http://localhost:16686

🧐Jaeger demo

咱们简略写一个 Jaeger 的例子,仅仅是在一个利用中,模仿 test1 -> testtest1-1 的一个链路

package main

import (
   "log"
   "time"
   jaegerCfg "github.com/uber/jaeger-client-go/config"
   "github.com/opentracing/opentracing-go"
   "github.com/uber/jaeger-client-go"
   "context"
)

func main() {
   // 初始 log 日志
   log.SetFlags(log.LstdFlags | log.Lshortfile)
   // 配置 Jaeger
   cfg := jaegerCfg.Configuration{
      Sampler: &jaegerCfg.SamplerConfig{
         Type:  jaeger.SamplerTypeConst,
         Param: 1,
      },
      Reporter: &jaegerCfg.ReporterConfig{
         LogSpans:           true,
         LocalAgentHostPort: "127.0.0.1:6831",
      },
   }
   // 创立一个全局的 Jaeger tracer
   closer, 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 页面置换算法

正文完
 0