漯河网站建设兼职,怎么弄免费的php空间做网站,长春财经学院是一本还是二本,网站做漏洞扫描费用“ 在微服务架构中#xff0c;一次请求往往涉及到多个模块#xff0c;多个中间件#xff0c;多台机器的相互协作才能完成。图片来自 Pexels这一系列调用请求中#xff0c;有些是串行的#xff0c;有些是并行的#xff0c;那么如何确定这个请求背后调用了哪些应用#xf… “ 在微服务架构中一次请求往往涉及到多个模块多个中间件多台机器的相互协作才能完成。图片来自 Pexels这一系列调用请求中有些是串行的有些是并行的那么如何确定这个请求背后调用了哪些应用哪些模块哪些节点及调用的先后顺序如何定位每个模块的性能问题本文将为你揭晓答案。本文将会从以下几个方面来阐述分布式追踪系统原理及作用SkyWalking 的原理及架构设计我司在分布式调用链上的实践分布式追踪系统的原理及作用如何衡量一个接口的性能好坏一般我们至少会关注以下三个指标接口的 RT 你怎么知道?是否有异常响应?主要慢在哪里? 单体架构在初期公司刚起步的时候可能多会采用如下单体架构对于单体架构我们该用什么方式来计算以上三个指标呢最容易想到的显然是用 AOP使用 AOP 在调用具体的业务逻辑前后分别打印一下时间即可计算出整体的调用时间使用 AOP 来 catch 住异常也可知道是哪里的调用导致的异常。 微服务架构在单体架构中由于所有的服务组件都在一台机器上所以相对来说这些监控指标比较容易实现。不过随着业务的快速发展单体架构必然会朝微服务架构发展如下图一个稍微复杂的微服务架构如果有用户反馈某个页面很慢我们知道这个页面的请求调用链是A→C→B→D此时如何定位可能是哪个模块引起的问题。每个服务 Service ABCD 都有好几台机器。怎么知道某个请求调用了服务的具体哪台机器呢可以明显看到由于无法准确定位每个请求经过的确切路径在微服务这种架构下有以下几个痛点排查问题难度大周期长。特定场景难复现。系统性能瓶颈分析较难。分布式调用链就是为了解决以上几个问题而生它主要的作用如下自动采取数据。分析数据产生完整调用链有了请求的完整调用链问题有很大概率可复现。数据可视化每个组件的性能可视化能帮助我们很好地定位系统的瓶颈及时找出问题所在。通过分布式追踪系统能很好地定位如下请求的每条具体请求链路从而轻易地实现请求链路追踪每个模块的性能瓶颈定位与分析。分布式调用链标准OpenTracing知道了分布式调用链的作用那我们来看下如何实现分布式调用链的实现及原理。首先为了解决不同的分布式追踪系统 API 不兼容的问题诞生了 OpenTracing 规范。OpenTracing 是一个轻量级的标准化层它位于应用程序/类库和追踪或日志分析程序之间。这样 OpenTracing 通过提供平台无关厂商无关的 API使得开发人员能够方便地添加追踪系统的实现。说到这大家是否想过 Java 中类似的实现还记得 JDBC 吧通过提供一套标准的接口让各个厂商去实现程序员即可面对接口编程不用关心具体的实现。这里的接口其实就是标准所以制定一套标准非常重要可以实现组件的可插拔。接下来我们来看 OpenTracing 的数据模型主要有以下三个Trace一个完整请求链路。Span一次调用过程(需要有开始时间和结束时间)。SpanContextTrace 的全局上下文信息如里面有 TraceId。理解这三个概念非常重要为了让大家更好地理解这三个概念我特意画了一张图如图示一次下单的完整请求完整就是一个 Trace显然对于这个请求来说必须要有一个全局标识来标识这一个请求每一次调用就称为一个 Span每一次调用都要带上全局的 TraceId。这样才可把全局 TraceId 与每个调用关联起来这个 TraceId 就是通过 SpanContext 传输的既然要传输显然都要遵循协议来调用。如图示我们把传输协议比作车把 SpanContext 比作货把 Span 比作路应该会更好理解一些。理解了这三个概念接下来我看看分布式追踪系统如何采集统一图中的微服务调用链。我们可以看到底层有一个 Collector 一直在默默无闻地收集数据那么每一次调用 Collector 会收集哪些信息呢全局 trace_id这是显然的这样才能把每一个子调用与最初的请求关联起来。span_id图中的 011.12这样就能标识是哪一个调用。parent_span_id比如 b 调用 d 的 span_id 是 1.1那么它的 parent_span_id 即为 a 调用 b 的 span_id 即 1这样才能把两个紧邻的调用关联起来。有了这些信息Collector 收集的每次调用的信息如下根据这些图表信息显然可以据此来画出调用链的可视化视图如下于是一个完整的分布式追踪系统就实现了。以上实现看起来确实简单但有以下几个问题需要我们仔细思考一下怎么自动采集 Span 数据自动采集对业务代码无侵入。如何跨进程传递 Context。TraceId 如何保证全局唯一。请求量这么多采集会不会影响性能。接下我来看看 SkyWalking 是如何解决以上四个问题的。SkyWalking 的原理及架构设计 怎么自动采集 Span 数据SkyWalking 采用了插件化javaagent 的形式来实现了 Span 数据的自动采集。这样可以做到对代码的无侵入性插件化意味着可插拔扩展性好(后文会介绍如何定义自己的插件)。 如何跨进程传递 Context我们知道数据一般分为 Header 和 Body就像 HTTPhttp 有 Header 和 BodyRocketMQ 也有 MessageHeaderMessage 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 重复是否再加一层校验会好点。这里要说一下系统设计上的方案取舍问题了首先如果针对产生的这个随机数作唯一性校验无疑会多一层调用会有一定的性能损耗。但其实时间回拨发生的概率很小(发生之后由于机器时间紊乱业务会受到很大影响所以机器时间的调整必然要慎之又慎)再加上生成的随机数重合的概率也很小综合考虑这里确实没有必要再加一层全局惟一性校验。对于技术方案的选型一定要避免过度设计过犹不及。全部采集会不会影响性能请求这么多如果对每个请求调用都采集那毫无疑问数据量会非常大但反过来想一下是否真的有必要对每个请求都采集呢。其实没有必要我们可以设置采样频率只采样部分数据SkyWalking 默认设置了 3 秒采样 3 次其余请求不采样如图示这样的采样频率其实足够我们分析组件的性能了按 3 秒采样 3 次这样的频率来采样数据会有啥问题呢。理想情况下每个服务调用都在同一个时间点(如下图示)这样的话每次都在同一时间点采样确实没问题。但在生产上每次服务调用基本不可能都在同一时间点调用因为期间有网络调用延时等实际调用情况很可能是下图这样这样的话就会导致某些调用在服务 A 上被采样了在服务 BC 上不被采样也就没法分析调用链的性能那么 SkyWalking 是如何解决的呢。它是这样解决的如果上游有携带 Context 过来(说明上游采样了)则下游强制采集数据。这样可以保证链路完整。 SkyWalking 的基础架构SkyWalking 的基础如下架构可以说几乎所有的的分布式调用都是由以下几个组件组成的首先当然是节点数据的定时采样采样后将数据定时上报将其存储到 ES, MySQL 等持久化层有了数据自然而然可根据数据做可视化分析。 SkyWalking 的性能如何接下来大家肯定比较关心 SkyWalking 的性能那我们来看下官方的测评数据图中蓝色代表未使用 SkyWalking 的表现橙色代表使用了 SkyWalking 的表现以上是在 TPS 为 5000 的情况下测出的数据。可以看出不论是 CPU内存还是响应时间使用 SkyWalking 带来的性能损耗几乎可以忽略不计。接下来我们再来看 SkyWalking 与另一款业界比较知名的分布式追踪工具 ZipkinPinpoint 的对比(在采样率为 1 秒 1 个线程数 500请求总数为 5000 的情况下做的对比)。可以看到在关键的响应时间上 Zipkin(117ms)PinPoint(201ms)远逊色于 SkyWalking(22ms)从性能损耗这个指标上看SkyWalking 完胜再看下另一个指标对代码的侵入性如何ZipKin 是需要在应用程序中埋点的对代码的侵入强而 SkyWalking 采用 javaagent插件化这种修改字节码的方式可以做到对代码无任何侵入。除了性能和对代码的侵入性上 SkyWaking 表现不错外它还有以下优势几个优势对多语言的支持组件丰富目前其支持 Java.Net CorePHPNodeJSGolangLUA 语言组件上也支持 DubboMySQL 等常见组件大部分能满足我们的需求。扩展性对于不满足的插件我们按照 SkyWalking 的规则手动写一个即可新实现的插件对代码无入侵。我司在分布式调用链上的实践SkyWalking 在我司的应用架构由上文可知 SkyWalking 有很多优点那么是不是我们用了它的全部组件了呢其实不然来看下其在我司的应用架构从图中可以看出我们只采用了 SkyWalking 的 Agent 来进行采样放弃了另外的「数据上报及分析」「数据存储」「数据可视化」三大组件。那为啥不直接采用 SkyWalking 的整套解决方案呢因为在接入 SkyWalking 之前我们的 Marvin 监控生态体系已经相对比较完善了。如果把其整个替换成 SkyWalking一来没有必要Marvin 在大多数场景下都能满足我们的需求二来系统替换成本高三来如果重新接入用户学习成本很高。这也给我们一个启示任何产品抢占先机很重要后续产品的替换成本会很高抢占先机也就是抢占了用户的心智这就像微信虽然 UI功能上制作精良但在国外照样干不过 Whatsapp 一样因为先机已经没了。从另一方面来看对架构来说没有最好的最有最合适的结合当前业务场景去平衡折中才是架构设计的本质。 我司对 SkyWalking 的改造实践我司主要作了以下改造和实践预发环境由于调试需要强制采样实现更细粒度的采样日志中嵌入 traceId自研实现了 SkyWalking 插件①预发环境由于调试需要强制采样从上文分析可知 Collector 是在后台定时采样的这不挺好的吗为啥要实现强制采样呢。还是为了排查定位问题有时线上出现问题我们希望在预发上能重现希望能看到这个请求的完整调用链所以在预发上实现强制采样很有必要。所以我们对 Skywalking 的 Dubbo 插件进行了改造实现强制采样。我们在请求的 Cookie 上带上一个类似 force_flagtrue 这样的键值对来表示我们希望强制采样。在网关收到这个 Cookie 后就会在 Dubbo 的 Attachment 里带上force_flagtrue 这个键值对。然后 Skywalking 的 Dubbo 插件就可以据此来判断是否是强制采样了如果有这个值即强制采样如果没有这个值则走正常的定时采样。②实现更细粒度的采样?哈叫更细粒度的采样。先来看下 Skywalking 默认的采样方式 即统一采样。我们知道这种方式默认是 3 秒采样前 3 次其他请求都丢弃这样的话有个问题。假设在这台机器上在 3 秒内有多个 DubboMySQLRedis 调用但在如果前三次都是 Dubbo 调用的话其他像 MySQLRedis 等调用就采样不到了。所以我们对 Skywalking 进行了改造实现了分组采样如下就是说 3 秒内进行 3 次 RedisDubboMySQL 等的采样也就避免了此问题。③日志中如何嵌入 TraceId输出日志中嵌入 TraceId 便于我们排查问题所以打出出 TraceId 非常有必要该怎么在日志中嵌入 TraceId 呢我们用的是 log4j这里就要了解一下 log4j 的插件机制了log4j 允许我们自定义插件来输出日志的格式首先我们需要定义日志的格式在自定义的日志格式中嵌入 %traceId作为占位符如下然后我们再实现一个 log4j 的插件如下首先 log4j 的插件要定义一个类这个类要继承 LogEventPatternConverter 这个类并且用标准 Plugin 将其自身声明为 Plugin。通过 ConverterKeys 这个注解指定了要替换的占位符然后在 format 方法里将其替换掉。这样在日志中就会出现我们想要的 TraceId如下④我司自研了哪些 Skywalking 插件SkyWalking 实现了很多插件不过未提供 Memcached 和 Druid 的插件所以我们根据其规范自研了这两者的插件插件如何实现呢可以看到它主要由三个部分组成插件定义类指定插件的定义类最终会根据这里的定义类打包生成 plugin。Instrumentation指定切面切点要对哪个类的哪个方法进行增强。Interceptor指定步骤 2 中要在方法的前置后置还是异常中写增强逻辑。可能大家看了还是不懂那我们以 Dubbo Plugin 来简单讲解一下我们知道在 Dubbo 服务中每个请求从 Netty 接收到消息递交给业务线程池处理开始到真正调用到业务方法结束中间经过了十几个 Filter 的处理而 MonitorFilter 可以拦截所有客户端发出请求或者服务端处理请求所以我们可以对 MonitorFilter 作增强。在其调用 Invoke 方法前将全局 TraceId 注入到其 Invocation 的 Attachment 中这样就可以确保在请求到达真正的业务逻辑前就已经存在全局 TraceId。所以显然我们需要在插件中指定我们要增强的类(MonitorFilter)对其方法(Invoke)做增强要对这个方法做哪些增强呢这就是拦截器(Inteceptor)要做的事来看看 Dubbo 插件中的 instrumentation(DubboInstrumentation)我们再看看下代码中描写的拦截器(Inteceptor)干了什么事以下列出关键步骤首先 beforeMethod 代表在执行 MonitorFilter 的 invoke 方法前会调用这里的方法与之对应的是 afterMethod代表在执行 invoke 方法后作增强逻辑。其次我们从第 23 点可以看到不管是 Consumer 还是 Provider, 都对其全局 ID 作了相应处理。这样确保到达真正的业务层的时候保证有了此全局 Traceid定义好 Instrumentation 和 Interceptor 后最后一步就是在 skywalking.def 里指定定义的类// skywalking-plugin.def 文件dubboorg.apache.skywalking.apm.plugin.asf.dubbo.DubboInstrumentation这样打包出来的插件就会对 MonitorFilter 的 Invoke 方法进行增强在 Invoke 方法执行前对期 Attachment 作注入全局 TraceId 等操作这一切都是静默的对代码无侵入的。总结本文由浅入深地介绍了分布式追踪系统的原理相信大家对其作用及工作机制有了比较深的理解。特别需要注意的是引入某项技巧一定要结合现有的技术架构作出最合理的选择就像 SkyWalking 有四个模块我司只采用其 Agent 采样功能一样没有最好的技术只有最合适的技术。通过此文相信大家应该对 SkyWalking 的实现机制有了比较清晰的认识文中只是介绍了一下 SkyWalking 的插件实现方式不过其毕竟是工业级软件要了解其博大精深还要多读源码哦。作者码海编辑陶家龙出处转载自公众号码海(IDseaofcode)精彩文章推荐Kafka都没整明白还敢去面试一次代码评审差点过不了试用期漫画丨Linux内核到底长啥样