分享

OpenTelemetry 开源实现:可观测技术之服务拓扑

 汉无为 2023-04-27 发布于湖北

前言

虽然 OpenTelemetry 在设计 “可观测性的三大支柱” 规范时,并没有直接设计 Service Map 相关的数据结构和算法,但作为可观测领域的经典宏观分析方法,社区也提供了基于 OTLP 协议的 ServiceGraph 的 Processor ——通过链路数据推导出服务间调用关系。这套技术目前已经成为 OpenTelemetry Collector 组件的重要组成部分,也成为很多团队构建自己的可观测系统使用的利器

了解新系统的第一步

从经验出发,你可能会主动寻找最初系统的系统设计文档,不过系统是演变的,你找到的文档大概率是过时的;接着,你可能会去寻找队友的帮助,但队友的理解可能只是完整系统的一隅,队友的体悟和实际情况之间也许会有偏差…… 所以,你有什么更好的办法?

此时,可通过可观测技术来还原系统的真实面貌。目前,可观测能力的三大支柱——链路——及其衍生出来的服务拓扑(Service Map,又被翻译成“服务地图”)可以很好地解决这个问题。

服务拓扑最大的好处就是——为系统运维人员提供了复杂系统的可见性,这种可见性不仅在调查特定问题或事件时很重要,还适合运维工程师了解整个应用程序的工作方式;通过实时绘制观察到的这些服务之间真正的依赖关系,因此您可以通过数据流了解您的架构并通过拓扑指标从宏观层面识别出系统目前是否存在瓶颈。

此外,服务拓扑还有很多实际的使用场景:

  • · 提供系统健康状况的高级概览。服务拓扑显示错误率、延迟以及其他相关数据。

  • · 提供系统拓扑的历史视图。分布式系统变化非常频繁,服务拓扑提供了一种查看这些系统如何随时间演变的方法。

  • · 通过实时拓扑验证系统实现是否与原先设计一致。

原理 - 什么是服务拓扑

服务拓扑是从分布式链路技术衍生出来的重要的使用场景。从链路数据推导出拓扑数据是自然而然的,链路描述的就是一个请求在分布式系统中途径的服务,自然就包含了服务间调用关系。

点动成线,线聚成面,服务是点,链路是线,拓扑就是这个面。

虽然拓扑的底层原理可以概括为 “服务连接成链路,链路堆叠成拓扑” ,不过,在 OpenTelemetry 架构中,链路数据又是通过什么组件进行转换与计算,接着是如何存储,最后拓扑又是如何展示的呢?接下来我们逐个分析。

图片

OpenTelemetry 与观测信号流

首先,我们快速回忆一下什么是 OpenTelemetry ,以及相关的信号流。

OpenTelemetry(简称 OTel)旨在为所有类型的可观测数据定义一个统一的标准,主要关注链路、指标和日志这 3 种可观测信号(Signal)。曾经, 对于每一种信号,我们需要分别关注信号的数据结构(数据协议)、产生、采集、存储和分析;而现在,这些过程中差异正通过 OpenTelemetry 被一点点的弥合:

  • · 统一的跨语言规范:从今天开始,你只需要关注 OTLP 协议的数据,各个商业产品圈地树立的 “次元壁” 被打通。

  • · 基于规范的各种语言的 API & SDK:社区统一维护了各种语言的 API & SDK,你对语言和类库的选择将更自由,至少不再需要费心可观测性的集成。

  • · 收集,转换和转发的工具 Collector:社区提供了 OpenTelemetry Collector (以下简称 OTel Collector) 对 SDK 暴露的数据进行采集和转换。本文讨论的服务拓扑就是在这里进行聚合计算的。

在 OpenTelemetry 时代,不同语言的应用,都通过 OTel SDK 进行三种信号的统一暴露。接着,通过社区的 OpenTelemetry Collector 组件 ,进行信号的统一采集;随即,OTel Collector 组件可以过滤噪音信号,清洗和整理信号数据,再聚合分析出新的信号;最后导出到任何你正在使用的可观测性产品中,可能是 Datadog,NewRelic 之类的云上服务商,也可能是 Jaeger 加上 Prometheus 组合的开源方案,甚至是云上云下混合的组合方式。OpenTelemetry 让你获得前所未有的解放,开发们不需要不断地学习各种产商的 SDK,运维只需要一套 OTel Collector 就可以完成各种信号的采集,运营人员可以选择自己称手的观测分析工具。对于企业而言,你重新拥有了你的可观测数据的所有权。

下图说明了可观测信号在应用中的变化:

图片

OTel Collector 采集来自业务应用和基础架构的日志,链路和指标数据;这些数据在 OTel Collector 中进一步的被聚合与流转,然后输出给后端观测产品或观测数据持久化中间件中。

OpenTelemetry Collector 的信号流

OTel Collector 被设计为一个独立的信号采集器,是一个配置非常灵活的的信号处理工具。

图片

OTel Collector 基本架构如上图所示。从左到右分别是 :接收器,处理器和导出器。此外,我们将接收器,处理器和导出器组合成管道(Pipeline)。

  • · 接收器:负责接受各种格式的遥感数据,并将数据转换成 OTLP 数据,在 OTel Collector 内流转,目前,已经支持超过 40 种不同类型数据结构的接收器。

  • · 处理器:收集器写入的 OTLP 数据后,不同的信号数据会根据管道的编排进入不同的处理器中计算。有负责清理错误和敏感数据的处理器;也有统计链路情况,并转化成指标的处理器( 名为 SpanMetrics );还有本次重点讨论的,将链路数据推导出拓扑数据,并保存成指标数据进行存储的处理器(名为 Service Graph)。

  • · 导出器:数据从处理器出来之后,会经过导出器输出到各种持久化指标的后端。虽然目前原生支持 OTLP 的后端不够丰富,我们还可以将 OTLP 转换成面流行的系统所支持的格式并存储。比如将指标信号导出存入 Prometheus,将链路数据导出成 OpenTracing 的格式被 Jaeger 存储。

ServiceGraph Processor 的原理

服务拓扑的计算原理是:通过检查链路信号,并从中查找出具有代表请求父子关系的 span , 以此来描述请求的发起方和接收方。服务拓扑处理器(Processer)使用 OpenTelemetry 语义约定来检测各式各样的请求。目前支持处理以下请求:

  • · 两个服务之间的直接请求,其中传出和传入跨度必须span.kind分别具有客户端和服务器。

  • · 跨消息系统的请求,其中传出和传入跨度必须span.kind分别具有生产者和消费者。

数据库请求;在这种情况下,处理器查找包含属性span.kind=client 以及 db.name 的跨度。

每一条可能被配对形成请求的 span 都被保存在内存中,直到收到其对应的配对 span 或等待超时。当满足上述这两个条件中的任何一个时,该请求数据将被保存成指标,并从内存中删除。

每个保存的指标数据(metrics series)都含有 客户端 和 服务器 这 2 个标签,对应于请求的发送方和请求的接收方。如下指标样例:

图片

traces_service_graph_request_total{client='app', server='db'20

图片

如何渲染服务拓扑

通过 ServiceGraph 技术我们可以将服务拓扑的计算标准化,产生的指标数据也标准化,那么,渲染的部分也可以标准化么?

这是目前社区的一个难点。现阶段,还没有一款开源的、兼具实用和美观的开源服务拓扑可视化产品。即便是被社区广泛使用的 Grafana 推出的 NodeGraph 组件还是处于 beta 阶段,而且,针对指标数据源,也仅能绘制出点和线的关系;想要进一步给点和线增加颜色,以及复杂的 UI 交互也爱莫能助。

先阶段,Grafana 社区推荐的玩法是,提供一个数据源(Datasource)将数据进一步聚合成如下结构。

{
  'nodes': [
    {
      'id': 1,
      'title': 'nginx',
      'mainStat': 21233,
      'arc__passed': 0.283,    # ”成功“ 的占比
      'passed_color': 'green', # ”成功“ 占比的颜色
      'arc__failed': 0.717,    # ”失败“ 的占比
      'failed_color': 'red'    # ”失败“ 占比的颜色
    }
  ]
}

可以遇见的是:因为 Grafana 的市场优势,许多可观测产品最后可能为针对 Grafana 的 NodeGraph 拓扑可视化组件提供接口,比如目前的 AWS 的 X-Ray Datasource。

示例上手

OpenTelemetry 官方维护了一个模拟真实世界的微服务分布式系统,用来说明 OpenTelemetry 在接近真实环境中的具体使用。此 Demo 由若干不同编程语言编写的微服务组成,这些微服务通过 gRPC 或 HTTP 相互通信;此外,还增加了使用 Locust 伪造用户流量的负载生成器。该微服务 Demo 也成为各个可观测性产品测试 OpenTelemetry 支持度的必选示例。

今天我们也通过这个示例微服务系统来测试 ServiceGraph 相关的能力。

安装 OpenTelemetry Demo

官方的示例推荐 2 种安装方法,一种是正式的云原生化的部署方式,通过 helm 将应用部署到 Kubernetes 中;另一种是方便本地执行和验证的的方式,通过 docker-compose 命令在本机上运行程序。为了简化部署细节,本次示例使用 docker-compose 的方式,关于 helm 部署到 Kubernetes 可以参考之前的文档,或者官方文档。

安装 OpenTelemetry Demo 示例

# 克隆 Webstore 项目。因为官方示例还未完整集成 ServiceGrpah 的相关实例,此次,为了更完整的展示内容,我们推荐使用 fork 出来的版本。
git clone https://github.com/hermaproditus/opentelemetry-demo.git

# 切入项目文件夹下
cd opentelemetry-demo/

# 通过 docker compose 运行项目
# 注意使用 --no-build 参数,避免重源码开始构建。
docker compose up --no-build

这里的 —no-build 标志参数,使 docker-compose 安装时,直接从镜像仓库中获取实相关的镜像(image)直接启动,避免从源码从头开始构建出镜像再启动,进而优化了部署速度。

稍微等待一会儿,通过浏览器打开 http://localhost:8080/ ,看到如下页面,即说明 OpenTelemetry Demo 安装成功。

图片

通过 Grafana 查看 ServiceGraph

通过浏览器打开 http://localhost:3000,进入到 Grafana 的页面中,并选择 ServiceGraph Dashboard 即可看到通过 OpenTelemetry Collector 数据绘制出来的 Service Map。如下图所示。

图片

通过此仪表板即可快速的查看到最近 30 分钟内,这套微服务系统里,微服务与微服务之间的调用关系。

解析 ServiceGraph 核心配置

官方默认的配置是没有在 Collector 中开启 ServiceGraph 相关的配置,我们将对应用进行简单的改造。

receivers: #step-1
  otlp/servicegraph: # Dummy receiver for the metrics pipeline
    protocols:
      grpc:
        endpoint: localhost:12345

exporters: #step-2
  prometheus/servicegraph:
    endpoint: 0.0.0.0:9099
    # namespace: servicegraph

processors: #step-3
  servicegraph:
    metrics_exporter: prometheus/servicegraph
    latency_histogram_buckets: [2ms4ms6ms8ms10ms50ms100ms200ms500ms800ms1s1400ms2s5s10s15s]
    dimensions:
      - k8s.cluster.id
      - k8s.namespace.name
    store:
      ttl: 60s
      max_items: 100000
    # attribute values refs: go.opentelemetry.io/collector/semconv@v0.73.0/v1.13.0/generated_trace.go

service: #step-4
  pipelines:
        traces: #step-4-1
      receivers: [otlp]
      processors: [servicegraphbatch#step-4-1-1
      exporters: [otlploggingspanmetrics]
    metrics/servicegraph: #step-4-2
      receivers: [otlp/servicegraph]
      processors: []
      exporters: [prometheus/servicegraph]

我们在 step-3 里声明了一个名为 servicegraph 的 ServiceGraph Processor ,并设置了核心参数。另外,声明了 metrics/servicegraph 用来导出指标数据到 Prometheus 中。

然后调整 step-4-1-1 的 trace 数据流中使用了 servicegraph 这个 processor。一旦 Collector 接受到链路数据,就会根据 step-3 声明的参数,将链路的访问关系转换成指标并向外暴露。接着,数据被 Prometheus 采集并持久化。

最后,通过 Grafana 自带的 node graph 组件,就可以渲染出来 Service Graph。

进一步思考

Q1:Jaeger 本身已提供 ServiceMap 能力,为什么我们还需要 OpenTelemetry Collector 的 ServiceGraph 呢?

A1:OTel Collector 的服务拓扑计算是在数据采集的时候进行的。这么设计的好处是,服务拓扑,不再依赖任何可观测性的产品。即便你的可观测后端不支持服务拓扑能力,你都可以通过部署 Prometheus + Grafana 这套开源观测套件来实现服务拓扑的功能。

Q2:这套方案是否提供了通用的数据绘制模型?是仅针对 Grafana 的数据结构么?

A2:虽然 ServiceGraph Processor 的核心开发确实是来自 Grafana 公司的 Tempo 团队的,但数据最后暴露的指标数据结构其实是通用的,Kiali 等产品也是如此设计。此外,这套数据结构也非常容易适配到可视化的组件里。本次的示例使用 Grafana 来渲染,是因为目前 Grafana 的 Dashboard 就支持 node graph 这种拓扑可视化组件,而且,OpenTelemetry Demo 本身就自带了 Grafana 来展示指标数据。

最后的话

目前,ServiceGraph Processor 已经成为 OTel Collector 组件的默认组成部分,这意味着,所有 OTel Collector 用户都免费解锁了 “服务拓扑” 这种观测能力。在许多商业的可观测产品里,这是作为高级能力和卖点,而现在成为每个可观测用户开箱即可使用的能力。

本文通过一个问题引出服务拓扑(ServiceMap)的概念,然后讨论了在 OpenTelemetry 架构中,ServiceGraph Processor 如何通过链路数据流绘制出服务拓扑,最后通过一个官方示例,简单的展示 OpenTelemetry Graph 能力。

作者介绍

张晓珣(Jerry.Zhang),云原生观测领域的观测人。现就职于 DaoCloud

  • · 最近社区发起社区文化礼品相赠的活动,贡献技术文章能得到价值300元带社区彩色 Logo的公文包,感谢可观察性解决方案团队 杭州乘云数字技术的友情赞助

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多