云原生观测性 - OpenTelemetry

云原生观测性 - OpenTelemetry_第1张图片

应用的稳定性,以及出现问题的时候,怎样的快速定位到真正的原因,对于很多企业来说是都是一直在不断的设计和完善的能力。主要体现在怎样监控系统,怎样从日志上快速的找到错误,怎样快速的知道调用链是不是出现了问题,以及应用的运行时有没有出问题,应用依赖的数据库,中间件等是不是出现问题了。这也是大家经常听到的观测性的大三要素,监控,日志,链路。随着云原生的技术的发展,社区也在重新思考一样这些问题,也在不断的提出新的标准。接下来,我们就来介绍介绍 OpenTelemetry 这个技术。

云原生观测性 - OpenTelemetry_第2张图片

云原生观测性 - OpenTelemetry_第3张图片

01 方法论

观测性常见方案主要总结:

日志方案:filebeats->elasticsearch->kibana;filebeats->kafka->logstash->elasticsearch->kibana; fluentd->elasticsearch->kibana;fluentd->kafka->fluentd->elasticsearch->kibana 。

监控方案:比较统一的都在使用 prometheus,prometheus-operator,thanos,grafana。

链路方案:主要方案有开源的 skywalking,jaeger,zipkin,还有商业的方案,如 dynatrace 等。

方法论之一 怎样衔接日志,监控,链路

现阶段,我们又是怎样来统一?

答案是,不是很统一(商业方案不确定)。各个领域专注的点不一样。举例来说,我们可以以关键业务模型的 ID,Name 等作为串起三个技术方便的入口。在日志里注入业务 ID;在监控的数据里,注入业务 ID;在 trace 里通过规范化的方式注入业务 ID。这样在某一个业务对象在系统中出现问题的时候,就可以根据业务 ID,可以相对统一的方式拿到三大观测领域的相关数据。

OpenTelemetry 怎样解决这个问题?

用了 OpenTelemetry,我还需要再规划业务 ID?其实可以不用,三大观测领域中,需要有一个来承担起牵头作用,谁越靠近应用就应该是谁来承担这个责任,答案就是 Trace。在 OpenTelemetry 里串起三大观测能力的核心点就是 trace id 和 span id。了解过Trace,应该知道 trace id 就是代表一次业务处理的全局的可追踪的上下文 ID,所以 OpenTelemetry 的方案就是在 metrics 里,在 log 里增加了 trace id 和span id 字段。这样只需要根据告警,以及告警信息里嵌入的 trace id 和 span id (来源于告警规则里嵌入 metrics 的名为 trace id 的 lable,以及对应的 value),就可以很快的拿到出现问题的那一刻的准确的全部的观测数据。

方法论之二 怎样在最短时间定位到问题

现阶段,怎样解决的?

怎样知道在排查问题的时候,确定问题发生的事件?即便有告警辅助,业务和观测系统的各自处理部分都是需要时间,怎样就能确定具体时间?正常情况是知道大概是什么时间出现的问题,即便是这样,想要快速定位这个问题,还是需要在精确的时间里整合出三大观测的数据,此时,能做的就是取一个相对时间范围小一点的,如根据告警的左右十分钟,或者左右半小时等等。要通过肉眼去识别最后需要的日志,还是会花时间,这个时间和参与排查问题的人的经验也是相关的,这种情况是比较规范和完美的玩法,对于一些团队没有规划这些方案的团队,那就更难在很短时间排查出问题,最后就是先保存一下日志,先重启服务或者重启机器先解决了再说,这个不是我们期望的解决问题的方式。

OpenTelemetry 怎样解决这个问题?

在同一时刻通过 trace id 和 span id 将三大能力串起来。每一个部分都需要有时间,如监控是时序数据库,模式就带时间字段;如日志,日志框架都有时间这个字段;如链路,链路也都是有时间字段的。因为三者在采集的时候,每个模块的执行时机有先后顺序,但是可以保证的是这个时间范围肯定是在这次请求过程中,这样就可以将时间范围缩短到一个很短的时间范围内,来达到精确的定位问题。

方法论之三 怎样定位关联资源的故障

根因分析需要知道真正出现问题的地方,不仅仅是应用本身。在这个过程中,链路分析是最贴近的,因为链路的工具包中有内置应用依赖的基础设施的访问链路的分析。定位到应用依赖的基础设施的位置了,接下来前提条件就是被依赖的基础设施本身有监控和告警的能力。经过关系查找到基础设施的监控数据进行展示和分析。但是基础设施的监控数据也许会比较多,那怎样快速的找到问题,这就需要在建设基础设施的监控和告警能力的时候,规划好最常见问题的监控能力,这种能力的建设也是在关联分析中比较重要也是比较有难度的部分,这些数据的准确程度都是取决经验来建设,减少不必要的监控数据和告警设置,防止有用的告警和监控数据被掩盖。

方法论之四 怎样建设业务相关的观测性能力

观测性相关的工具只是提供了一些工具。如果要建设业务观测能力,需要根据需要观测的具体业务来关联观测数据。

和业务最相关的,最贴近的是业务的日志,这种方式也是成本最小的方式。对业务逻辑的程序中需要考虑到业务可运维能力,所以需要在需要观测的业务逻辑的日志里增加业务相关字段,包括当前操作所属于具体的业务,这样可以根据固定的关键业务名称快速定位到相关错误日志,以及配合日志告警,这样可以在出现问题的时候,第一时间通过告警的方式知道,以及再根据 logs 里带有的 trace 的相关信息,快速定位具体业务的链路信息。

建设业务相关的监控能力,针对重要的业务需要程序化的方式提供监控能力,举例如业务 A 的访问频率和错误数,这样可以在出现问题的时候,第一时间通过告警的方式知道,以及再根据 metrics 里带有的 trace 的相关信息,快速定位具体业务的链路信息。

对需要支持观测能力的重要业务,进行业务名称的定义和管理,映射业务名称到日志的查询语句,以及映射业务名称到 metrics 的指标查询语句或对应指标的快速查看入口。

02 OpenTelemetry 介绍

OpenTelemetry 是以解决观测性为初衷的项目,观测性包含链路,监控,日志。主要解决的问题是观测性领域模型的统一,观测性数据收集的统一,观测性数据输出的统一。这些统一性主要体现在 API 规范,SDK 实现规范,接口规范等。OpenTelemetry 不会负责观测数据的存储,需要存储这些观测数据的 backend。OpenTelemetry 定义来数据输出的规范,由各大厂商自行完成数据的持久化。

OpenTelemetry 也提供了很多开发语言的 SDK,开发者需要使用自己熟悉的语言的 SDK 完成应用程序的观测性能力。目前不同的开发语言的支持程度不一样。

主要组成:

Specification:这个组件是语言无关的,主要是定义了规范,如 API 的规范,SDK 的开发规范,数据规范。使用不同开发源于开发具体 SDK 的时候会按照标准开发,保证了规范性。

Proto:这个组件是语言无关的,主要是定义了 OpenTelemetry 的 OTLP 协议定义,OTLP 协议是 OpenTelemetry 中数据传输的重要部分。如 SDK 到Collector,Collector 到 Collector,Collector 到 Backend这些过程的数据传输都是遵循了 OTLP 协议。

Instrumentation Libraries:是根据 SDK 的开发规范开发的支持不同语言的 SDK,如 java,golang,c 等语言的 SDK。客户在构建观测性的时候,可以直接使用社区提供的已经开发好的 SDK 来构建观测能力。社区也在此基础上提供了一些工具,这些工具已经集成了常见软件的对接。

Collector:负责收集观测数据,处理观测数据,导出观测数据。

03 OpenTeleMetry整体架构

云原生观测性 - OpenTelemetry_第4张图片

架构介绍:

Application: 一般的应用程序,同时使用了 OpenTelemetry 的 Library (实现了 API 的 SDK)。

OTel Libraty:也称为 SDK,负责在客户端程序里采集观测数据,包括 metrics,traces,logs,对观测数据进行处理,之后观测数据按照 exporter 的不同方式,通过 OTLP 方式发送到 Collector 或者直接发送到 Backend 中。

OTel Collector:负责根据 OpenTelemetry 的协议收集数据的组件,以及将观测数据导出到外部系统。这里的协议指的是 OTLP (OpenTelemetry Protocol)。不同的提供商要想能让观测数据持久化到自己的产品里,需要按照 OpenTelemetry 的标准 exporter 的协议接受数据和存储数据。同时社区已经提供了常见开源软件的输出能力,如 Prometheus,Jaeger,Kafka,zipkin 等。图中看到的不同的颜色的 Collector,Agent Collector 是单机的部署方式,每一个机器或者容器使用一个,避免大规模的 Application 直接连接 Service Collector;Service Collector 是可以多副本部署的,可以根据负载进行扩容。

Backend: 负责持久化观测数据,Collector 本身不会去负责持久化观测数据,需要外部系统提供,在 Collector 的 exporter 部分,需要将 OTLP 的数据格式转换成 Backend 能识别的数据格式。目前社区的已经集成的厂商非常多,除了上述的开源的,常见的厂商包括 AWS,阿里,Azure,Datadog,Dynatrace,Google,Splunk,VMWare 等都实现了 Collector 的 exporter 能力。

04 数据流

云原生观测性 - OpenTelemetry_第5张图片

05 Trace 原理

由于 Trace 是 OpenTelemetry 中,比较成熟的部分,下面以 opentelemetry-go 这个 SDK,来分析一下 Trace 部分的基本工作原理。对 Trace 本身的数据结构和知识点不在本篇文章中详解。

云原生观测性 - OpenTelemetry_第6张图片

1.  开始一个 span。

2. 当客户的 App 要想记录一次 trace,需要在 code 里 call 这个 Start 方法,这个方法最后会返回一个 span 出来,后续 span 可以调用 span 的 End 接收这次的 trace。

3. 开始真正的初始化 span,保存 span 的 TraceID,SpanID,以及 span 的attributes,events,links,以及处理 span 限制的 spanLimits,以及 span 的 startTime,span的parent span,span 的 n ame 等一个 span 需要的相关属性。

4. 初始化处理 span 的所有类型的 processors,根据定义的 processor 去处理 span,目前只支持 simple 和 batch 两种,simple 是不推荐生产,因为是同步的 call,而且是一条一条的生产上推荐使用 batch,性能好。

5. 根据配置的所有 span 的 processors,使用每一个 processor 的 OnStart 的去处理 span,这里的 OnStart 其实是空实现。不管是 simple 类型的,还是 batch 类型的,目前都是一个是个空的方法,这个方法的定义的作用就是在开始处理 span 的时候,做一些处理。最后返回一个初始化后的 span 给到客户 (注意,要想让这个 span 真正的进入到整个 trace 里,还要调用 span 对象的 End 方)。

6. 由 tracer 返回开始的 span。

7. 当 call span 的 End 方法时候就会对 span 做一下快照,这里的快照只是将可读写的 span,复制到只读的 ReadOnlySpan 对象,通过 processor 的 OnEnd 方法放到 processor 的 queue 中,可见放到 queue 中等待发送出去的 span 都是只读的 sp.sp.OnEnd(s.snapshot()))。

8. 从 queue 获取 span 放到 batch 中,当 batch 的数量满了,或者到达了固定时间,都会将已经处于 end 状态的 span 通过 exporter 发送出去。

9. 从 queue 获取 span 放到 batch 中,当 batch 的数量满了,或者到达了固定时间,都会将已经处于 end 状态的 span 通过 processor 的 exportSpans 方法发送出去。

10. exportSpans 方法处理,只会去拿 processor 的 batch 字段的数据去处理,每次 exportSpans 时都是一次处理一个 batch 的数据。

11. 使用一个 batch 里的数据,进行转换成 collector 能接受的 trace 数据。

12. 使用 exporter 的 client,upload trace 数据到 collector。

13. 循环所有的 trace 数据,封装成 tracepb.Span, 由 Spans 方法再封装成 tracepb.ResourceSpans。

14. 定义一个 traces 发送的请求。

15. 进行发送 traces。

16. 在发送 traces 的时候,在 send 中 call singleSend 去发送数据,会有失败重试。

17. 使用 http 或者 grpc 的client,发送 tracepb.ResourceSpans 数据到 collector。

18. 将 batch 的数据处理完之后,清空一下 batch 字段,用于继续从 queue里面拿 span,用于下一个发送时机要去处理的 span 数据。

以 golang 的 SDK 的案例代码

云原生观测性 - OpenTelemetry_第7张图片

06 Metrics 简介

Metrics 是业务系统监控所必须的工具。从使用者的角度,更加关心有哪些监控数据采集类型和场景。以下介绍 OpenTelemetry 中规范的几种类型以及每种类型的一些特性,来帮助理解。(Metrics 在 OpenTelemetry 中的实现部分是三大块中最复杂,篇幅有限,原理部分不在当前这篇文章中详细介绍)

6.1. Instrument 类型总结

Counter :递增的计数器。

UpDownCounter:可增可减的计数器。

Histogram:统计一组数据,如直方图。

CounterObserver:异步方式的递增计数器。

UpDownCounterObserver:异步方式的可增可减计数器。

GaugeObserver:异步的方式观测最新数据的计量器。

6.2. 聚合器类型总结

Sum:类型匹配到 Counter,UpDownCounter,CounterObserver,UpDownCounterObserver。这类聚合器用于对数据做加法。

LastValue:类型匹配到 GaugeObserver。这类聚合器用于根据数据的时间,计算出最新时间点的数据。

Histogram:类型匹配到 Histogram。这类聚合器用于计算一组 Points 中 sum,count,buckets。

MinMaxSumCount:类型匹配到 Histogram。这类聚合器用于计算 sum,count,min,max。

Exact:类型匹配到 Histogram。这类聚合器虽然处理的也是一组 Points,但是不做任何计算,只是保存这些 Points。

备注:有三个聚合器都对应到了 Histogram Instrument,根据期望的分布统计选择对应的策略。NewWithHistogramDistribution 对应选择 Histogram 聚合器作为 Histogram Instrument 的聚合器 (默认推荐);NewWithExactDistribution 对应选择 Exact 聚合器作为 Histogram Instrument 的聚合器;NewWithInexpensiveDistribution 对应选择MinMaxSumCount 聚合器作为 Histogram Instrument 的聚合器; 

6.3. 同步/异步的区别

同步:类型匹配到 Counter,UpDownCounter,Histogram。由应用程序每次主动指定 Instrument 的监控数据,随着每次程序的执行而执行。如一次请求处理,在请求处理中设置请求次数。

异步:类型匹配到 CounterObserver,UpDownCounterObserver,GaugeObserver。由 SDK 每次的收集周期执行一次异步类型 Instrument 设置的回掉函数,在回掉函数中设置监控数据。如每次收集间隔是,统计一下程序的运行时间。

6.4. Adding 和 Grouping 的区别 

Adding:类型匹配到 Counter,UpDownCounter,CounterObserver,UpDownCounterObserver。每次收集周期,Instrument 对应的聚合器关注于对同一个 Instrument 做加法。

Grouping:类型匹配到 Histogram,GaugeObserver。关注于一组数据的处理。如 GaugeObserver 对应的聚合器会保存 Points,Points 中保存着同一个 Instrument 在不同时间点采集的数据 (Point);Histogram 会计算一组Points 中的 sum,count,min,max,buckets,Points。

6.5. 对应的Prometheus类型 

Counter :Counter

UpDownCounter:Gauge

Histogram:Histogram

CounterObserver:Counter

UpDownCounterObserver:Gauge

GaugeObserver:Gauge

6.6 代码案例

云原生观测性 - OpenTelemetry_第8张图片

云原生观测性 - OpenTelemetry_第9张图片

07 Log 简介

以下介绍了 OpenTelemetry 中,Log 的数据格式规范。

云原生观测性 - OpenTelemetry_第10张图片

08 Log 关联 Trace

Log4j2 支持 Trace,引用 OpenTelemetry 提供的 jar 包,以及修改配置文件。

云原生观测性 - OpenTelemetry_第11张图片

Logback 支持 Trace,引用 OpenTelemetry 提供的 jar 包,以及修改配置文件。

云原生观测性 - OpenTelemetry_第12张图片

Golang logrus 支持 Trace,在 code 里手动注入 trace 的相关信息。

云原生观测性 - OpenTelemetry_第13张图片

OpenTelemetry 自己的 log sdk,在 code 里手动注入 trace 的相关信息。

云原生观测性 - OpenTelemetry_第14张图片

09 Metrics 关联 Trace

这里先引入一个概念,Exemplars。Exemplars 的作用是连接 metrics 和 trace 的关键,也就是在 metrics 的数据里注入 trace id 和 span id。这种方式目前已经实现的开源软件有 Prometheus,OpenMetrics。OpenTelemetry 引用 OpenMetrics 的设计,也使用一样的概念完成在 OpenTelemetry 中注入 trace id 和 span id 到 metrics,区别是 OpenMetrics只实现 Histogram Instrument 类型的 Exemplars,OpenTelemetry 将会实现所有 Instrument 类型的 Exemplars 能力。

opentelemetry-java 最新版本是 1.7.0,已经支持了默认支持了 Exemplars,但还是 alpha 版本。OTEL_METRICS_EXEMPLAR_FILTER 这个环境变量默认值是 WITH_SAMPLED_TRACE 作,会自动将需要 sampled (trace中需要被采样的span) 的 trace id 以及 span id 和 metrics 关联起来。

云原生观测性 - OpenTelemetry_第15张图片

样例: 

request_duration{path="/test",le="0.004"} 4.0 #{trace_id="043cd631811e373e4188e",span_id="cd122d2ca5b0"} 0.0033 1618261159.027

opentelemetry-go 目前版本暂时还没有实现这部分功能。

10 Auto Instrumentation

在使用工具的时候,都希望这个工具简单而且强大。

OpenTelemetry 的 java sdk 中,应用可以无需修改 code,只需要引用对应的 jar 包就可以完成对很多常见观测能力的集成。目前支持的集成已经比较广泛,包含常见的软件集成。主要包含,akka,camel,dubbo,httpclient,cassandra,couchbase,elasticsearch,finatra,geode,grails,grizzly,grpc,guava,get,hibernate,hystrix,jaxrs,jaxws,jdbc,jedis,jetty,jms,jsf,jsp,kafka,kubernetes,log4j,logback,mongo,netty,quartz,rabbitmq,reactor,redisson,rmi,rocketmq,scala,servlet,spark,spymemcached,struts,spring,tomcat,vertx等。使用了 OpenTelemetry 的 java 的 SDK,就可以自带这些软件的调用分析能力。

OpenTelemetry 的 golang sdk 中开始支持 http,grpc,beego,mongo,sarama (kakfa),host (程序所在主机的内存,网络,CPU使用),runtime (程序本身的资源使用,如 heap memory 的使用,gc 的情况),gocql,mux,gin,go-kit,go-restful,gomemcache 等,使用了 OpenTelemetry 的 go 的 sdk,就可以自带这些软件的调用分析能力。

11 社区

collector 的 contrib,是各大厂商参与社区的主要方向之一, 其中对 receiver,processor,exporter 都进行了大量的扩展。

各种语言的 SDK 的 auto instrumentation,主要分布在各种语言 SDK 的 contrib 仓库中。使用了这些工具之后,可以具备更多自动化的能力,而不需要自己再基于 SDK 的基础能力去开发这些能力。举例,可以自动获取当前进程的运行状态等等。所以此类的能力也是社区参与度比较高的部分。

java 的 SDK 的版本是比较高的,因为目前企业还是 java 的系统偏多,其它版本低一点,但是 trace 部分也都发布了 1.0 以上的版本。

trace 的成熟度最高,基本可以商用。metrics 还在 alpha 阶段,最近还在变动 Instrument Kind,举例 ValueRecorder 改成了 Histogram。log 也是在 alpha 阶段,比 metrics 稍微落后一点,java 的 SDK 已经有 alpha 版本,但是 golang 的 SDK 中还没有任何 log 相关的实现。

12 总结

OpenTelemetry 的出现,将会改变目前现有的观测能力的方案方向。重新定义云原生观测性能力。从目前的社区状态看,还有一些部分还不是很成熟,还需要一些时间。随着社区的发展,会有越来越多的 vendor 去适配,会有更多的观测能力方案和存储观测数据的方案集成到 OpenTelemetry 中。

最后,云原生交流群,欢迎加入参与交流互动:

云原生观测性 - OpenTelemetry_第16张图片

你可能感兴趣的:(云原生,elasticsearch,cloud,native,容器,云计算)