Distributed Tracing 基本介绍
起源
分布式追踪技术的兴起,主要源于现代软件架构向微服务和云原生方向的转变。在单体应用时代,系统的复杂度相对较低,请求处理路径清晰,调试和故障定位较为直观。然而,随着业务规模的扩大和技术演进,单体应用逐渐分解为多个独立的服务,形成了复杂的微服务架构。在这种架构下,一个用户请求可能需要跨过数十个甚至上百个服务节点,传统的日志记录和监控方式难以满足对系统行为的全面洞察和问题定位需求。
2006年,Google内部开发了一种名为Dapper的分布式追踪系统,用于解决其大规模分布式系统中的追踪问题。Dapper能够自动收集和分析跨服务调用的详细信息,为工程师提供了前所未有的系统可见性。Dapper的成功应用,启发了业界对于分布式追踪技术的探索和实践,随后涌现出如Jaeger、Zipkin、Pinpoint、Skywalking、OpenTelemetry等开源分布式追踪框架,推动了该领域的发展和普及。
基本概念
分布式追踪的核心理念是追踪和记录服务间调用的完整链路信息,以便于理解和诊断分布式系统的运行状况。它主要涉及以下几个关键概念:
- TraceId: 每一次调用分配一个唯一的ID(一般叫traceId)
- Span(跨度):是Distributed Tracing中最重要的概念,一般表示一次操作的开始和结束,可以是一个数据库查询、RPC调用或任何具有明确起止时间的操作。其包含几个关键字段如下
- traceId: 同一次业务调用的不同span的traceId相同。
- spanId: 每个Span都有一个唯一的ID。
- parentSpanId: 以及一个可选的父Span ID
- spanName: 用以标识一次操作的名称
- duration:耗时。
- attributes:可以拓展的若干个k、v组合,用户给span附着一些额外信息。
- Root Span(根跨度):根跨度代表追踪的起始点,通常是用户的初始请求。
- Trace(追踪):是一系列相关Spans的集合,这些span有相同的TraceId,共同描述了一个完整的业务请求或操作的执行流程。Traces通过Span之间的父子关系串联起来,形成树状结构,展现了请求在不同服务间的流转情况。
- Service(服务):指参与分布式系统中特定功能实现的一个组件。每个服务都可以产生和接收Spans,从而被纳入到Traces中进行追踪。
- Sampler(采样器):用于决定哪些Trace应该被完整记录和存储。由于分布式系统中产生的Traces数量巨大,不加筛选地保存所有数据是不现实的,因此采样策略成为控制存储成本和保证关键信息不丢失的关键。
- SpanContext (上下文):上下文是trace信息的载体,一般包含当前span的traceId和spanId,在跨进程调用时,调用方的SpanContext往往需要序列化并传递给被调用方,被调用方还原上下文之后再依据还原的上下文生成新的SpanContext,保证跨进程的不同Span父子关系符合预期。
下面用一个简单的例子并结合上述的关键概念说明Trace的工作原理
一次典型的业务调用如下图所示,用户发起http请求想要查看自己的订单列表,该接口首先会调用鉴权中心的服务进行鉴权,鉴权通过后路由到对应的controller中处理,在controller中执行简单的数据库查询之后将结果封装并返回。
对上面这个简单的业务链路的时序图关键节点均建模生成Span,并根据他们在时序图中的调用关系组装Span父子关系,就得到下图所示的一次业务调用对应的链路图, 下图这种展现形式只是Tracing数据的一种常见展现形式,被称为火焰图。其中每一个长方形代表一个Span,每个长方形的长度代表了该Span的耗时长短,不同长方形之间的箭头指向代表了他们之间的父子关系。
可以发现,通过下图这种形式,可以很清晰明了的看清楚复杂业务场景下的调用关系,便于问题快速定位。
应用场景
基础的Tracing数据,常常被用于以下几个场景:
- 复杂链路下问题快速定界、定位。
- 服务之间依赖分析、梳理以及进一步的强弱依赖确定、服务治理。
基础的Tracing数据在实际进行根因定位时候往往存在最后一公里问题,所以实际业务使用中,往往将Tracing数据和其他数据结合完成根因诊断:
- 和日志结合快速定位业务问题,通过traceId快速从海量日志中查找关键日志。
- 和profiling数据关联,解决trace埋点盲区导致的慢调用无法定位根因问题。
通过对Tracing数据进行二次聚合可以得到服务的RED数据,常用于下述场景:
- 配置服务可用性大盘巡检服务健康状况。
- 配置报警及时发现问题。
基于Tracing系统的的全链路baggage透传能力,根据不同的场景需求对业务流量进行染色:
- 依据业务参数对流量进行染色,实现从业务角度查看RED指标,比如对于下单接口的商品类型对流量进行染色,并在指标聚合时记录商品类型维度,可以查看不同商品类型的RED指标。
- 依据特定请求头对流量进行染色,保证被染色流量路由到特定机器,实现全链路灰度等能力。
主流开源实现
随着多年的发展,在最开始的Dapper 论文中的Distributed Tracing原型基础上,社区涌现出了很多被广泛使用和验证的开源项目,他们各自有各自擅长的特点,下面分别介绍。
Jaeger:
- 简介: Jaeger 是 Uber 开源的一个分布式追踪系统
- 特性:
- 支持多种编程语言和框架。
- 提供了丰富的API和SDK,方便集成到应用中。
- 有强大的查询和分析能力,可以进行复杂的过滤和聚合操作。
- 支持高并发和大规模数据量。
Zipkin:
- 简介: Zipkin 是 Twitter 开源的一个分布式追踪系统,它的目标是提供一个高性能、可扩展的追踪解决方案。
- 特性:
- 支持多种编程语言和客户端库。
- 提供了直观的UI界面,方便查看追踪数据和分析问题。
- 可以与各种存储后端集成,如MySQL、Cassandra等。
- 支持跨数据中心的追踪数据收集。
Skywalking:
- 简介: Skywalking 是 Apache 基金会下的开源应用性能监控(APM)系统,也是目前国内被最广泛使用的一块开源APM系统,相较于其他两个,他是一个完整的监控解决方案,不仅支持分布式追踪,还可以进行日志和性能指标的采集,以实现分布式追踪、性能监控、依赖关系分析等功能。
- 特性:
- 支持多种编程语言和客户端库。
- 提供了直观的UI界面,方便查看追踪数据和分析问题。
- 可以与各种存储后端集成,如MySQL、Cassandra等。
- 支持跨数据中心的追踪数据收集。
上述项目都各自有各自的特点和优势,但是由于其数据模型,数据上报协议,trace透传协议等不同,彼此之间往往难以互联互通。实际场景下常常由于不同企业、不同部门、不同工种的技术选型不同导致各种问题,背离了Distributed Tracing设计的初衷,亟待一个统一标准的出现,在这个时候,OpenTelemetry项目也就应运而生了。
OpenTelemetry介绍:
OpenTelemetry (OTel)是一个位于云原生计算基金会(CNCF)的开放源代码项目,旨在标准化遥测数据的收集、处理和导出的方式。他最初是由OpenTracing 和 OpenCensus两个项目合并得到,项目合并后来自不同公司和组织的贡献者共同协作创建和维护用于分布式追踪、指标和日志的 API、SDK 和工具。他们的目标是让用于服务可观测性的相关代码可以更方便的集成到业务代码中,从而使用户能够更有效地监控、调试和优化他们的应用程序。目前OpenTelemetry的Tracing相关项目已经具备了下述能力:
- 提供了一套标准的 API 和 SDK,支持多种语言。
- 支持多种语言的无侵入接入,Java、Go、PHP、Python、Nodejs等等。
- 默认使用W3C协议透传Trace上下文,同时支持多种其他协议。
- 可以与各种追踪后端集成,如 Jaeger、Zipkin等。
OTel社区经过短短四年的发展,社区活跃度位列CNCF第二,逐渐成为可观测领域的开源标准,得到越来越多的传统商业化APM公司的支持。它不仅完成了对传统的可观测三大支柱Tracing、Metrics、Logs数据的标准定义,也正在着手制定Profiling数据的标准,可以预见在不久的未来,所有可观测数据将拥有统一的语意约定、数据模型、上报协议、处理规范、展现形式,更好的为企业IT系统稳定性这项复杂工程助力。