| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> 链路追踪(Tracing)的前世今生(上) -> 正文阅读 |
|
[Java知识库]链路追踪(Tracing)的前世今生(上) |
带着疑问看历史提起链路追踪,大部分人都会想起 Zipkin、Jaeger、Skywalking 这些已经比较成熟的链路追踪开源软件以及 Opentelemetry、OpenTracing、OpenCensus 这些开源标准。虽然实现各有差异,但是使用各种软件、标准和实现组合搭建出来的不同的链路追踪系统,却有着许多相类似的地方。 例如这些链路追踪系统都需要在调用链路上传播元数据。他们对元数据内容的定义也大同小异,链路唯一的 trace id, 关联父链路的 parent id,标识自身的 span id 这些。他们都是异步分散上报采集的追踪信息,离线的聚合聚合追踪链路。他们都有链路采样等等。 链路追踪系统架构和模型的设计看着都是如此相似,我不禁会产生一些疑问:开发者在设计链路追踪的时候,想法都是这么一致吗?为什么要在调用链路传递元数据?元数据的这些信息都是必要的吗?不侵入修改代码可以接入到链路追踪系统吗?为什么要异步分散上报,离线聚合?设置链路采样有什么用? 带着各种各样的问题,我找到这些众多链路追踪软件的灵感之源 – 《Google Dapper》 论文,并且拜读了原文以及相关的引用论文。这些论文逐渐解开了我心中的疑惑。 黑盒模式探索早期学术界对分布式系统链路状态检测的探索,有一派的人们认为分布式系统里面的每个应用或者中间件,应该是一个个黑盒子,链路检测不应该侵入到应用系统里面。那个时候 Spring 还没被开发出来,控制反转和切面编程的技术也还不是很流行,如果需要侵入到应用代码里面,需要涉及到修改应用代码,对于工程师来说额外接入门槛太高,这样的链路检测工具就会很难推广开来。 如果不允许侵入应用里面修改代码,那就只能够从应用的外部做手脚,获取并记录链路信息了。而由于黑盒的限制,链路信息都是零散的无法串联起来。如何把这些链路串联起来成了需要解决的问题。 《Performance Debugging for Distributed Systems of Black Boxes》 这篇论文发表于 2003 年,是对黑盒模式下的调用链监测的探索,文中提出了两种寻找链路信息的算法。 第一种算法称为“嵌套算法”,首先是通过生成唯一 id 的方式,把一次跨服务调用的请求 (1 call)链路与返回(11 return)链路关联再一起形成链路对。然后再利用时间的先后顺序,把不同往返链路对做平级关联或上下级关联(参考图1)。 图1 如果应用是单线程情况,这种算法但是没有什么问题。生产的应用往往是多线程的,所以使用这种方法无法很好的找到链路间对应关系。虽然论文提出了一种记分板惩罚的方法可以对一些错误关联的链路关系进行除权重,但是这种方法对于一些基于异步 RPC 调用的服务,却会出现一些问题。 另外一种算法称为“卷积算法”,把往返链路当成独立的链路,然后把每个独立链路对当成一个时间信号,使用信号处理技术,找到信号之间的关联关系。这种算法好处是能够出使用在基于异步 RPC 调用的服务上。但是如果实际的调用链路存在回环的情况,卷积算法除了能够得出实际的调用链路,还会得出其他调用链路。例如调用链路 A -> B -> C -> B -> A,卷积算法除了得出其本身调用链路,还会得出 A -> B -> A 的调用链路。如果某个节点在一个链路上出现次数多次,那么这个算法很可能会得出大量衍生的调用链路。 在黑盒模式下,链路之间的关系是通过概率统计的方式判断链路之间的关联关系。概率统计始终是概率,没办法精确得出链路之间的关联关系。 另一种思路怎么样才能够精确地得出调用链路之间的关系呢?下面这篇论文就给出了一些思路与实践。 Pinpoint: Problem Determination in Large, Dynamic Internet Services 注:此 Pinpoint 非 github 上的 pinpoint-apm 这篇论文的研究对象主要是拥有不同组件的单体应用,当然相应的方法也可以扩展到分布式集群中。在论文中 Pinpoint 架构设计主要分为三部分。参考 图2,其中 Tracing 与 Trace Log 为第一部分,称为客户端请求链路追踪(Client Request Trace),主要用于收集链路日志。Internal F/D 、External F/D 和 Fault Log 为第二部分,是故障探测信息(Failure Detection),主要用于收集故障日志。Statistical Analysis 为第三部分,称为数据聚类分析(Data Clustering Analysis),主要用于分析收集进来的日志数据,得出故障检测结果。
Pinpoint 架构中,设计了一种能够有效用于数据挖掘分析方法的数据。如 图3 所示,每个调用链路作为一个样本数据,使用唯一的标识 request id 标记,样本的属性记录了这个调用链路所经过的程序组件(Component)以及故障状态(Failure)。
为了能够把每次调用的链路日志 (Trace Logs) 和 故障日志 (Fault Logs) 都关联起来,论文就以 Java 应用为例子,描述了如何在代码中实现这些日志的关联。下面是 Pinpoint 实践章节的一些关键点汇总: 需要为每一个组件生成一个 component id 这篇论文发表时间是 2002 年,那个时候 java 版本是 1.4,已经具备了线程本地变量(ThreadLocal)的能力,在线程中携带信息是比较容易做到的。但又因为在那个时代切面编程还不是很普及(Spring 出现在 2003年,javaagent 是在 java 1.5 才有的能力,发布于2004年),所以这样的方法并不能够被广泛应用。如果反过来想,可能正是因为这些编程需求的出现,促使着 java 切面编程领域的技术进步。 重新构建调用链路X-Trace: A Pervasive Network Tracing Framework 这篇论文主要研究对象是分布式集群里面的网络链路。X-Trace 论文延续并扩展了 Pinpoint 论文的思路,提了能够重新构建完整调用链路的框架和模型。为了达到目的,文中定义了三个设计原则: 在调用链路内携带元数据(在调用链路传递的数据也称之为带内数据,in-bound data) 下面再看看 X-Trace 对元数据的内容定义: Flags
在 X-Trace 上报链路数据的结构设计中,遵循了第 2 个设计原则。如 图6 所示, X-Trace 为应用提供了一个轻量的客户端包,使得应用端可以转发链路数据到一个本地的守护进程。而本地的守护进程则是开放一个 UDP 协议端口,接收客户端包发过来的数据,并放入到一个队列里面。队列的另外一边则根据链路数据的具体具体配置信息,发送到对应的地方去,也许是一个数据库,也许是一个数据转发服务、数据收集服务或者是数据聚合服务。
X-Trace 上报链路数据的架构设计,对现在市面上的链路追踪实现有着不小的影响。对照 Zipkin 的 collector 以及 Jeager 的 jaeger-agent,多少能够看到 X-Trace 的影子。 X-Trace 的三个设计原则、带内带外数据的定义、元数据传播操作定义、链路数据上报架构等,都是现今链路追踪系统有所借鉴的内容。对照 Zipkin 的 collector 以及 Jeager 的 jaeger-agent,就多少能够看到 X-Trace 链路数据上报架构的影子。 大规模商用实践 – DapperDapper, a Large-Scale Distributed Systems Tracing Infrastructure Dapper 是谷歌内部用于给开发者们提供复杂分布式系统行为信息的系统。Dapper 论文则是介绍谷歌对这个分布式链路追踪基础设施设计和实践的经验。Dapper 论文发布于2010年,根据论文的表述,Dapper 系统已经在谷歌内部有两年的实践经验了。 Dapper 系统的主要目的是给开发者提供提供复杂分布式系统行为信息。文中分析为了实现这样的系统,需要解决什么样的问题。并根据这些问题提出了两个基本的设计需求:大范围部署和持续性的监控。针对着两个基本设计要求,提出了三个具体的设计目标: 低开销(Low overhead):链路追踪系统需要保证对在线服务的的性能影响做到忽略不计的程度。即使是很小的监控消耗也会对一些高度优化过的服务有可觉察的影响,甚至迫使部署团队关闭追踪系统。 另外一个独到的特点是他们实现非常高的应用透明度。这个得益于 Google 应用集群部署有比较高的同质化,他们可以把链路追踪设施实现代码限制在软件的底层而不需要在应用里面添加而外的注解信息。举个例子,集群内应用如果使用相同的 http 库、消息通知库、线程池工厂和 RPC 库,那么就可以把链路追踪设施限制在这些代码模块里面。 如何定义链路信息的?文中首先举了一个简单的调用链例子,如 图7 ,作者认为对一个请求做分布式追踪需要收集消息的识别码以及消息对应的事件与时间。如果只考虑 RPC 的情况,调用链路可以理解为是 RPCs 嵌套树。当然,谷歌内部的数据模型也不局限于 RPCs 调用。
图8 阐述了 Dapper 追踪树的结构,树的节点为基本单元,称之为 span。边线为父子 span 之间的连接。一个 span 就是简单带有起止时间戳、RPC 耗时或者应用相关的注解信息。为了重新构建 Dapper 追踪树,span 还需要包含以下信息: span name: 易于阅读的名字,如图8中的 Frontend.Request
图9 是一个 RPC span 的详细信息。值得一提的是,一个相同的 span 可能包含多个主机的信息。实际上,每一个 RPC span 都包含了客户端和服务端处理的注释。由于客户端的时间戳和服务端的时间戳来自不同的主机,所以需要异常关注这些时间的异常情况。图9 是一个 span 的详细信息
如何实现应用级透明的?Dapper 通过对一些通用包添加测量点,对应用开发者在零干扰的情况下实现了分布式链路追踪,主要有以下实践: 当一个线程在处理链路追踪路径上时,Dapper 会把追踪上下文关联到线程本地存储。追踪上下文是一个小巧且容易复制的 span 信息容易。 结尾Dapper 论文给出了易于阅读和有助于问题定位的数据模型设计、应用级透明的测量实践以及低开销的设计方案,为链路追踪在工业级应用的使用清除了不少障碍,也激发了不少开发者的灵感。自从 Google Dapper 论文出来之后,不少开发者受到论文的启发,开发出了各式各样的链路追踪,2012 年推特开源 Zipkin、Naver 开源 Pinpoint,2015 年吴晟开源 Skywalking,Uber 开源 Jaeger 等。从此链路追踪进入了百家争鸣的时代。
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 1:47:37- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |