本教程的目的是为 OpenTelemetry 中的跨度链接提供实用且易于理解的指南。
它旨在帮助开发人员,特别是那些使用复杂和异步系统的开发人员,了解跨度链接是什么,它们与传统跟踪中的父子关系有何不同,以及为什么它们对于更好的跟踪关联很有价值。
在本指南结束时,您将获得有效使用跨度链接来跟踪分布式系统内交互所需的技能,从而提高可观察性和调试能力。
过去,应用程序通常是整体式的,这意味着每个进程或功能都作为一个服务器上的单个单元执行。监控此类应用程序非常简单。
例如:如果出现问题,您可以查看该服务器的日志来识别问题。然而,微服务的兴起改变了这种简单性。
现在,现代应用程序通常由数十个甚至数百个协同工作的较小的独立服务组成。例如:当您使用移动应用程序下订单时,可能会有单独的服务来处理用户身份验证、处理付款、管理库存和发送确认电子邮件。
这些服务并不总是位于同一服务器上,甚至可以通过互联网进行通信,这增加了跟踪与应用程序交互时发生的情况的复杂性。
这就是分布式跟踪的用武之地。将分布式跟踪视为一种在单个请求经过复杂应用程序中的各种服务时跟踪单个请求的方法。它跟踪请求通过复杂系统的旅程。
在现代应用程序中,请求经常通过多个服务传输,每个服务运行在不同的机器上。分布式跟踪帮助我们可视化这一过程,从而更容易识别瓶颈和错误。
它就像一张侦探地图,将流程每个步骤之间的点连接起来,向您显示每个部分花费了多长时间以及出现问题的位置。当您查看跟踪时,您会看到请求如何通过不同服务移动的时间线,从而更容易识别速度减慢、错误或失败。
代码库
这是本教程的代码存储库:
[https://github.com/Noibisjunior/Span-Links-in-OpenTelemetry]
OpenTelemetry 是实现这种可见性的关键角色。它是一个开源可观察性框架,允许开发人员从应用程序收集日志、指标和跟踪等数据。它作为一个工具集,用于捕获有关服务内部发生的情况的详细信息。
在现代可观测性的世界中,OpenTelemetry 可帮助您了解分布式应用程序的性能和运行状况。它就像一座桥梁,从各种服务收集数据并将其发送到 SigNoz 等工具,您可以在其中可视化正在发生的情况。这使得 OpenTelemetry 对于识别瓶颈、跟踪错误和确保应用程序顺利运行非常有价值。
通过将 OpenTelemetry 与分布式跟踪结合使用,您可以全面了解应用程序的行为方式,从而更轻松地诊断问题并改善用户体验。
随着软件,尤其是分布式系统变得越来越复杂,理解其内部工作原理成为一项具有挑战性的任务。这就是 OpenTelemetry 的跨度可以轻松解决挑战的地方。
跨度是 OpenTelemetry 跟踪系统中的基本工作单元。它是应用程序中发生的单个操作或事件。
它捕获该操作期间发生的情况、花费的时间以及任何相关详细信息,例如操作是否成功或失败。
例如,假设您的应用程序处理用户请求:
跨度的关键属性:
单独使用时,跨度很有用,但是当它们一起形成轨迹时,它们会更有效。
跟踪是跨度的集合,代表请求或操作流经系统时的整个过程。
让我们回到我们的用户请求示例:
当请求进入系统时,跟踪开始,并创建根跨度。当请求触发数据库查询时,数据库交互跨度链接到根跨度,表明它是同一进程的一部分。
用于调用其他服务的额外跨度被添加到跟踪中。通过查看此跟踪,您可以大致了解请求如何通过系统的不同部分。它不仅可以帮助您了解发生了什么,还可以帮助您了解应用程序的不同部分是如何连接的。
查明问题:跨度可帮助您放大出现问题的位置。如果请求很慢,span 可以告诉您是否是数据库查询、网络调用或进程的其他部分导致了延迟。您可以看到哪个跨度花费的时间比预期更长,从而更容易找到瓶颈。
构建上下文:每个跨度都包含上下文信息,例如开始时间、结束时间和自定义标签(属性)。此数据可让您深入了解系统中特定时刻发生的情况,例如请求中涉及的特定用户 ID 或执行的查询。
创建关系:Span 彼此之间存在关系,通常采用父子结构。根跨度是父跨度,后续跨度是其子跨度。这一结构可帮助您了解事件发生的顺序以及它们如何相互依赖。这就像在您的应用程序中查看操作的家谱。
调试分布式系统:对于具有微服务的应用程序(其中不同的服务处理请求的不同部分),跨度尤其重要。它们可以帮助您跟踪在服务之间移动的请求,即使这些服务运行在不同的服务器或不同的数据中心中。这是理解服务之间复杂交互的关键。
什么是跨度链接?
在分布式系统的世界中,多个服务协同工作来处理用户请求,跟踪就像侦探的地图,它显示了请求在这些服务中移动时所采取的路径。这个旅程中的每一个活动称为一个跨度,一个完整的旅程称为一个踪迹。
传统上,跨度是使用父子关系连接的。将它们想象成一个家谱:父跨度启动一个流程(例如向另一个服务发出请求),子跨度代表由此发生的活动(例如处理请求的服务)。这是表示请求流的一种简单方法。
但是当两个跨度相关但它们并不完全适合父子层次结构时会发生什么?这就是跨度链接的用武之地。
跨度链接允许您连接两个相关但没有直接父子关系的跨度。它就像分布式系统中两个活动之间的“引用”或“捷径”。
例如,假设您有一个用户发出触发多个独立进程的请求,例如发送电子邮件和写入数据库。这些进程不是彼此的子活动;而是彼此的子活动。它们同时发生。使用跨度链接,您可以指示电子邮件发送跨度和数据库写入跨度与同一个初始用户请求相关,即使它们在父子概念中没有直接连接。
亲子关系:这是一个简单的事件链。用户发送请求(父级),该请求触发在数据库(子级)中创建记录。如果没有父跨度,子跨度就不会存在,这使其成为直接结果。
跨度链接:这些更像是在某些上下文中相关的活动之间绘制虚线,但不遵循直接的操作链。它们提供了一种表达方式:“这些事情是相关的,尽管其中一个并没有直接导致另一个。”跨度链接非常适合表示相互作用但不严格分层的并行活动或事件。
跨度链接在复杂和异步系统中的重要性
跨度链接在复杂和异步系统中特别有价值,在这些系统中,事件流并不总是遵循清晰的父子路径。以下是一些实际使用场景;
异步工作流程:
想象一个从后台作业开始的用户请求(例如生成报告)。初始请求完成,但报告生成仍在后台继续。
通过跨度链接的实现,您可以将初始请求跨度与后台作业跨度相关联,即使它们不遵循直接的父子模式。
微服务通信:
在微服务架构中,服务通常以不严格分层的方式相互通信。
例如,用户操作可以触发多个服务来同时处理数据的不同部分。 Span 链接允许您跟踪这些独立和相关的 Span,作为更广泛的工作流程的一部分。
批处理:如果您正在处理批量数据,其中批次中的每个项目都会生成自己的范围,则可以使用范围链接将这些范围连接回原始批处理。
这样可以更轻松地跟踪批次的整个生命周期,并了解各个项目如何与主流程相关。
它充当代码和可观察性系统之间的桥梁,使收集有关应用程序运行方式的详细信息成为可能。
将 OpenTelemetry 想象为一个“相机”,用于捕获应用程序操作的快照。通过将 SDK 集成到您的应用中,您可以放置此摄像头来记录幕后发生的事情。
您需要使用应用程序的编程语言(例如 Python、Java、JavaScript)安装 SDK。
(2) SigNoz 设置:SigNoz 是一个开源可观察性工具,可让您可视化和分析通过 OpenTelemetry 收集的数据。
将 SigNoz 视为“控制室”,您可以在其中查看 OpenTelemetry 设置捕获的镜头。您可以在这里清楚地了解应用程序中的跟踪和指标。
您需要设置一个 SigNoz 实例,这涉及将其部署在本地计算机或服务器上,通常使用 Docker 或 Kubernetes。
SigNoz 有助于将原始数据转换为可视化效果,例如图形和图表,让您更轻松地了解应用程序内部发生的情况。
痕迹:
简单来说,跟踪就像用户或请求与应用程序交互时发生的情况的“故事”。它捕获由于该交互而发生的所有操作,从初始请求到可能涉及的所有服务和数据库。
想象一个用户单击您网站上的按钮。痕迹会记录接下来发生的每一步。
跨度:
跨度是跟踪故事中的“章节”。每个跨度代表作为跟踪的一部分发生的特定操作或任务。
例如,如果跟踪捕获了用户请求的整个过程,则跨度可以代表单个步骤,例如查询数据库或调用外部 API。
每个跨度都有开始和结束时间,为您提供有关每个步骤花费多长时间的精确详细信息。这使得更容易查明任何速度减慢或错误。
使用 OpenTelemetry 检测代码:
检测是向应用程序添加代码以收集可观测性数据的过程。通过使用 OpenTelemetry 检测您的代码,这通常涉及在您想要创建跟踪和跨度的位置添加几行代码。
例如,您可以检测数据库查询以查看需要多长时间,或检测用户登录过程以跟踪其性能。
OpenTelemetry SDK 提供可直接集成到代码中的库和函数,使这一切变得更容易。可以将其想象为将跟踪器连接到机器的各个部分以监控它们如何协同工作。
让我们看一个 Python 中的基本示例。我们将使用 OpenTelemetry SDK 创建两个跨度并将它们链接在一起。
from opentelemetry import trace from opentelemetry.trace import Link from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import SimpleSpanProcessor, ConsoleSpanExporter # Set up the tracer provider and span exporter trace.set_tracer_provider(TracerProvider()) tracer = trace.get_tracer(__name__) span_processor = SimpleSpanProcessor(ConsoleSpanExporter()) trace.get_tracer_provider().add_span_processor(span_processor) # Create the first span, simulating some work being done with tracer.start_as_current_span("span_one") as span_one: span_one.add_event("Processing order") order_id = "12345" # Imagine this as an order ID we're processing # Create a second span with a link to the first span with tracer.start_as_current_span("span_two", links=[Link(span_one.get_span_context())]) as span_two: span_two.add_event("Updating order status") # Simulate some additional work here print("Order ID: {order_id} has been updated.") print("Tracing complete")
上述 Python 代码片段的说明
设置跟踪器提供程序:
上面的代码片段以跟踪器提供程序开始,它管理跨度的创建。
这对于 OpenTelemetry 了解如何处理跨度至关重要。我们还配置了 SimpleSpanProcessor 和 ConsoleSpanExporter 以将跨度数据打印到控制台。这有助于我们了解正在创建的跨度类型以及它们是如何链接的
.
(2) 创建第一个 Span (span_one):
使用tracer.start_as_current_span方法,我们创建一个名为span_one的span。这可以代表任何操作,例如处理订单。
在此范围内,我们添加一个事件处理顺序来指示在该特定时间点发生的情况。
我们还模拟了将在下一个跨度中使用的订单 ID (order_id = "12345")。
(3) 创建带有链接的第二个 Span (span_two):
在这里,我们启动了另一个名为 span_two 的跨度来表示不同但相关的操作,例如更新订单的状态。
注意 links 参数。我们使用 Link(span_one.get_span_context()) 在 span_two 和 span_one 之间创建链接。
这告诉 OpenTelemetry,“虽然这些操作不是父子关系,但它们是相关的。”
在span_two中,我们添加了另一个事件,更新订单状态,并模拟一些工作,例如更新数据库中的订单状态。
(4) 输出:
当您运行此代码时,您将在 ConsoleSpanExporter 的控制台中看到输出,其中显示两个跨度以及它们之间的链接。这有助于可视化这两个跨度在跟踪中如何相互关联。
(1) 缺失的跨度上下文:
错误:如果您尝试在不调用 span_one.get_span_context() 的情况下创建链接,您将收到错误,因为 OpenTelemetry 需要有效的跨度上下文才能创建链接。
解决方案:始终确保在创建链接时传递跨度上下文。使用活动范围的 .get_span_context() 方法。
(2) 链接未开始或结束的 Span:
错误:如果您尝试创建指向尚未开始或已经结束的跨度的链接,您可能会遇到无法识别该链接的问题。
解决方案:创建链接时,确保您链接到的跨度处于活动状态。使用已经结束的跨度创建链接可能会导致跟踪显示方式出现意外行为。
(3) 性能考虑因素:
性能问题:链接太多跨度会增加跟踪数据的开销,导致高流量系统中的性能下降。
解决方案:有选择地使用链接。仅当存在需要可视化或分析的有意义的关系时,才会出现链接跨度。对于高流量环境,您可以使用 OpenTelemetry 的采样选项来减少捕获的跟踪数据量。
在使用分布式系统时,了解系统不同部分如何通信至关重要。 OpenTelemetry 中的跨度链接 在连接可能没有直接父子关系的跟踪方面发挥着至关重要的作用,可以更清晰地了解请求如何流经您的服务。
为什么可视化跨度链接很重要
想象一下您的应用程序有一个支付服务,当支付成功时会触发通知服务。虽然这些服务交互,但它们可能不共享直接的父子关系。
跨度链接允许您关联这些交互,显示付款触发了通知。可视化这些链接可以帮助您更全面地了解独立服务如何实时关联。
通过设置 SigNoz 来可视化这些跨度链接,您可以更深入地了解应用程序的行为。
以下是如何配置 SigNoz 来捕获和查看 Span 链接
第 1 步:确保 SigNoz 已正确安装
第 2 步:配置 OpenTelemetry SDK 以包含您的 Span 链接
下一步是确保您的 OpenTelemetry SDK 配置为将跨度链接数据发送到 SigNoz。在应用程序的代码中,您需要添加跨度链接作为跟踪逻辑的一部分。
这是 Python 编程语言的代码片段:
from opentelemetry import trace from opentelemetry.trace import Link from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import SimpleSpanProcessor, ConsoleSpanExporter # Set up the tracer provider and span exporter trace.set_tracer_provider(TracerProvider()) tracer = trace.get_tracer(__name__) span_processor = SimpleSpanProcessor(ConsoleSpanExporter()) trace.get_tracer_provider().add_span_processor(span_processor) # Create the first span, simulating some work being done with tracer.start_as_current_span("span_one") as span_one: span_one.add_event("Processing order") order_id = "12345" # Imagine this as an order ID we're processing # Create a second span with a link to the first span with tracer.start_as_current_span("span_two", links=[Link(span_one.get_span_context())]) as span_two: span_two.add_event("Updating order status") # Simulate some additional work here print("Order ID: {order_id} has been updated.") print("Tracing complete")
上述Python代码片段的解释
我们首先配置 TracerProvider 来处理应用程序中的跟踪并设置跨度处理器。
OTLPSpanExporter 用于使用 OTLP 协议将跨度发送到 SigNoz 的后端。
如果您没有在本地运行 SigNoz,请将 http://localhost:4317 替换为适当的 SigNoz 端点。
其次,创建跨度和链接:
首先创建parent_span,代表一个初始操作(例如,用户请求)。我们使用 get_span_context() 提取parent_span的上下文,这允许我们将另一个span链接到它。
然后创建linked_span,并添加一个链接来引用parent_span的上下文。这意味着虽然 linked_span 不是 Parent_span 的直接子级,但它与之相关。
最后,将数据发送到 SigNoz:
使用BatchSpanProcessor处理span数据,确保span数据高效发送到SigNoz。
trace.get_tracer_provider().shutdown() 在最后调用,以确保在程序退出之前刷新并导出任何剩余的跨度。
第 3 步:更新 SigNoz 配置以跟踪数据
from opentelemetry import trace from opentelemetry.trace import SpanKind, Link from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter # Set up the tracer provider and add a span processor trace.set_tracer_provider(TracerProvider()) tracer = trace.get_tracer(__name__) # Configure the exporter to send spans to SigNoz using the OTLP exporter otlp_exporter = OTLPSpanExporter(endpoint="http://localhost:4317", insecure=True) span_processor = BatchSpanProcessor(otlp_exporter) trace.get_tracer_provider().add_span_processor(span_processor) # Create two spans, linking the second span to the context of the first with tracer.start_as_current_span("parent_span") as parent_span: # Simulate some logic for the parent_span print("Parent span is active") # Get the context of the parent span parent_context = parent_span.get_span_context() # Create a linked span and add a link to the parent span's context with tracer.start_as_current_span( "linked_span", links=[Link(parent_context)] ) as linked_span: # Simulate some logic for the linked_span print("Linked span is active") # Ensure all spans are flushed before exiting the application trace.get_tracer_provider().shutdown()
第 4 步:在 SigNoz 中可视化跨度链接
应用程序将带有跨度链接的跟踪数据发送到 SigNoz 后,您可以通过以下方式可视化这些链接:
第 5 步:调整视图以获得清晰度
为了获得完美的可视化效果,您需要注意以下几点:
后续步骤
在本教程中,我们学习了如何使用跨度链接来跟踪分布式系统内的交互
在下一个教程中,我们将学习使用 Span 链接的最佳实践和高级用例
以上是使用 OpenTelemetry 和 Signoz 掌握通过 Span Links 进行跟踪分析(实用指南)的详细内容。更多信息请关注PHP中文网其他相关文章!