分布式跟踪:我们做错了一切

注意事项 佩雷夫 :本材料的作者是imgix的工程师Cindy Sridharan,他从事API的开发,尤其是测试微服务。 在本文中,她分享了她对分布式跟踪领域中实际问题的详细了解,她认为在该领域中,缺乏真正有效的工具来解决紧迫的问题。


[插图是从另一本有关分布式跟踪的资料中借用的。]

人们认为, 分布式跟踪很难实现,并且其收益充其量是可疑的 。 跟踪的“问题”由多种原因解释,通常是指设置系统的每个组件以随每个请求一起发送相应报头的复杂性。 尽管确实发生了此问题,但根本不能称其为不可克服的。 顺便说一句,它没有解释为什么开发人员不真正喜欢跟踪(即使已经运行)。

分布式跟踪的主要困难是不收集数据,不标准化用于分发和呈现结果的格式,不确定何时,何地以及如何采样。 我一点也不试图将这些“易消化性问题” 简单地介绍出来 -实际上,必须克服相当多的技术和政治挑战(如果我们真的在研究开源标准和协议 ),以便可以考虑这些问题。解决了。

但是,如果您认为所有这些问题都已解决,那么就最终用户体验而言,很可能不会有太大改变。 在大多数常见的调试方案中,即使已经部署了跟踪,跟踪可能仍然不可行。

如此不同的痕迹


分布式跟踪包括几个不同的组件:

  • 为应用程序和中间件配备控件;
  • 分布式上下文传输
  • 跟踪收集;
  • 痕迹的存储;
  • 他们的提取和可视化。

关于分布式跟踪的很多讨论都归结为将其视为一种一元操作,其唯一目的是帮助对系统进行完整的诊断。 这很大程度上是由于分布式跟踪概念的形成方式所致。 在打开Zipkin来源时发表的博客文章中,提到他[Zipkin]使Twitter更快 。 最初的用于跟踪的商业产品也被推广为APM工具

注意事项 佩雷夫 :为了使更多的文本更好地理解,我们根据OpenTracing项目文档定义了两个基本术语:

  • 跨度 -分布式跟踪的基本元素。 它是对某些工作流程(例如,数据库查询)的描述,包括名称,开始和结束时间,标签,日志和上下文。
  • 跨度通常包含到其他跨度的链接,这使您可以在Trace中组合许多跨度-可视化请求在分布式系统中移动时的生命周期。

Trace'y包含非常宝贵的数据,这些数据可以帮助执行以下任务:生产中的测试,进行灾难恢复测试,引入错误的测试等。 实际上,一些公司已经将跟踪用于此目的。 首先, 通用上下文传输除了将跨度简单地传输到存储系统外,还有其他用途:

  • 例如,Uber 使用跟踪结果来区分测试流量和生产流量。
  • Facebook 使用跟踪数据来分析关键路径并在常规灾难恢复测试期间切换流量。
  • 社交网络还使用 Jupyter笔记本,允许开发人员对跟踪结果执行任意查询。
  • 沿袭驱动的故障注入( LDFI)附加程序 使用分布式跟踪进行错误测试。

以上选项均不与调试方案完全相关,在调试方案中,工程师试图通过查看跟踪来解决问题。

在调试场景中, traceview图仍然是主要接口(尽管有些人也称其为“甘特图”“级联图” )。 通过traceview,我的意思是一起构成跟踪的所有范围和相关的元数据。 每个开源跟踪系统以及每个商业跟踪解决方案都提供基于traceview的用户界面,用于可视化,详细显示和过滤跟踪数据。

我目前所熟悉的所有跟踪系统的问题在于,最终的可视化效果(traceview)几乎完全反映了跟踪生成过程的功能。 即使提供了其他可视化效果:强度图(热图),服务拓扑,延迟直方图,最终它们仍然可以追溯到traceview

过去,我抱怨关于UI / UX的可追溯性的大多数“创新”似乎仅限于在跟踪中包括其他元数据,在其中嵌入具有高基数的信息或提供向下钻取特定范围的能力。或执行跟踪间和跟踪内查询。 在这种情况下, traceview仍然是可视化的主要手段。 只要这种情况持续存在,分布式跟踪(最多)将作为调试工具排在第四位,其次是度量,日志和堆栈跟踪,最糟糕的是浪费时间和金钱。

traceview问题


traceview的目的是提供单个请求在与其相关的分布式系统的所有组件之间移动的完整情况。 一些更高级的跟踪系统允许您向下钻取单个跨度并查看单个过程中的时间细分(跨度有功能边界时)。

微服务架构的基本前提是组织结构随公司需求而增长的想法。 支持微服务的人认为,各种业务任务在单独服务中的分布使小型自治开发团队可以控制此类服务的整个生命周期,从而使他们能够独立创建,测试和部署这些服务。 但是,这种分发的缺点是丢失了有关每个服务如何与其他服务交互的信息。 在这种情况下,分布式跟踪声称是调试服务之间的复杂交互所必不可少的工具。

如果您拥有一个真正令人震惊的复杂分布式系统 ,那么没人会记住它的完整画面。 实际上,基于通常可能的假设来开发工具只是一种反模式(低效且无效的方法)。 理想情况下,调试需要一种工具来帮助缩小搜索范围,以便工程师可以专注于与所讨论的场景相关的维度的子集(服务/用户/主机等)。 在确定故障原因时,不需要工程师立即了解所有服务中发生的情况,因为这样的要求将与微服务架构的思想相矛盾。

但是,traceview就是这样。 是的,当跟踪中的跨度数量太大而无法在单个可视化视图中显示时,某些跟踪系统会提供压缩的跟踪视图。 但是,由于即使在这种截断的可视化中也包含大量信息,工程师仍被迫 “筛选”该信息,从而将选择范围缩小到一组问题的服务源。 las,在该领域中,机器比人类快得多,不易出错,并且其结果更具可重复性。

我认为traceview方法错误的另一个原因是,它不适用于假设的调试。 从本质上讲,调试是一个从假设开始的迭代过程,然后使用不同的向量,结论/概括以及对假设真相的进一步评估,检查从系统收到的各种观察结果和事实。

快速廉价地检验假设并相应改善心理模型的能力是调试的基石 。 任何调试工具都应该是交互式的,并缩小搜索空间,或者在错误跟踪的情况下,允许用户返回并专注于系统的另一个区域。 理想的工具将主动执行此操作,立即将用户的注意力吸引到潜在有问题的区域。

tracetraceview不能称为交互式界面工具。 使用它时,最好的办法是检测某个延迟增加的特定来源,并查看与其相关的所有标记和日志。 这无助于工程师识别流量模式 ,例如延迟分布的细节,或检测不同测量之间的相关性。 通用跟踪分析可以解决其中一些问题。 确实, 有一些使用机器学习来成功分析的示例,以识别异常跨度并识别可能与异常行为相关的标签子集。 不过,我还没有看到令人信服的可视化结果,这些结果是通过将机器学习或数据分析应用于跨度而得出的,这些跨度与traceview或DAG(有向无环图)明显不同。

跨度太低


traceview的根本问题是,对于延迟分析和根本原因分析, 跨度太低级的原语。 这就像分析单个处理器命令以消除异常一样,因为它知道有很多更高级的工具(例如backtrace),使用起来更方便。

此外,我将自由声明以下内容:理想情况下,我们不需要完整了解请求的生命周期中发生的情况,而现代跟踪工具代表该情况。 取而代之的是,需要某种形式的高级抽象,其中包含有关出了什么问题的信息 (类似于回溯)以及一些上下文。 除了观察整个轨迹,我更喜欢在发生有趣或不寻常的情况时查看其中的一部分 。 当前,搜索是手动进行的:工程师接收到一条迹线,并独立分析跨度以寻找有趣的东西。 人们盯着跨度以寻找可疑活动的希望的方式根本无法扩展(尤其是当他们必须理解以不同跨度编码的所有元数据时,例如跨度ID,RPC方法名称,跨度持续时间) ',日志,标签等)。

Traceview的替代品


当可以以某种方式可视化跟踪结果以使他们对系统的互连部分中发生的事情有个不小的了解时,它是最有用的。 在这种情况下,调试过程基本上保持惰性,并取决于用户注意到正确的相关性,检查系统的正确部分或将镶嵌图组装在一起的能力,这与帮助用户提出这些假设的工具不同。

我不是视觉设计师或UX专家,但是在下一节中,我想分享一些有关这种可视化效果的想法。

专注于特定服务


在业界围绕SLO(服务水平目标)和SLI(服务水平指标)的思想进行整合的环境中,各个团队首先应监视其服务与这些目标的相关性似乎是合理的。 因此, 面向服务的可视化最适合此类团队。

跟踪,尤其是没有采样的跟踪,是有关分布式系统每个组件的信息的仓库。 可以将这些信息提供给一个棘手的处理程序,该处理程序将向用户提供面向服务的查找结果,这些查找结果可以预先检测-甚至在用户查看跟踪之前:

  1. 延迟分布图仅用于高度区分的请求(异常请求)
  2. 未达到SLO服务目标的情况的延迟分布图;
  3. 查询中最“常见”,“有趣”和“奇怪”的标签,这些标签经常重复出现
  4. 对于服务依赖性未达到设定的SLO目标的情况的延迟细分;
  5. 细分各种下游服务的延迟。

内置指标根本无法回答其中一些问题,从而迫使用户仔细研究跨度。 结果,我们对用户具有极其敌对的机制。

在这方面,出现了一个问题:由不同团队控制的各种服务之间的复杂交互作用如何? traceview是否被认为是解决这种情况的最合适工具?

移动开发人员,无状态服务的所有者,托管有状态服务的所有者(如数据库)和平台所有者可能对分布式系统的另一种观点感兴趣; 对于这些根本不同的需求, traceview是一种过于通用的解决方案。 即使在非常复杂的微服务体系结构中,服务所有者也不需要深入了解超过两个或三个上游和下游服务。 本质上,在大多数情况下,用户只需要回答有关有限服务集的问题。

就像为了仔细研究而通过放大镜看一小部分服务。 这将使用户可以提出有关这些服务及其直接依存关系之间的复杂交互的更为紧迫的问题。 这类似于服务领域中的回溯,在该领域中,工程师知道错误所在,并且对周围服务中正在发生的事情有一些了解,以了解其原因

我要推广的方法与基于traceview的自上而下的方法完全相反,当分析从整个轨迹开始,然后逐渐下降到各个跨度时。 相反,自下而上的方法始于对事故潜在原因附近的一小块区域进行分析,然后在必要时扩大搜索空间(可能需要其他团队的参与来分析更广泛的服务)。 第二种方法更适合于快速检验初始假设。 在获得特定结果之后,将有可能继续进行更加集中和详细的分析。

拓扑建筑


如果用户知道哪个服务或服务组导致延迟增加或是错误来源,则与特定服务关联的视图将非常有用。 但是,在复杂的系统中,在故障期间识别入侵者可能不是一件容易的事,尤其是在没有从服务接收到错误消息的情况下。

建立服务拓扑对于确定哪个服务显示出错误率激增或等待时间增加,从而导致服务性能显着下降非常有帮助。 说到构建拓扑,我并不是指以死亡之星的形式显示系统中可用的且以其体系结构图而闻名的每个服务的服务图 。 这样的表示并不比基于有向无环图的跟踪视图更好。 相反,我希望看到基于某些属性(例如错误率,响应时间或任何用户定义的参数,可以帮助澄清特定可疑服务情况)的动态生成的服务拓扑

让我们来看一个例子。 想象一个假设的新闻站点。 首页服务与Redis,推荐服务,广告服务和视频服务进行通信。 视频服务从S3获取视频,并从DynamoDB获取元数据。 推荐服务从DynamoDB接收元数据,从Redis和MySQL下载数据,将消息写入Kafka。 广告服务从MySQL接收数据并将消息写入Kafka。

以下是此拓扑的示意图(许多商业路由程序构建该拓扑)。 如果您需要了解服务的依赖性,它会派上用场。 但是,在调试过程中,当某个服务(例如,视频服务)显示出增加的响应时间时,这种拓扑不是很有用。


假新闻网站服务计划

下图会更好。 中央有一个问题服务(视频) 。 用户立即注意到他。 从该可视化中可以清楚地看出,由于S3的响应时间增加,视频服务无法正常工作,从而影响了主页的部分下载速度。


仅显示“有趣”服务的动态拓扑

动态生成的拓扑方案可能比静态服务图更有效,尤其是在灵活的,可自动伸缩的基础结构中。 比较和对比服务拓扑的能力使用户可以提出更相关的问题。 有关系统的更精确的问题更有可能导致人们更好地了解系统的工作方式。

比较显示


另一个有用的可视化是比较显示。 迹线当前不太适合并行比较,因此通常会比较跨度 。 而本文的主要思想恰恰是跨度太低,无法从跟踪结果中提取最有价值的信息。

比较两个trace'ov根本不需要新的可视化。 实际上,诸如直方图之类的东西表示与traceview相同的信息就足够了。 令人惊讶的是,即使这种简单的方法也比单独研究两条痕迹能带来更多的成果。 可视化 聚合中痕迹比较的功能将更加强大。 看看最近部署的数据库配置随着GC(垃圾收集)的变化如何影响下游服务在几小时内的响应时间将非常有用。 如果我在这里描述的内容看起来像是使用跟踪结果对各种服务中基础结构更改的影响进行的A / B分析,那么您与事实相距不远。

结论


我不怀疑跟踪本身的用处。 我真诚地相信,没有其他方法可以像跟踪中所包含的那样收集丰富,随意和上下文相关的数据。 , . , traceview-, , , trace'. , , .

, , . , , . , production , , , , .

, , , , , . , , , trace' span'.

( UI). , , . , . . .

译者的PS


另请参阅我们的博客:

Source: https://habr.com/ru/post/zh-CN460365/


All Articles