OpenTelemetry 项目解读

iBit程序猿 2022年03月13日 1,601次浏览

随着分布式应用越来越普遍,分布式应用需要依赖强大的可观测性设施来提供监控保障,强大的可观测性设施需要依赖高质量的遥测数据。虽然已经有许多开源或者商业供应商提供了遥测数据监测采集方案。但是在没有统一标准的情况下,采集的遥测数据兼容性差,维护监测客户端也给使用者带来沉重的负担。

Opentelemetry可以为开发者们提供统一的,与第三方无关的遥测数据采集方案,以解决上述的各种问题。

一、源起

Opentelemetry源自于OpenTracing与OpenCensus两大开源社区的合并。OpenTracing在2016年由Ben Sigelman发起,旨在解决开源Tracing实现重复开发监测客户端,数据模型不统一,Tracing后端兼容成本高的问题。OpenCensus则是由Google内部实践而来,结合了Tracing和 Metrics的监测客户端开源工具包

由于两大开源社区各自的影响力都不小,而存在两个或多个Tracing的标准这个事情本身跟社区组建的主旨相违背。于是两大开源社区一拍即合,成立了OpenTelemetry。

二、为什么需要

从使用者角度来看,接入Tracing监测客户端,对业务代码有一定入侵性。一旦接入了一个供应商的监测客户端,就很难切换到其他供应商提供的监测客户端。而从Tracing服务端供应商的角度来说,服务端除了要能够处理自己Tracing客户端的数据外,还需要兼容其他供应商Tracing客户端产生的数据,维护成本越来越高。尤其是在分布式应用逐渐普及的情况下,如文章开头所说,Opentelemetry的价值更加明显

三、Opentelemetry项目组成

Opentelemetry的项目主要分为四个部分内容:

  • 跨语言规范说明
  • 收集、转换、转发遥测数据的工具Collector
  • 各语言监测客户端API&SDK
  • 自动监测客户端与第三方库Instrumentation&Contrib

(一)跨语言规范说明

规范说明包含话题内容比较广泛。其中有包含遥测客户端内部实现所需要的规范,也有包含遥测客户端与外部通信所需要实现的协议规范。

代码仓库opentelemetry-specification

遥测客户端内部实现所需要的规范,如监测客户端基本架构、设计原则,遥测信号(Traces/Metrics/Logs)与辅助对象(Baggage/Context/Propagator)的概念与模型定义,实现遥测客户端需要实现的类与功能的设计等。这部分内容本文就不做详细介绍,可以在specification/overview.md以及相应对象文件夹下面的datamodel.md/ api.md/sdk.md可以进行查阅。

遥测客户端与外部通信所需要实现的协议规范主要是指OpenTelemetry Protocol(简称OTLP)。OTLP是Opentelemetry原生的遥测信号传递协议,虽然在Opentelemetry的项目中组件支持了Zipkin v2或Jaeger Thrift的协议格式的实现,但是都是以第三方贡献库的形式提供的。只有 OTLP是Opentelemetry官方原生支持的格式。

OTLP的数据模型定义是基于ProtoBuf完成的,如果你需要实现一套可以收集OTLP遥测数据的后端服务,那就需要了解里面的内容,对应可以参考代码仓库:

代码仓库opentelemetry-proto

(二)收集、转换、转发遥测数据的工具Collector

在Tracing实践中有一个原则,遥测数据收集过程需要与业务逻辑处理正交。意思就是遥测数据收集并传递到遥测后端服务的过程不占用业务逻辑的信道/线程,尽量较少监测客户端对原有业务逻辑的影响。Collector是基于这个原则实践的产物。

代码仓库opentelemetry-collector

从架构层面来说,Collector有两种****模式。一种是把Collector部署在应用相同的主机内(如K8S的DaemonSet),或者部署在应用相同的Pod里面 (如K8S中的Sidecar),应用采集到的遥测数据,直接通过回环网络传递给Collector。这种模式统称为Agent模式

另一种模式是把Collector当作一个独立的中间件,应用把采集到的遥测数据往这个中间件里面传递。这种模式称之为Gateway模式

两种模式既可以单独使用,也可以组合使用,只需要数据出口的数据协议格式跟数据入口的数据协议格式保持一致。

image.png

Opentelemetry Architecture

在Collector内部设计中,一套数据的流入、处理、流出的过程称为pipeline。一个pipeline有三部分组件组合而成,它们分别是receiver/processor/exporter。

  • receiver

负责按照对应的协议格式监听接收遥测数据,并把数据转给一个或者多个processor。

  • processor

负责做遥测数据加工处理,如丢弃数据,增加信息,转批处理等,并把数据传递给下一个processor或者传递给一个或多个exporter。

  • exporter

负责把数据往下一个接收端发送(一般是遥测后端),exporter可以定义同时从多个不同的processor中获取遥测数据。

Collector Pipeline

从上面的设计可以看出,Collector除了提供让遥测数据收集与业务逻辑处理正交的能力,还充当了遥测数据对接遥测后端的适配器。Collector可以接收otlp、zipkin、jaeger等任意格式的数据,然后以otlp、zipkin、jaeger等任意格式的数据转发出去。这一切只取决于你需要输入或输出的格式是否有对应的receiver和exporter实现。otlp相关实现都是在opentelemetry-collector仓库中。而otlp以外的协议实现,则是可以参考下面代码仓库。

代码仓库opentelemetry-collector-contrib

(三)各语言监测客户端API&SDK

Opentelemetry为每种语言提供了基础的监测客户端API&SDK包。这些包一般都是根据opentelemetry-specification里面的建议与定义,以及结合语言自身的特点,实现了在客户端采集遥测数据的基本能力。如元数据在服务间、进程间的传递,Trace添加监测与数据导出,Metrics指标的创建、使用及数据导出等。以下为各语言监测客户端API&SDK包对应的代码仓库表。

按照Opentelemetry项目的规划,2021年上半年大部分组件完成Tracing的支持。以目前的时间点(2021年12月)来看,C++/.NET/Golang/Java/Javascript/Python/Ruby监测客户端对Tracing支持已经进入Stable状态。Erlang/Rust/Swift监测客户端对Tracing支持则是进入了Beta测试阶段。

而Opentelemetry项目规划对于Mertics的支持则晚一些。希望在2021年下半年大部分组件能够完成Metrics的支持。以目前情况来看,各语言客户端包对于Metrics支持还处在Alpha测试阶段。而对于Logs的支持,则是计划在2022年开始。

(四)Instrumentation&Contrib

如果单纯使用监测客户端API&SDK包,许多的操作是需要修改应用代码的。如添加Tracing监测点,记录字段信息,元数据在进程/服务间传递的装箱拆箱等。这种方式具有代码侵入性,不易解耦,而且操作成本高,增加用户使用门槛。这个时候就可以利用公共组件的设计模式或语言特性等来降低用户使用门槛。

利用公共组件的设计模式,例如Golang的Gin组件,实现了Middleware责任链设计模式。我们可以引用github.com/gin-gonic/gin库,创建一个otelgin.Middleware,手动添加到Middleware链中,实现Gin的快速监测。

利用语言特性,例如Java使用Java Agent的能力与bytebuddy字节码织入技术,在Java应用启动之前找到对应类和方法,修改字节码注入监测,实现对指定类的自动监测。

理论上来说,快速监测依赖于客户端API&SDK,自动监测则依赖于快速监测。但是实际操作却并没有按理论的来。如Java语言利用Java Agent与bytebuddy技术可以实现对指定开源组件实现全自动监测的,所以就没有单独提供快速监测(在OpenTracing里面是有分开的)。

四、总结

Opentelemetry的使命是实现收集高质量大范围便携的遥测数据,让有效的可观测性设施成为可能。它本身并不提供完整的可观测性解决方案,而是提供了统一的遥测数据采集方案。而如果是需要搭建一套完整的可观测性设施,还需要搭配相应的监测后端做数据持久化与数据查询,如Tracing后端zipkin/jaeger/tempo/、metrics后端prometheus、logs后端loki等。

版权申明

本文转载于【周东科 云加社区】OpenTelemetry项目解读,仅用于学习,版权归作者所有,如有侵权烦请告知,我会立即删除并表示歉意,联系邮箱