十年前,基本上只有学者和少数大型互联网公司在认真思考分布式追踪。如今,它已成为任何采用微服务的组织的基本要求。理由已充分确立:微服务以令人惊讶且往往壮观的方式失败,而分布式追踪是描述和诊断这些故障的最佳方法。
话虽如此,如果您着手将分布式追踪集成到您自己的应用程序中,您将很快意识到术语“分布式追踪”对不同的人意味着不同的事物。此外,追踪生态系统中充斥着部分重叠的项目,这些项目具有相似的目标。本文描述了分布式追踪中四个(可能)独立的组件,以及它们如何协同工作。
分布式追踪:心智模型
大多数追踪的心智模型都源于 Google 的 Dapper 论文。OpenTracing 使用类似的名称和动词,因此我们将从该项目中借用这些术语
- 追踪 (Trace): 事务在分布式系统中流转的描述。
- Span: 命名、定时的操作,表示工作流程的一部分。Span 接受键值标签以及附加到特定 Span 实例的细粒度的、带时间戳的、结构化日志。
- Span 上下文 (Span context): 伴随分布式事务的追踪信息,包括当它通过网络或消息总线从服务传递到服务时。Span 上下文包含追踪标识符、Span 标识符以及追踪系统需要传播到下游服务的任何其他数据。
如果您想深入了解此心智模型的详细描述,请查看 OpenTracing 规范。
四个主要部分
从应用层分布式追踪系统的角度来看,现代软件系统如下图所示
现代软件系统中的组件可以分解为三个类别
- 应用程序和业务逻辑:你的代码。
- 广泛共享的库:别人的代码。
- 广泛共享的服务:别人的基础设施。
这三个组件具有不同的需求,并驱动了分布式追踪系统的设计,该系统负责监控应用程序。由此产生的设计产生了四个重要部分
- 追踪检测 API:用于装饰应用程序代码。
- 网络协议:在 RPC 请求中与应用程序数据一起发送的内容。
- 数据协议:异步(带外)发送到你的分析系统的内容。
- 分析系统:用于处理追踪数据的数据库和交互式用户界面。
为了进一步解释这一点,我们将深入探讨驱动此设计的细节。如果您只是想要我的建议,请跳到最后的四个主要解决方案。
需求、细节和解释
应用程序代码、共享库和共享服务具有显著的运营差异,这严重影响了检测它们的需求。
检测应用程序代码和业务逻辑
在任何特定的微服务中,微服务开发者编写的大部分代码都是应用程序或业务逻辑。这是定义领域特定操作的代码;通常,它包含任何特殊的、独特的逻辑,这些逻辑证明了首先创建新微服务的合理性。几乎根据定义,此代码通常不共享或以其他方式存在于多个服务中。
话虽如此,您仍然需要理解它,这意味着它需要以某种方式进行检测。一些监控和追踪分析系统使用黑盒代理自动检测代码,另一些则期望显式的“白盒”检测。对于后者,抽象追踪 API 为微服务特定的应用程序代码提供了许多实际优势
- 抽象 API 允许您更换新的监控工具,而无需重写检测代码。您可能想要更换云提供商、供应商和监控技术,而一大堆不可移植的检测代码将为该过程增加有意义的开销和摩擦。
- 事实证明,检测还有其他有趣的用途,超出生产监控范围。现有项目使用相同的追踪检测来支持测试工具、分布式调试器、“混沌工程”故障注入器和其他元应用程序。
- 但最重要的是,如果您想将应用程序组件提取到共享库中会怎么样? 这将我们引向
检测共享库
大多数应用程序中存在的实用代码——处理网络请求、数据库调用、磁盘写入、线程、排队、并发管理等的代码——通常是通用的,不特定于任何特定应用程序。此代码被打包成库和框架,然后安装在许多微服务中,并部署到许多不同的环境中。
这是真正的区别:对于共享代码,其他人是用户。大多数用户具有不同的依赖关系和操作风格。如果您尝试检测此共享代码,您将注意到几个常见问题
- 您需要一个 API 来编写检测。但是,您的库不知道正在使用什么分析系统。有很多选择,并且在同一应用程序中运行的所有库都不能做出不兼容的选择。
- 从请求头注入和提取 Span 上下文的任务通常落在 RPC 库上,因为这些包封装了所有网络处理代码。但是,共享库需要知道每个应用程序正在使用哪种追踪协议。
- 最后,您不想在您的用户身上强制冲突的依赖关系。大多数用户具有不同的依赖关系和操作风格。即使他们使用 gRPC,它会是你绑定的 gRPC 的相同版本吗?因此,您的库为追踪引入的任何监控 API 都必须没有依赖关系。
因此,抽象 API,它 (a) 没有依赖关系,(b) 与网络协议无关,并且 (c) 与流行的供应商和分析系统一起工作,应该是检测共享库代码的要求。
检测共享服务
最后,有时整个服务——或微服务集——是足够通用的,以至于被许多独立的应用程序使用。这些共享服务通常由第三方托管和管理。示例可能包括缓存服务器、消息队列和数据库。
重要的是要理解,从应用程序开发者的角度来看,共享服务本质上是“黑盒”。 不可能将你的应用程序的监控解决方案注入到共享服务中。相反,托管服务通常运行自己的监控解决方案。
四个主要解决方案
因此,抽象的追踪 API 将帮助库发出数据并注入/提取 Span 上下文。标准网络协议将帮助黑盒服务互连,标准数据格式将帮助独立的分析系统整合它们的数据。让我们看看一些有希望的选项来解决这些问题。
追踪 API:OpenTracing 项目
如上所示,为了检测应用程序代码,需要一个追踪 API。并且为了将该检测扩展到共享库(Span 上下文注入和提取主要发生在其中),API 必须以某些关键方式进行抽象。
OpenTracing 项目旨在为库开发者解决这个问题。OpenTracing 是一个厂商中立的追踪 API,它没有依赖关系,并且正在迅速获得大量监控系统的支持。这意味着,越来越多的,如果库在出厂时内置了原生的 OpenTracing 检测,当监控系统在应用程序启动时连接时,追踪将自动启用。
就我个人而言,作为一个编写、发布和运营开源软件超过十年的人,在 OpenTracing 项目上工作并最终解决这个可观察性难题,我感到非常满意。
除了 API 之外,OpenTracing 项目还维护着一个不断增长的贡献检测列表,其中一些可以在 这里 找到。如果您想参与进来,无论是通过贡献一个检测插件,原生检测你自己的 OSS 库,还是只是想问一个问题,请在 Gitter 上找到我们并打个招呼。
网络协议:trace-context HTTP 标头
为了使监控系统能够互操作,并在从一个监控系统更改为另一个监控系统时减轻迁移问题,需要一个标准网络协议来传播 Span 上下文。
w3c 分布式追踪上下文社区组 正在努力定义这个标准。目前,重点是定义一组标准 HTTP 标头。规范的最新草案可以在 这里 找到。如果您对此组有疑问,邮件列表 和 Gitter 聊天室 是获取答案的好去处。
数据协议(尚不存在!!)
对于黑盒服务,在这些服务中,不可能安装追踪器或以其他方式与程序交互,需要数据协议来从系统中导出数据。
关于此数据格式和协议的工作目前处于早期阶段,主要发生在 w3c 分布式追踪上下文工作组的背景下。特别感兴趣的是在标准数据模式中定义更高级别的概念,例如 RPC 调用、数据库语句等。这将允许追踪系统可以假设哪些类型的数据可用。OpenTracing 项目也在努力解决这个问题,方法是开始定义 标准标签集。计划是这两个努力相互配合。
请注意,目前有一个可用的中间地带。对于应用程序开发者操作但不希望编译或以其他方式对其执行代码修改的“网络设备”,动态链接可以提供帮助。这方面的主要示例是服务网格和代理,例如 Envoy 或 NGINX。对于这种情况,兼容 OpenTracing 的追踪器可以编译为共享对象,然后在运行时动态链接到可执行文件中。此选项目前由 C++ OpenTracing API 提供。对于 Java,OpenTracing Tracer 解析器 也在开发中。
这些解决方案适用于支持动态链接且由应用程序开发者部署的服务。但从长远来看,标准数据协议可能会更广泛地解决这个问题。
分析系统:一种从追踪数据中提取见解的服务
最后但并非最不重要的一点是,现在有大量的追踪和监控解决方案。已知与 OpenTracing 兼容的监控系统列表可以在 这里 找到,但还有更多选择。我鼓励您研究您的选项,并且我希望您发现本文提供的框架在比较选项时很有用。除了根据其运营特性评估监控系统(更不用说您是否喜欢 UI 和功能),请确保您考虑上述三个主要部分、它们对您的相对重要性,以及您感兴趣的追踪系统如何为它们提供解决方案。
结论
最后,每个部分的重要性在很大程度上取决于你是谁以及你正在构建哪种系统。例如,开源库作者对 OpenTracing API 非常感兴趣,而服务开发者往往对 Trace-Context 规范更感兴趣。当有人说一个部分比另一个部分更重要时,他们通常意味着“一个部分对我来说比另一个部分更重要。”
然而,现实情况是:分布式追踪已成为监控现代系统的必需品。在为这些系统设计构建块时,古老的做法——“尽可能解耦”——仍然适用。干净地解耦的组件是保持灵活性和向前兼容性的最佳方式,当构建一个像分布式监控系统这样跨领域的系统时。
感谢阅读!希望现在当您准备在自己的应用程序中实施追踪时,您有一个指南来理解他们正在谈论哪些部分,以及它们如何协同工作。
想了解更多?报名参加 5 月的 KubeCon EU 或 12 月的 KubeCon North America。
评论已关闭。