随着分布式和微服务架构的发展,应用系统和服务组件之间的调用关系愈发复杂。如何精确的展示和快速定位服务单元之间的调用关系,实时观测应用系统整体链路情况,对应用系统的监控运维提出了挑战。本文简要介绍分布式应用链路跟踪的实现方式、OpenTracing规范以及对比不同全链路开源组件的实现。
随着分布式和微服务技术的发展演进,越来越多的系统从单体应用向分布式微服务架构转型。在微服务架构下应用服务被拆分为不同的服务模块,这些服务模块之间的调用关系也变得错综复杂,客户端的连接请求可能需要在多个不同的服务单元之间进行流转。此时如果某个服务单元或者模块出现异常,很难快速直观的去定位到异常点,以及对整个系统的影响范围和影响程度、爆炸半径等。如下图所示为典型的微服务架构:
为了分析和解决分布式架构下故障的快速定位分析、故障影响的精确判断、服务模块之间的依赖关系和调用关系以及整个应用系统调用链路的整体观测性,引入了全链路跟踪技术。全链路跟踪技术可以将一次分布式请求还原成调用链路,将一次分布式请求的调用情况集中展示,比如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等。全链路跟踪的主要有以下功能点:
下图是一个简单的微服务架构下的完整调用链路视图:
链路跟踪最早由Google提出,并发表了一篇论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,介绍Google自研的分布式链路跟踪系统Dapper的实现原理和设计实现。随后出现了一众开源产品如Zipkin、Jaeger等,但是各个开源的分布式链路跟踪方案互不兼容,为了统一标准接口,诞生了OpenTracing。OpenTracing于2016年10月加入CNCF基金会,它是一个中立的(厂商无关、平台无关)分布式追踪的 API 规范,提供统一接口,可方便开发者在自己的服务中集成一种或多种分布式追踪的实现。
OpenTracing是一个分布式跟踪系统,它提供了一个平台无关、厂商无关的API,使得开发人员能够方便地添加(或更换)追踪系统的实现。在全链路跟踪中,OpenTracing通过在HTTP头中注入唯一标识符(trace ID)来实现追踪。这个唯一标识符可以关联所有的HTTP请求,从而形成一个完整的调用链。
在应用系统中,Tracing指的是使用特定的日志记录程序的执行信息,与之相近的还有metrics和logging两个概念。
Tracing、Metrics和Logging这三种监控类型交集的情况比较常见:
在分布式系统中,Tracing、Metrics和Logging作为三种不同类型的监控方式,侧重点不同,并且有不同的工具来实现:Tracing基于OpenTracing规范实现请求流程的链路分析、Metrics基于Prometheus实现应用系统指标的监控分析、Logging基于ELK或EFK实现日志数据的采集和分析。
OpenTracing的出现主要是为了解决不同的分布式链路追踪平台的API兼容问题,通过提供与平台和厂商无关API的方式,使得开发人员能够很方便地切换追踪系统。在OpenTracing中有几个基本概念:
1)Span
Span是分布式跟踪的主要构建块,表示分布式系统中完成的单个工作单元。Span之间通过嵌套或者顺序排列建立逻辑因果关系。在OpenTracing中的一条Trace被认为是一个由多个Span组成的有向无环图(DAG)。每个Span根据OpenTracing规范封装了以下状态:
在OpenTracing的一条Trace中,一个Span可以和多个Span之间存在因果关系,在OpenTracing中定义了ChildOf和FollowsFrom两种引用关系,如下所示:
Causal relationships between Spans in a single Trace
[Span A] ←←←(the root span)
|
+------+------+
| |
[Span B] [Span C] ←←←(Span C is a `ChildOf` Span A)
| |
[Span D] +---+-------+
| |
[Span E] [Span F] >>> [Span G] >>> [Span H]
↑
(Span G `FollowsFrom` Span F)
2)Tags
每个Span可以有多个键值对形式的Tags,Tags是没有时间戳的,只是为Span添加一些简单解释和补充信息。
3)Logs
每个Span可以进行多次Logs操作,每一次Logs操作,都需要带一个时间戳,以及一个可选的附加信息。
4)SpanContext
SpanContext表示进程边界,在跨进调用时需要将一些全局信息,例如TraceId、当前SpanId等信息封装到Baggage中传递到另一个进程中。
备注:在OpenTracing官网上看到OpenTracing相关的技术已经迁移到OpenTelemetry上。OpenTelemetry是OpenTracing和OpenCensus两个项目的合并,是一个更加强大的监控解决方案。它可以收集所有类型的遥测数据,如日志、指标和调用链,并且是一个开箱即用的API、SDK和库的合集。其中一条trace如下所示:
{
"name": "hello-greetings",
"context": {
"trace_id": "0x5b8aa5a2d2c872e8321cf37308d69df2",
"span_id": "0x5fb397be34d26b51"
},
"parent_id": "0x051581bf3cb55c13",
"start_time": "2022-04-29T18:52:58.114304Z",
"end_time": "2022-04-29T22:52:58.114561Z",
"attributes": {
"http.route": "some_route2"
},
"events": [
{
"name": "hey there!",
"timestamp": "2022-04-29T18:52:58.114561Z",
"attributes": {
"event_attributes": 1
}
},
{
"name": "bye now!",
"timestamp": "2022-04-29T18:52:58.114585Z",
"attributes": {
"event_attributes": 1
}
}
]
}
其中包括span_id和parent_id、traceid、start_time和end_time、attributes和events等信息。
回到1.1中微服务架构下的完整调用链路视图,在服务调用的时候加上spanid、traceid和parentid,其中traceid为链路请求全局唯一id。如下所示:
通过ParentID找到父节点,并通过全局唯一的traceID实现链路跟踪。
自Google Dapper系统开放以来,出现很多分布式链路跟踪的产品,如Pinpoint、Zipkin、Skywalking、Jaeger等,接下去将简要介绍对比。
1)Pinpoint
Pinpoint是由一个韩国团队实现并开源,针对Java编写的大规模分布式系统设计,通过JavaAgent的机制做字节代码植入,实现加入traceid和获取性能数据的目的,对应用代码零侵入。
官方网站:https://github.com/pinpoint-apm/pinpoint
2)SkyWalking
SkyWalking是一款国产的开源框架,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计的分布式系统的应用程序性能监视工具,包括了分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案。SkyWalking支持Java、.Net Core、PHP、NodeJS、Golang等多种语言探针,支持Envoy + Istio构建的Service Mesh。
SkyWalking的客户端通过HTTP或gRPC方式向SkyWalking收集器发送链路调用数据。SkyWalking收集器对接收到的链路信息进行分析和聚合,并存储到服务端数据库,支持的存储组件有ES、H2、MySQL、TiDB和Sharding Sphere等。SkyWalking UI则提供了链路调用信息的可视化和检索。以下为Skywalking架构图:
官方网站:http://skywalking.apache.org/
3)Zipkin
Zipkin是由Twitter开源,是分布式链路调用监控系统,聚合各业务系统调用延迟数据,达到链路调用监控跟踪。Zipkin基于Google的Dapper论文实现,主要完成数据的收集、存储、搜索与界面展示。Zipkin组件如下图所示,包括Collector、Storage、Search和Web UI:
官方网站:https://zipkin.io/
4)云原生链路监控组件Jaeger
Jaeger是CNCF云原生项目之一,由Uber开源的分布式追踪系统,兼容Open Tracing API。Jaeger主要用于微服务的监控和请求追踪,支持分布式上下文传播、请求报错分析、服务的调用网络分析以及性能/延迟优化。Jaeger在架构上支持分布式追踪和性能监控,包括多个组件和模块,以实现数据收集、存储、查询和可视化等功能。如下图所示:
官方网站:https://www.jaegertracing.io/
5)各种全链路跟踪方案对比
对比上述四种组件,Zipkin本身实现相对简单,指标的分析和展示需求需要二次开发工作;Jaeger是对Zipkin的优化,在WebUI和传输协议上进行了改进,但也无告警功能;Pinpoint不支持OpenTracing规范,并且不支持查询单个调用链,二次开发难度较高;SkyWalking功能较为齐全,探针性能损耗低,同时也支持多种语言的客户端,并且中文社区非常活跃。
接下去将重点介绍基于Skywalking的全链路跟踪实现。
参考资料: