自从项目上了SkyWalking,睡觉真香!(1)

简介: 自从项目上了SkyWalking,睡觉真香!(1)


前言

在微服务架构中,一次请求往往涉及到多个模块,多个中间件,多台机器的相互协作才能完成。这一系列调用请求中,有些是串行的,有些是并行的,那么如何确定这个请求背后调用了哪些应用,哪些模块,哪些节点及调用的先后顺序?如何定位每个模块的性能问题?本文将为你揭晓答案。

本文将会从以下几个方面来阐述

  • 分布式追踪系统原理及作用
  • SkyWalking的原理及架构设计
  • 我司在分布式调用链上的实践

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

分布式追踪系统的原理及作用

如何衡量一个接口的性能好坏,一般我们至少会关注以下三个指标

  • 接口的 RT 你怎么知道?
  • 是否有异常响应?
  • 主要慢在哪里?

单体架构

在初期,公司刚起步的时候,可能多会采用如下单体架构,对于单体架构我们该用什么方式来计算以上三个指标呢?

最容易想到的显然是用 AOP

使用 AOP 在调用具体的业务逻辑前后分别打印一下时间即可计算出整体的调用时间,使用 AOP 来 catch 住异常也可知道是哪里的调用导致的异常。

微服务架构

在单体架构中由于所有的服务,组件都在一台机器上,所以相对来说这些监控指标比较容易实现,不过随着业务的快速发展,单体架构必然会朝微服务架构发展,如下

如图示:一个稍微复杂的微服务架构

如果有用户反馈某个页面很慢,我们知道这个页面的请求调用链是 A ----->  C ----->  B ----->  D,此时如何定位可能是哪个模块引起的问题。每个服务 Service A,B,C,D 都有好几台机器。怎么知道某个请求调用了服务的具体哪台机器呢?

可以明显看到,由于无法准确定位每个请求经过的确切路径,在微服务这种架构下有以下几个痛点

  1. 排查问题难度大,周期长
  2. 特定场景难复现
  3. 系统性能瓶颈分析较难

分布式调用链就是为了解决以上几个问题而生,它主要的作用如下

  • 自动采取数据
  • 分析数据产生完整调用链 :有了请求的完整调用链,问题有很大概率可复现
  • 数据可视化:每个组件的性能可视化,能帮助我们很好地定位系统的瓶颈,及时找出问题所在

通过分布式追踪系统能很好地定位如下请求的每条具体请求链路,从而轻易地实现请求链路追踪,每个模块的性能瓶颈定位与分析。

分布式调用链标准 - OpenTracing

知道了分布式调用链的作用,那我们来看下如何实现分布式调用链的实现及原理, 首先为了解决不同的分布式追踪系统 API 不兼容的问题,诞生了 OpenTracing 规范,OpenTracing 是一个轻量级的标准化层,它位于应用程序/类库和追踪或日志分析程序之间。

这样 OpenTracing 通过提供平台无关,厂商无关的 API,使得开发人员能够方便地添加追踪系统的实现。

说到这大家是否想过 Java 中类似的实现?还记得 JDBC 吧,通过提供一套标准的接口让各个厂商去实现,程序员即可面对接口编程,不用关心具体的实现。这里的接口其实就是标准,所以制定一套标准非常重要,可以实现组件的可插拔。

接下来我们来看 OpenTracing 的数据模型,主要有以下三个

  • Trace :一个完整请求链路
  • Span :一次调用过程(需要有开始时间和结束时间)
  • SpanContext :Trace 的全局上下文信息, 如里面有traceId

理解这三个概念非常重要,为了让大家更好地理解这三个概念,我特意画了一张图

如图示,一次下单的完整请求 完整就是一个 Trace, 显然对于这个请求来说,必须要有一个全局标识来标识这一个请求,每一次调用就称为一个 Span,每一次调用都要带上全局的 TraceId, 这样才可把全局 TraceId 与每个调用关联起来,这个 TraceId 就是通过 SpanContext 传输的,既然要传输显然都要遵循协议来调用。如图示,我们把传输协议比作车,把 SpanContext 比作货,把 Span 比作路应该会更好理解一些。

理解了这三个概念,接下来我看看分布式追踪系统如何采集统一图中的微服务调用链

我们可以看到底层有一个 Collector 一直在默默无闻地收集数据,那么每一次调用 Collector 会收集哪些信息呢。

  1. 全局 trace_id:这是显然的,这样才能把每一个子调用与最初的请求关联起来
  2. span_id: 图中的 0,1,1.1,2,这样就能标识是哪一个调用
  3. parent_span_id:比如 b 调用 d 的  span_id 是 1.1,那么它的 parent_span_id 即为 a 调用 b 的 span_id 即 1,这样才能把两个紧邻的调用 关联起来。

有了这些信息,Collector 收集的每次调用的信息如下

根据这些图表信息显然可以据此来画出调用链的可视化视图如下

于是一个完整的分布式追踪系统就实现了。

以上实现看起来确实简单,但有以下几个问题需要我们仔细思考一下

  1. 怎么自动 采集 span 数据:自动采集,对业务代码无侵入
  2. 如何跨进程传递 context
  3. traceId 如何保证全局唯一
  4. 请求量这么多采集会不会影响性能

接下我来看看 SkyWalking 是如何解决以上四个问题的

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

SkyWalking的原理及架构设计

怎么自动采集 span 数据

SkyWalking 采用了插件化 + javaagent 的形式来实现了 span 数据的自动采集,这样可以做到对代码的 无侵入性 ,插件化意味着可插拔,扩展性好(后文会介绍如何定义自己的插件)

如何跨进程传递 context

我们知道数据一般分为 header 和 body, 就像 http 有 header 和 body, RocketMQ 也有 MessageHeader,Message Body, body 一般放着业务数据,所以不宜在 body 中传递 context,应该在 header 中传递 context,如图示

dubbo 中的 attachment 就相当于 header ,所以我们把 context 放在 attachment 中,这样就解决了 context 的传递问题。

小提示:这里的传递 context 流程均是在 dubbo plugin 处理的,业务无感知,这个 plugin 是怎么实现的呢,下文会分析

traceId 如何保证全局唯一

要保证全局唯一 ,我们可以采用分布式或者本地生成的 ID,使用分布式话需要有一个发号器,每次请求都要先请求一下发号器,会有一次网络调用的开销,所以 SkyWalking 最终采用了本地生成 ID 的方式,它采用了大名鼎鼎的 snowflow 算法,性能很高。

图示: snowflake 算法生成的 id

不过 snowflake 算法有一个众所周知的问题:时间回拨 ,这个问题可能会导致生成的 id 重复。那么 SkyWalking 是如何解决时间回拨问题的呢。

每生成一个 id,都会记录一下生成 id 的时间(lastTimestamp),如果发现当前时间比上一次生成 id 的时间(lastTimestamp)还小,那说明发生了时间回拨,此时会生成一个随机数来作为 traceId。这里可能就有同学要较真了,可能会觉得生成的这个随机数也会和已生成的全局 id 重复,是否再加一层校验会好点。

这里要说一下系统设计上的方案取舍问题了,首先如果针对产生的这个随机数作唯一性校验无疑会多一层调用,会有一定的性能损耗,但其实时间回拨发生的概率很小(发生之后由于机器时间紊乱,业务会受到很大影响,所以机器时间的调整必然要慎之又慎),再加上生成的随机数重合的概率也很小,综合考虑这里确实没有必要再加一层全局惟一性校验。对于技术方案的选型,一定要避免过度设计,过犹不及

相关文章
|
Web App开发 人工智能 小程序
爆肝熬夜开发了一个SpringBoot活动管理系统,现在开源给你!毕设面试学习都不愁了!
基于springboot的小程序系统,前台是小程序,后台用springboot开发的,源码进行开源。系统和奈斯,前台面向的是用户,可以进行登录、注册、在线预约活动、公告查看、活动分类查看等
287 0
爆肝熬夜开发了一个SpringBoot活动管理系统,现在开源给你!毕设面试学习都不愁了!
|
22小时前
|
SQL 分布式计算 算法
Jmeter--基础使用(1),2024年最新跳槽面试大厂被拒怎么回复
Jmeter--基础使用(1),2024年最新跳槽面试大厂被拒怎么回复
|
存储 Dubbo NoSQL
自从项目上了SkyWalking,睡觉真香!(2)
自从项目上了SkyWalking,睡觉真香!(2)
|
前端开发 JavaScript NoSQL
SpringBoot日记本系统全程直播05:把日记新增功能搞出来撒~
SpringBoot日记本系统全程直播05:把日记新增功能搞出来撒~
|
前端开发 Java 数据库
SpringBoot日记本系统全程直播01:先把框架搞起来撒~~
SpringBoot日记本系统全程直播01:先把框架搞起来撒~~
108 0
|
XML SQL JavaScript
SpringBoot日记本系统全程直播09:项目一期完结
大家好,我是兔哥呀。我又来啦,这个SpringBoot日记本系统已经接近尾声了,目前已经完成的模块有日记本的增删改查,类型的增删改查,头像上传,还有个人中心。 最后一节呢,我们来做一个收尾工作哈。
136 0
|
前端开发 Java
SpringBoot日记本系统全程直播02:登录页面搞起来撒~~
SpringBoot日记本系统全程直播02:登录页面搞起来撒~~
|
消息中间件 负载均衡 JavaScript
自从项目用了灰度发布,睡觉真香!
自从项目用了灰度发布,睡觉真香!
|
JSON Kubernetes Cloud Native
美女同事的烦恼:如何配置 Apache SkyWalking 告警?
技术部基本上是一个和尚庙,女生非常少,即使有女生也略微有点抽象,小婉就不一样,她气质绝佳。 上午,同事小婉刚才从老板办公室里出来,看上去一脸不悦的样子。为了表示对同事的关(ba)心(gua),我就主动和她聊一聊。
313 0
美女同事的烦恼:如何配置 Apache SkyWalking 告警?
|
前端开发 JavaScript API
晒一晒我的简易版热更新
前端项目开发过程中热更新的机制大家都知道,不知道你在开发的时候是否做了这方面的配置。 相信接触最多的就是 webpack 的热更新,文件保存后页面自动刷新,或者 css 自动更新,页面的样式在不刷新页面的情况下就会更新。 还有就是模块热替换。 热更新机制很好玩,能提升不少开发效率,但是只是处于会用的阶段不是我们的目的,我们应该适当的深入学习下,看看他背后的原理,一个是否思考过,一个是否能自己实现。
154 0
晒一晒我的简易版热更新