点击上方“程序架构首页”关注公众号并设为明星
终身学习技术信息及时传递
回顾过去的问题
1、
2、
一、问题背景
随着微服务架构的流行,服务按照不同维度进行拆分,一个请求往往会涉及多个服务。 互联网应用程序建立在不同的软件模块集上。 此类软件模块可以由不同的团队开发,使用不同的编程语言实现,并且可以分布在跨多个不同数据中心的数千台服务器上。 为此,我们需要一些能够帮助理解系统行为、分析性能问题的工具,以便在发生故障时能够快速定位并解决问题。
全链路监控组件就是在这样的问题背景下形成的。 最著名的就是微软公开论文中提到的GoogleDapper。 如果您想了解分布式系统在这种情况下的行为,您需要跨不同应用程序和不同服务器监视这些相关操作。
因此,在复杂的微服务架构系统中数字监控系统软件教程,几乎每一个后端请求都会产生复杂的分布式服务调用链路。 一个请求的完整调用链可能如右图所示:
一个请求完整的调用链
这样,在业务规模不断缩小、服务不断增加、变更频繁的情况下,面对复杂的调用链路就带来了一系列问题:
同时,我们会关注请求处理过程中每次调用的各种性能指标,例如:吞吐量(TPS)、响应时间、错误记录等。
全链路性能监控,展示从整体维度到局部维度的各项指标,集中解读跨应用所有调用链的性能信息。 它可以轻松测量整体和局部性能,还可以轻松找到故障源,从而可以大大减少产量。 故障排除时间短。
通过全链路监控工具,我们可以实现:
2、目标要求
如上所述,我们选择全链路监控组件的目标要求是什么? GoogleDapper中也提到了,总结如下:
1、探针的性能消耗
APM组件服务的影响应该足够小。 服务调用埋藏本身会带来性能损失,这就要求调用跟踪的消耗较低。 实际中,会通过配置采样率来选择一部分请求来分析请求路径。 在一些高度优化的服务中,即使是少量的磨损也很容易被注意到,并可能促使在线服务部署团队禁用跟踪系统。
2、代码的侵入性
即作为业务组件,对其他业务系统的侵入应该尽可能少或者不侵入,并且对用户透明,减轻开发人员的负担。
对于应用程序员来说,没有必要知道有跟踪系统。 一个追踪系统要想发挥作用,必须依赖应用开发者的积极配合。 这个追踪系统也太脆弱了。 应用程序问题通常是由应用程序中的跟踪系统植入的代码中的错误或遗漏引起的。 这就是未来。 可以满足跟踪系统“无处不在部署”的需求。
3. 可扩展性
一个优秀的呼叫追踪系统必须支持分布式部署并具有良好的可扩展性。 它可以支持的组件越多越好。 或者提供方便的插件开发API,对于一些不受监控的组件,应用开发者也可以自行扩展。
4. 数据分析
数据分析应该快速完成,维度尽可能多。 跟踪系统可以提供足够快的信息反馈,对生产环境中的异常情况做出快速反应。 综合分析还可以防止二次开发。
3、功能模块
通常的全链路监控系统大致可以分为四个功能模块:
1. 埋点和生成日志
埋点是指当前节点系统的上下文信息,可分为客户端埋点、服务器端埋点、客户端与服务器之间的单向埋点。 跟踪日志一般包含以下内容:traceId、spanId、调用开始时间、合约类型、调用者IP和端口、请求的服务名称、调用时长、调用结果、异常信息等。同时还有一个可扩展的数组预留用于以下 制定进一步扩展的计划;
不能造成绩效负担:一个价值未经验证却会影响绩效的东西,在公司很难推广!
由于需要写入日志,业务QPS越高,对性能的影响就越大。 通过采样和异步日志解决。
2. 日志收集和存储
主要支持分布式日志收集的方案,同时减少MQ作为缓冲区:
3. 分析统计调用链路数据,以及时效性
1)调用链追踪分析:收集具有相同TraceID的span,并按时间排序,形成时间线。 将ParentID串起来就是调用堆栈。
抛出异常或超时,并复制日志中的 TraceID。 使用TraceID查询调用链,定位问题。
2)依赖性测量:
3)离线分析:通过TraceID进行汇总,通过Span ID和ParentID还原调用关系,分析链路形态。
4)实时分析:直接分析单个日志,无需汇总或重组。 获取当前 QPS,推迟。
4. 解释和决策支持
4. 谷歌简洁
1.跨度
基本的工作单元,一个链接调用(可以是RPC、DB等,没有具体限制)创建一个span并用64位ID来标识它。 Uuid 更方便。 Span中还有其他数据,例如描述信息和时间戳。 、键值对的(注解)标签信息、parent_id等,其中parent-id可以代表span调用链路的来源。
跨度
上图说明了大跟踪期间跨度的样子。 Dapper 会记录 Span 名称,以及每个 Span 的 ID 和父 ID,以在跟踪过程中重建不同 Span 之间的关系。 如果跨度没有父 ID,则称为根跨度。 所有跨度都绑定到特定跟踪并共享跟踪 ID。
跨度数据结构:
type Span struct {
TraceID int64 // 用于标示一次完整的请求id
Name string
ID int64 // 当前这次调用span_id
ParentID int64 // 上层服务的调用span_id 最上层服务parent_id为null
Annotation []Annotation // 用于标记的时间戳
Debug bool
}
2.追踪
类似于树结构的 Span 集合表示一个完整的跟踪,从向服务器发出请求开始,到服务器返回响应结束。 它跟踪每个rpc调用的持续时间并具有唯一的trace_id。 例如:您运行的分布式大数据存储的 Trace 由您的一个请求组成。
痕迹
每个颜色注释表示一个span,一条链路由TraceId唯一标识,Span表示发起的请求信息。 树节点是整个架构的基本单元,每个节点都是span的引用。 节点之间的连接表示该跨度与其父跨度之间的直接关系。 其实span只是简单的代表了日志文件中span的开始和结束时间,但是它们在整个树结构中是相对独立的。
3. 注释
注释用于记录对特定风暴相关信息(例如时间)的请求。 一个span内会有多个注解描述。 一般包含四个注释信息:
注释数据结构:
type Annotation struct {
Timestamp int64
Value string
Host Endpoint
Duration int32
}
4. 调用示例
1)请求调用示例
请求呼叫示例
2)呼叫进程跟踪
通话全过程跟踪
3)调用链核心工作
4)总体部署框架
整体部署框架
5. AGENT无创部署
通过AGENT代理的非侵入式部署,性能检测和业务逻辑完全分离,可以通过任意方式检测任意类的执行时间。 这些方法大大提高了采集效率,同时降低了运维成本。 根据服务跨度主要分为两类AGENT:
(1)Dubbo支持;
(2)Rest支持;
(3)自定义RPC支持;
6)调用链监控的使用
5、方案对比
市面上的全链路监控理论模型大多借鉴了GoogleDapper论文。 本文重点介绍以下三个 APM 组件:
上述三种全链路监控方案需要对比的项目总结如下:
1. 探头性能
更加关注探头的性能。 虽然APM定位仍然是一个工具,但如果启用链路监控后吞吐量增加一半以上,这是不可接受的。 对 skywalking、zipkin 和 pinpoint 进行了压力测试,并与基线进行了比较(不使用探针)。
选择了一个常见的基于Spring的应用程序,包括SpringBoot、SpringMVC、redis客户端和mysql。 为了监视此应用程序,对于每个跟踪,探测器将捕获 5 个跨度(1Tomcat、1SpringMVC、2Jedis、1Mysql)。 与skywalkingtest的测试应用基本相同。
模拟了三种并发用户:500、750、1000。使用jmeter进行测试数字监控系统软件教程,每个线程发送30个请求,思考时间设置为10ms。 使用的采样率为1,即100%,可能与生产有所不同。 pinpoint默认采样率为20,即50%。 可以通过设置代理配置文件将其更改为100%。 Zipkin 也默认为 1。 加起来总共有12种。 请参阅下面的汇总表:
探头性能比较
从上表可以看出,三个链路监控组件中,skywalking的probe对吞吐量的影响最小,zipkin的吞吐量居中。 精确探针对吞吐量有重大影响。 当并发用户数为500时,测试服务的吞吐量从1385增加到774,影响很大。 然后我们看看对CPU和内存的影响。 对内部服务器进行压力测试,对CPU和内存的影响几乎在10%以内。
2. 收集器的可扩展性
收集器的可扩展性使得能力能够水平扩展以支持大规模服务器集群。
1) 拉链
开发zipkin-Server(尽管它是一个开箱即用的包)。 Zipkin-agent 通过 http 或 mq 与 zipkin-Server 进行通信。 HTTP通信会影响正常访问,所以建议基于mq异步方式进行通信。 zipkin-Server 通过订阅特定主题进行消费。 这个其实是可以扩展的。 多个zipkin-Server实例可以异步消费mq中的监控信息。
拉链
2)空中漫步
skywalking的collector支持两种部署形式:单机模式和集群模式。 收集器和代理之间的通信使用 gRPC。
3)精确定位
同样,pinpoint也支持集群和单机部署。 pinpointagent通过thrift通信框架向收集器发送链接信息。
3. 全面的通话链路数据分析
全面的调用链路数据分析提供代码级可见性,轻松定位故障点和困境。
1) 拉链
zipkin链接调用分析
zipkin的链接监控粒度相对没有那么细。 从上图可以看出,调用链是特定于socket级别的,没有涉及到进一步的调用信息。
2)空中漫步
Skywalking链接调用分析
skywalking还支持20+中间件、框架和类库,例如主流的dubbo、Okhttp,以及DB和消息中间件。 上图中的skywalking链接调用分析和拦截比较简单。 网段调用用户服务。 因为支持很多中间件,所以skywalking的链接调用分析比zipkin更完整。
3)精确定位
pinpoint链接调用分析
Pinpoint应该是这三个APM组件中最完整的数据分析组件了。 提供代码级可见性可以轻松定位故障点和困境。 上图可以看到,所有执行的SQL语句都被记录下来。 还可以配置举报规则等,为每个应用设置负责人,根据配置的规则进行举报。 支持的中间件和框架也比较齐全。
4.开发透明,切换方便
对开发透明,易于打开和关闭,无需更改代码即可添加新功能,易于启用或禁用。 我们希望功能能够在不更改代码的情况下工作,并且希望代码级可见性。
为此,Zipkin 使用修改后的泛型及其自己的容器 (Finagle) 来提供分布式事务跟踪功能。 此外,它还需要在必要时更改代码。 skywalking和pinpoint都是基于字节码增强的。 开发人员无需更改代码,并且由于字节码中包含更多信息,因此可以收集更准确的数据。
5. 完整的调用链应用拓扑
手动检查应用程序拓扑以帮助您了解应用程序的架构。
精确链路拓扑
skywalking链路拓扑
zipkin链路拓扑
前三张图分别展示了APM组件的调用拓扑,它们都可以实现完整的调用链应用拓扑。 相对而言,pinpoint界面显示的越来越丰富,特别是调用的DB的名称,而zipkin的拓扑仅限于服务服务。
6.Pinpoint和Zipkin细化对比
1)Pinpoint 和 Zipkin 的区别
2)Pinpoint 和 Zipkin 的相似之处
Pinpoint和Zipkin都是基于GoogleDapper论文,所以理论基础大致相同。 两者都是将服务调用拆分为多个具有级联关系的span,通过SpanId和ParentSpanId来级联调用关系; 最后,流经整个调用链的所有span都被压缩成一个Trace并报告给服务。 最后的收集器收集并存储。
尽管在这一点上,Pinpoint 使用的概念与那篇论文并不完全一致。 比如他使用TransactionId而不是TraceId,而真正的TraceId是一个包含TransactionId、SpanId和ParentSpanId的结构体。 而且Pinpoint在Span下添加了一个SpanEvent结构体,用来记录一个Span的内部调用细节(比如具体的方法调用等),所以Pinpoint默认会比Zipkin记录更多的跟踪数据。
而且理论上来说,Span的大小是没有限制的,所以一个服务调用可以是一个Span,所以每个服务中的方法调用也可以是一个Span。 在这种情况下,虽然Brave也可以跟踪方法调用级别,但这只是具体的实现。 仅此而已。
3)字节码注入vsAPI调用
Pinpoint实现了基于字节码注入的JavaAgent探针,而Zipkin的Brave框架只提供了应用程序级的API,仔细想想问题远没有那么简单。 字节码注入是一种简单粗暴的解决方案。 理论上,任何方法调用都可以通过注入代码来拦截。 换句话说,没有办不到的事,只有办不到的事。
但《勇敢者》不同。 它提供的应用级API也需要框架底层驱动的支持才能实现拦截。 例如MySQL的JDBC驱动提供了注入拦截器的方式,那么只需要实现StatementInterceptor套接字并在ConnectionString中配置即可轻松实现相关拦截; 相比之下,低版本的MongoDB驱动或者SpringDataMongoDB的实现没有这样的接口,实现拦截查询语句的功能比较困难。
所以,在这一点上,《Brave》是失败的。 不管使用字节码注入有多困难,至少是可以实现的。 勇敢也许无法启动,但能否注入、注入到什么程度,更多取决于它。 取决于框架的 API 而不是其自身的功能。
4)难度和成本
通过简单阅读Pinpoint和Brave插件的代码,就可以发现两者的实现难度有很大不同。 Brave 比 Pinpoint 更容易使用,无需任何开发文档的支持。 Brave中的代码量非常少,核心功能都集中在brave-core模块中。 中级开发人员三天之内就可以看懂其内容,并对API结构有非常清晰的认识。
Pinpoint的代码封装性也非常好,尤其是对字节码注入的底层API的封装非常出色,而这还是需要读者对字节码注入有一定的了解,虽然它的注入代码的核心API并不多,但是如果想要理解透彻,恐怕还得深入Agent的相关代码。 例如,很难清楚地理解addInterceptor和addScopedInterceptor之间的区别,而这两个方法位于Agent的相关类型中。
由于Brave的注入依赖底层框架提供相关socket,因此不需要对框架有全面的了解。 你只需要知道可以注入到哪里,注入时能得到什么数据。 和前面的例子一样,我们不需要知道MySQL的JDBCDriver是如何实现的,就可以实现拦截SQL的能力。 而Pinpoint则不然,因为Pinpoint几乎可以在任何地方注入任何代码,这就需要开发者对需要注入的库的代码实现有特别深入的了解。 您可以通过查看其 MySQL 和 HttpClient 插件的实现来深入了解这一点。 其实这也从另一个层面说明了Pinpoint的能力确实非常强大,但是它的很多默认插件已经实现了非常细致的拦截。
当底层框架没有公共API时,虽然Brave也不是完全无能为力,但我们可以通过AOP的方式将相关拦截注入到指定的代码中。 然而事实上,AOP的应用比字节码注入简单得多。 。
上述内容与实施监控的成本直接相关。 在Pinpoint的官方技术文档中,给出了参考数据。 如果集成一个系统,开发Pinpoint插件的成本为100,将插件集成到系统中的成本为0; 但对于Brave来说,插件开发成本仅为20,集成成本为10。从这一点可以看出,官方成本参考数据是5:1。 并且官方指出,如果需要集成的系统有10个,那么总成本就是10*10+20=120,这超过了Pinpoint的开发成本100,而且需要集成的服务越多,成本就越大。区别。 。
5) 多功能性和可扩展性
看来Pinpoint在这方面完全处于劣势,从社区开发的集成套接字就可以看出。
Pinpoint的数据套接字缺乏文档,但它不是很标准(参考峰会讨论帖子)。 您需要阅读大量代码来实现您自己的探针(例如 Node 或 PHP 的)。 并且出于性能考虑,团队使用Thrift作为数据传输合约标准,其难度比HTTP和JSON要低很多。
6) 社区支持
不言而喻,Zipkin 是 Twitter 开发的,也算是一个著名的团队,而 Naver 的团队只是一个默默无闻的小团队(从 #1759 的讨论就可以看出)。 事实上,这个项目短期内不太可能消失或停止更新,但它不如后者可靠。 而如果没有社区开发更多的插件,Pinpoint 很难仅靠团队自身的力量完成众多框架的整合,但他们目前的重点仍然是提高性能和稳定性。
7) 其他
Pinpoint在实施之初就考虑了性能问题。 该网站的前端各个服务每晚要处理超过200亿个请求。 为此,他们会选择Thrift的二补码变长编码格式,并使用UDP作为传输链路。 同时在传递常量时尽量使用数据引用字典、传递数字而不是直接传递字符串等。这种优化也降低了系统的复杂度:包括Thrift套接字的使用难度、UDP数据传输的难度问题,以及数据常量字典注册问题等。
相比之下,Zipkin 使用的是大家熟悉的 Restful socket 加 JSON,几乎没有学习成本和集成难度。 只要了解了数据传输结构,就可以轻松地为新框架开发相应的socket。
此外,Pinpoint 缺乏对请求进行采样的能力。 即使在大流量的生产环境中,也不可能记录所有的请求。 这需要对请求进行采样以确定我需要记录哪些请求。 Pinpoint 和 Brave 都支持采样率,即记录多少百分比的请求。 此外,Brave还提供了Sampler套接字,允许您自定义采样策略。 这个功能非常有意义,尤其是在进行A/B测试时。
8)总结
从短期目标来看,Pinpoint确实具有压倒性的优势:无需对项目代码进行任何改动即可部署探针,跟踪数据直至方法调用级别,拥有强大的用户界面,并且拥有几乎全面的Java框架支持。 。 而且从长远来看,未来学习Pinpoint的开发socket以及实现不同框架的socket的成本还是未知的。
相比之下,Brave 相对容易掌握,但 Zipkin 的社区更强大,未来更有可能开发更多套接字。 在最坏的情况下,我们也可以通过AOP添加适合自己的监控代码,而不需要引入太多的新技术和概念。 而当未来业务发生变化时,很难说Pinpoint官方提供的报告是否能够满足要求。 新报告的减少也会带来不可预测的工作难度和工作量。
6. 跟踪和监控的区别
监控可分为系统监控和应用监控。 系统监控CPU、显存、网络、C盘等整体系统负载数据,可以细化到各个进程的相关数据。 此类信息可以直接从系统中获取。 应用监控需要应用的支持并暴露相应的数据。 例如应用程序内部请求的QPS、请求处理的延迟、请求处理的错误数、消息队列的队列宽度、崩溃情况、进程垃圾收集信息等。Monitor的主要目标是发现异常情况并及时报告。
Tracing的基础和核心是调用链。 大多数相关指标都是通过分析调用链获得的。 跟踪的主要目标是系统分析。 早点发现问题比晚点解决要好。
跟踪和应用程序级监视器技术堆栈有很多共同点。 有数据收集、分析、存储和呈现。 只是收集的数据具体维度不同,分析过程也不同。