解决方案:传递给系统调用的数据区域太小怎么解决_分布式追踪系统不懂?没事,搞懂这40张图

优采云 发布时间: 2022-11-30 18:46

  解决方案:传递给系统调用的数据区域太小怎么解决_分布式追踪系统不懂?没事,搞懂这40张图

  各位新人大家好,大家好!由于公众号改版了,为了保证公众号的资源能按时推送到大家的手中,大家记得把我们的公众号置顶加星哦。在此表示衷心的感谢~

  正文如下:

  # 前言

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

  本文将从以下几个方面进行阐述

  # 分布式跟踪系统的原理和作用

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

  单体架构

  早期,公司刚起步的时候,可能会采用如下单体架构。对于单体结构,我们应该如何计算以上三个指标呢?

  最容易想到的显然是使用AOP

  使用AOP打印调用具体业务逻辑前后的时间来计算整体调用时间,使用AOP捕获异常,知道是哪里的调用导致了异常。微服务架构

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

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

  如果用户反映某个页面很慢,我们知道这个页面的请求调用链是A -----> C -----> B -----> D,如何定位哪个可能是模块在这个时候出现了问题。每个服务Service A、B、C、D都有几台机器。您如何知道请求在哪台特定机器上调用服务?

  可以明显看出,由于无法准确定位每个请求的准确路径,微服务架构下以下痛点难以排查。周期长的特定场景下系统性能瓶颈难以重现。

  分布式调用链就是为解决上述问题而诞生的,其主要作用如下

  通过分布式跟踪系统,可以很好地定位后续请求的各个具体请求链接,从而轻松实现请求链接跟踪,轻松实现各模块的性能瓶颈定位和分析。

  分布式调用链标准——OpenTracing

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

  通过这种方式,OpenTracing 使开发人员能够通过提供独立于平台和供应商的 API 轻松添加跟踪系统的实现。

  说到这里,你有没有想过在 Java 中有类似的实现?还记得JDBC吗,通过提供一套标准的接口供各个厂商实现,程序员可以针对接口进行编程,而不用关心具体的实现。这里的接口其实就是一个标准,所以制定一套标准非常重要,可以实现组件的可插拔性。

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

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

  如图所示,一个完整的订单请求就是一个Trace。显然,对于这个请求,必须有一个全局标识来标识这个请求。每次调用调用一个Span,每次调用都必须携带全局TraceId,这样全局TraceId才能与每次调用相关联。这个TraceId是通过SpanContext传递过来的。既然要传输,就必须按照协议来调用。如图所示,如果把transport protocol比作汽车,SpanContext比作货物,Span比作公路,应该更容易理解。

  理解了这三个概念之后,再来看看分布式追踪系统是如何将微服务调用链采集

到统一图中的

  我们可以看到最下面有一个Collector一直在默默的采集

数据,那么每次调用Collector都会采集

什么信息。

  global trace_id:这个很明显,这样每个子调用都可以关联到原创

请求span_id:图中的0、1、1.1、2,这样就可以识别出是哪个调用parent_span_id:比如b调用的span_id d为1.1,那么它的parent_span_id就是a调用b的span_id,为1,这样相邻的两个调用就可以关联起来。

  有了这些信息,采集

器为每个电话采集

的信息如下

  根据这些图表信息,很明显可以画出调用链的可视化视图如下

  这样就实现了一个完整的分布式跟踪系统。

  上面的实现看起来很简单,但是有几个问题需要我们仔细思考

  How to automatically collect span data: 自动采集,不侵入业务代码 如何跨进程传递contexttraceId 如何保证全局唯一请求量 采集这么多会不会影响性能

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

  

" />

  # SkyWalking如何自动采集span数据的原理和架构设计

  SkyWalking采用插件+javaagent的形式实现span数据的自动采集,可以对代码无侵入。插件意味着可插拔和良好的扩展性(后面我们会介绍如何定义自己的插件))

  如何跨进程传递上下文

  我们知道数据一般分为header和body,就像http有header和body一样,RocketMQ也有MessageHeader,Message Body,body一般收录

业务数据,所以body不宜传context,应该传入表头,如图

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

  提示:这里的上下文传递过程全部由dubbo插件处理,业务无感知。这个插件是怎么实现的呢?下面将分析traceId如何保证全局唯一性

  为了确保全局唯一性,我们可以使用分布式或本地生成的 ID。如果我们使用分布式,我们需要一个数字*敏*感*词*。每个请求必须首先请求数字*敏*感*词*。会有网络调用开销,所以SkyWalking最终采用了本地生成ID的方式,并且采用了著名的snowflow算法,性能较高。

  图解:雪花算法生成的id

  但是,雪花算法有一个众所周知的问题:时间回调,可能会导致重复生成id。那么SkyWalking是如何解决时间回调问题的呢?

  每次生成一个id,都会记录这个id生成的时间(lastTimestamp)。如果发现当前时间小于上次生成id的时间(lastTimestamp),说明发生了时间回调,此时会生成一个随机数作为traceId。这里可能有些同学想认真点。他们可能认为生成的随机数也将与生成的全局 id 相同。最好再加一层验证。

  这里想谈谈系统设计中方案的选择。首先,如果对生成的随机数进行唯一性校验,无疑会多出一层调用,会有一定的性能损失,但实际上时间回调的概率很小。(发生后,由于机器时间的紊乱,业务会受到很大的影响,所以机器时间的调整一定要谨慎),而且生成的随机数重合的概率也很小。真的没有必要再添加一个Layer全局唯一性校验。对于技术方案的选择,一定要避免过度设计,太多就是太多。

  这么多请求,全部采集

会不会影响性能?

  如果每一个请求都采集

起来,毫无疑问数据量会非常大,但是反过来想想,是不是真的有必要把每一个请求都采集

起来。其实大可不必。我们可以设置采样频率,只采样一些数据,SkyWalking默认设置3秒采样3次,其他请求不采样,如图

  这样的采样频率其实已经足够我们分析元器件的性能了。以每 3 秒 3 个样本的频率采样数据有什么问题?理想情况下,每次服务调用都是在同一个时间点(如下图),所以每次都在同一个时间点采样真的没问题

  但是在生产中,基本上不可能每个服务调用都在同一个时间点调用,因为期间存在网络调用延迟,实际调用情况很可能如下图所示

  在这种情况下,有些调用会在服务A上被采样,而不会在服务B和C上被采样,无法分析调用链的性能。那么SkyWalking是如何解决的。

  是这样解决的:如果上游携带了Context(说明上游已经采样),下游就会强制采集数据。这使链接保持完整。

  SkyWalking的基础设施

  SkyWalking 的基础是以下架构。可以说几乎所有的分布式调用都是由以下几个组件组成的

  首先当然是节点数据的定期采样。数据采样后定期上报,存储在ES、MySQL等持久层。有了数据,自然要根据数据做可视化分析。SkyWalking 的表现如何?

  接下来想必大家比较关心的是SkyWalking的性能表现,那么我们就来看看官方的评测数据吧

  图中蓝色代表未使用SkyWalking时的表现,橙色代表使用SkyWalking时的表现。以上是TPS为5000时测得的数据,可以看出无论是CPU、内存,还是响应时间,使用SkyWalking带带来的性能损失几乎可以忽略不计。

  接下来看一下SkyWalking与业界另一知名分布式追踪工具Zipkin、Pinpoint的对比(采样率为1秒,线程数为500,总请求数时进行对比)是 5000)。可以看出,在临界响应时间方面,Zipkin(117ms)、PinPoint(201ms)远不如SkyWalking(22ms)!

  从性能损失来看,SkyWalking 胜出!

  让我们看另一个指标:代码的侵入性如何?ZipKin需要埋在应用中,代码侵入性大。SkyWalking使用javaagent+插件修改字节码。没有侵入代码。除了代码的性能和侵入性,SkyWaking 的表现也不错。它还具有以下优点:

  # 我司在我司应用架构中分布式调用链SkyWalking的实践

  从上面可以看出SkyWalking有很多优点,那么它的组件我们都用上了吗?事实上,并非如此。来看看它在我们公司的应用架构

  从图中可以看出,我们只使用了SkyWalking代理进行采样,而放弃了其他三大组件“数据上报与分析”、“数据存储”、“数据可视化”,那么为什么不直接使用一整套 SkyWalking 的解决方案,因为我们的 Marvin 监控生态在接入 SkyWalking 之前已经比较完善了。如果我们换成SkyWalking,就没有必要了。Marvin 可以满足我们大部分场景的需求。第二,系统更换成本高,第三,如果用户重新连接,学习成本非常高。

  这也给了我们一个启示:任何产品抓住机会都是非常重要的,后续产品的更换成本会非常高。抢占先机,就是抢占用户心智。国外还是做不了Whatsapp一样的,因为机会没了。

  另一方面,对于架构,没有最好的,只有最合适的。架构设计的本质是结合当前业务场景进行折衷平衡

  我司对SkyWalking做了哪些改造和实践

  我公司主要做了以下改造和实践

  预发布环境需要强制采样调试,实现更细粒度的采样?traceId嵌入日志,自研实现SkyWalking插件。预发布环境需要强制采样调试

  从上面的分析可以看出,Collector是在后台定时采样的。这不好吗?为什么我们需要实施强制采样?或者排查定位问题,有时线上出现问题,我们希望在预发布上复现,希望看到这个请求完整的调用链,所以需要在预发布上进行强制采样。所以我们修改Skywalking的dubbo插件实现强制采样

  

" />

  我们在request cookie上放一个类似force_flag = true的key-value对,表示我们要强制采样。网关收到这个cookie后,会在dubbo附件中带上键值对force_flag = true,然后skywalking的dubbo插件就可以根据这个来判断是否是强制采样。如果有这个值,就是强制采样。如果没有这个值,则进行正常定时采样。

  实现更细粒度的采样?

  Ha 称为更细粒度的采样。先来看一下skywalking默认的采样方式,即uniform sampling

  我们知道这个方法默认是在3秒前采样3次,其他的请求都被丢弃。在这种情况下,有一个问题。假设3秒内本机有多次dubbo、mysql、redis调用,但是如果前3次都是dubbo调用的话,其他像mysql、redis等调用无法采样,所以我们修改了skywalking实现分组抽样,如下

  也就是说3秒内对redis、dubbo、mysql等进行3次采样,也避免了这个问题。如何在日志中嵌入 traceId?

  在输出日志中嵌入traceId,方便我们排查问题,所以打印traceId是非常有必要的,如何在日志中嵌入traceId呢?我们使用log4j,这里我们需要了解一下log4j的插件机制,log4j允许我们自定义插件输出日志的格式,首先我们需要定义日志的格式,在自定义日志格式,作为一个账号位,如下

  然后我们实现一个log4j插件,如下

  首先,log4j插件需要定义一个类,该类继承LogEventPatternConverter类,并用标准Plugin声明自己为Plugin,通过@ConverterKeys注解指定需要替换的占位符,然后在format方法中替换失去。这样日志中就会出现我们想要的TraceId,如下

  我司开发了哪些skywalking插件

  SkyWalking实现了很多插件,但是没有提供memcached和druid的插件,所以我们根据这两个的规范开发了插件

  插件是如何实现的,可以看到主要由三部分组成

  插件定义类:指定插件的定义类,最后根据这里的定义类生成pluginInstrumentation。在设置或异常中编写增强逻辑

  可能大家看了还是不太明白,下面就用dubbo plugin来简单说明一下。我们知道,在dubbo服务中,每次请求都会收到来自netty的消息,提交给业务线程池处理,真正调用到业务方法时结束。中间经过十几个Filter进程

  而MonitorFilter可以拦截所有客户端请求或者服务端处理请求,所以我们可以增强MonitorFilter,在调用invoke方法之前,将全局traceId注入到它的Invocation attachment中,从而保证请求到达真正业务之前全局traceId已经存在逻辑。

  那么显然我们需要在插件中指定我们要增强的类(MonitorFilter),并增强它的方法(invoke)。应该对此方法进行哪些改进?这就是*敏*感*词*(Inteceptor)要做的事情。来看看Dubbo插件中的插桩(DubboInstrumentation)

  我们来看看代码中描述的*敏*感*词*(Inteceptor)是干什么的。关键步骤如下

  首先,beforeMethod表示这里的方法会在MonitorFilter的invoke方法执行之前被调用,而afterMethod与之对应,表示invoke方法执行之后才会执行增强逻辑。

  其次,从第2点和第3点我们可以看出,无论是消费者还是提供者,其全局ID都做了相应的处理,以保证到达真正的业务层时,全局traceid是可用的。定义好 Instrumentation 和 Interceptor 之后,最后一步就是在 skywalking.def 中指定定义的类

  // skywalking-plugin.def 文件dubbo=org.apache.skywalking.apm.plugin.asf.dubbo.DubboInstrumentation

  这样打包出来的插件就会对 MonitorFilter 的  invoke 方法进行增强,在 invoke

   方法执行前对期 attachment 作注入全局 traceId 等操作,这一切都是静默的,

  对代码无侵入的。

  # 总结

  本文由浅入深地介绍了分布式跟踪系统的原理。相信大家对它的作用和工作机制有了更深入的了解。尤其需要注意的是,在引入某项技术时,一定要结合现有的技术架构,做出最佳方案。一个合理的选择,就像SkyWalking有四个模块,我们公司只是用它的agent采样功能,没有最好的技术,只有最适合的技术,通过这篇文章,相信大家应该对SkyWalking的实现机制有了更清晰的认识文章只介绍SkyWalking的插件实现,但毕竟是工业级软件。要了解它的深奥,还需要多阅读源码。

  看完这篇文章,你有什么收获?欢迎在留言区与30w+ Java开发者共同探讨~

  热门推荐:

  厉害了,华为云开源的Spring Cloud框架,网友:这是在对标阿里~某运营商官网竟然带了木马脚本,给用户宣传*敏*感*词*~厉害了,我写了一个类似QQ界面的聊天小项目在Java中,可以在线聊天(附源码)~

  点击

  最新版本:免费迅睿CMS采集插件-SEO工具支持各大CMS网站批量采集发布

  Q:如何使用免费的迅锐CMS采集

插件?如何批量采集文章到迅锐CMS 答:一键创建多个采集任务,实现批量采集文章发布。每个网站只需要设置关键词即可自动采集并发布文章 Q:免费的迅锐CMS采集插件可以应用到多少个网站?A:网站数量没有限制。新增网站只需要创建任务即可实现采集和发布。Q:迅锐CMS免费插件收录了多少篇文章?答:每天可采集数千万条数据(根据自己网站设置) Q:免费迅锐CMS插件 如何发布锐CMS插件采集?A:该工具具有迅锐CMS自动发布功能,开启采集

后可自动发布到站点。无论是旧版还是新版的迅锐CMS都可以使用,再也不用担心因为网站版本没有更新而无法使用采集

功能了!Q:安装免费的迅锐CMS采集插件复杂吗?答:直接在本地电脑安装,双击直接运行!由于是与服务器无关的本地采集工具,不会造成服务器卡顿,从而保证服务器有良好的访问速度,有利于搜索引擎的抓取!如何使用免费的迅锐CMS采集

插件打开软件导入关键词采集

文章,

  还为SEO人员配备定时发帖功能(设置定时发帖,让搜索引擎更频繁地抓取,使整个网站不断被抓取收录,提高排名。网站排名越高,排名越高交通..

  

" />

  ) 发布工具还支持自动内链,标题插入关键词,内容插入关键词,随机作者,随机阅读数,再也不用担心因为网站太多而手忙脚乱!永远不要在网站后台来回切换,反复登录后台很痛苦。再也不用担心您的网站不再充满内容了。一个网站的流量取决于网站被收录的比例,收录越多关键词排名越高,流量越大。

  

" />

  为什么那么多人选择迅锐CMS 迅锐cms免费开源系统是一款面向网站开发者的简易框架管理软件。

  本软件基于PHP7语言使用CodeIgniter4构建。提供电脑、手机、APP等多种界面和一体化操作模式。不会因用户二次开发而损坏程序核心。web和PHP的建站功能都能完美运行。堪称PHP通用建站框架。. 并且迅锐CMS采用研发出资的全新模板技术,可以帮助用户快速分离MVC设计模式的业务层和表现层,支持原生态PHP语法,支持CI框架语法。各种模板只需要用户分析一次,下次可以快速添加使用,让您设计出自己理想的模板。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线