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

本文涉及的产品
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
日志服务 SLS,月写入数据量 50GB 1个月
简介: 微服务线上问题排查困难?不知道问题出在哪一环?那是你还不会分布式链路追踪

咱们以前单体应用里面有很多的应用和功能,依赖各个功能之间相互调用,使用公共的代码包等等,排查问题,使用类似于 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"

感谢阅读,欢迎交流,点个赞,关注一波 再走吧

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~

文中提到的技术点,感兴趣的可以查看这些文章:

相关实践学习
基于OpenTelemetry构建全链路追踪与监控
本实验将带领您快速上手可观测链路OpenTelemetry版,包括部署并接入多语言应用、体验TraceId自动注入至日志以实现调用链与日志的关联查询、以及切换调用链透传协议以满足全链路打通的需求。
分布式链路追踪Skywalking
Skywalking是一个基于分布式跟踪的应用程序性能监控系统,用于从服务和云原生等基础设施中收集、分析、聚合以及可视化数据,提供了一种简便的方式来清晰地观测分布式系统,具有分布式追踪、性能指标分析、应用和服务依赖分析等功能。 分布式追踪系统发展很快,种类繁多,给我们带来很大的方便。但在数据采集过程中,有时需要侵入用户代码,并且不同系统的 API 并不兼容,这就导致了如果希望切换追踪系统,往往会带来较大改动。OpenTracing为了解决不同的分布式追踪系统 API 不兼容的问题,诞生了 OpenTracing 规范。OpenTracing 是一个轻量级的标准化层,它位于应用程序/类库和追踪或日志分析程序之间。Skywalking基于OpenTracing规范开发,具有性能好,支持多语言探针,无侵入性等优势,可以帮助我们准确快速的定位到线上故障和性能瓶颈。 在本套课程中,我们将全面的讲解Skywalking相关的知识。从APM系统、分布式调用链等基础概念的学习加深对Skywalking的理解,从0开始搭建一套完整的Skywalking环境,学会对各类应用进行监控,学习Skywalking常用插件。Skywalking原理章节中,将会对Skywalking使用的agent探针技术进行深度剖析,除此之外还会对OpenTracing规范作整体上的介绍。通过对本套课程的学习,不止能学会如何使用Skywalking,还将对其底层原理和分布式架构有更深的理解。本课程由黑马程序员提供。
相关文章
|
2月前
|
安全 应用服务中间件 API
微服务分布式系统架构之zookeeper与dubbo-2
微服务分布式系统架构之zookeeper与dubbo-2
|
2月前
|
负载均衡 Java 应用服务中间件
微服务分布式系统架构之zookeeper与dubbor-1
微服务分布式系统架构之zookeeper与dubbor-1
|
3月前
|
存储 监控 Go
带你十天轻松搞定 Go 微服务系列(九、链路追踪)
带你十天轻松搞定 Go 微服务系列(九、链路追踪)
|
6天前
|
存储 JSON 监控
微服务链路追踪原理,一文搞懂!
本文重点讲解微服务链路追踪(Microservices Distributed Tracing),介绍其原理、架构及工作流程。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
微服务链路追踪原理,一文搞懂!
|
19天前
|
存储 NoSQL 关系型数据库
微服务Zipkin链路追踪原理,图解版,一文吃透!
本文重点讲解Zipkin链路追踪的原理与使用,帮助解决微服务架构下的服务响应延迟等问题,提升系统性能与稳定性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
微服务Zipkin链路追踪原理,图解版,一文吃透!
|
1月前
|
消息中间件 存储 负载均衡
微服务与分布式系统设计看这篇就够了!
【10月更文挑战第12天】 在现代软件架构中,微服务和分布式系统设计已经成为构建可扩展、灵活和可靠应用程序的主流方法。本文将深入探讨微服务架构的核心概念、设计原则和挑战,并提供一些关于如何在分布式系统中实现微服务的实用指导。
49 2
|
1月前
|
人工智能 文字识别 Java
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
尼恩,一位拥有20年架构经验的老架构师,通过其深厚的架构功力,成功指导了一位9年经验的网易工程师转型为大模型架构师,薪资逆涨50%,年薪近80W。尼恩的指导不仅帮助这位工程师在一年内成为大模型架构师,还让他管理起了10人团队,产品成功应用于多家大中型企业。尼恩因此决定编写《LLM大模型学习圣经》系列,帮助更多人掌握大模型架构,实现职业跃迁。该系列包括《从0到1吃透Transformer技术底座》、《从0到1精通RAG架构》等,旨在系统化、体系化地讲解大模型技术,助力读者实现“offer直提”。此外,尼恩还分享了多个技术圣经,如《NIO圣经》、《Docker圣经》等,帮助读者深入理解核心技术。
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
|
3月前
|
监控 Go API
带你十天轻松搞定 Go 微服务之大结局(分布式事务)
带你十天轻松搞定 Go 微服务之大结局(分布式事务)
|
3月前
|
Kubernetes 监控 API
微服务从代码到k8s部署应有尽有系列(十二、链路追踪)
微服务从代码到k8s部署应有尽有系列(十二、链路追踪)
|
3月前
|
Java 数据库连接 微服务
揭秘微服务架构下的数据魔方:Hibernate如何玩转分布式持久化,实现秒级响应的秘密武器?
【8月更文挑战第31天】微服务架构通过将系统拆分成独立服务,提升了可维护性和扩展性,但也带来了数据一致性和事务管理等挑战。Hibernate 作为强大的 ORM 工具,在微服务中发挥关键作用,通过二级缓存和分布式事务支持,简化了对象关系映射,并提供了有效的持久化策略。其二级缓存机制减少数据库访问,提升性能;支持 JTA 保证跨服务事务一致性;乐观锁机制解决并发数据冲突。合理配置 Hibernate 可助力构建高效稳定的分布式系统。
66 0