使用 Jaeger 的 OpenTelemetry 自动检测

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前, 星球 内第2个项目《仿小红书(微服务架构)》正在更新中。第1个项目:全栈前后端分离博客项目已经完结,演示地址:http://116.62.199.48/。采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 255 小节,累计 39w+ 字,讲解图:1716 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 1300+ 小伙伴加入,欢迎点击围观

早期在单体应用中很容易推演和调试一个问题,因为后端和前端只运行一个服务。现在,我们正在转向微服务架构,其中应用程序被划分为多个可独立部署的服务。这些服务有自己的服务目标和逻辑。在这种应用程序架构中,很难观察到一个服务如何依赖或影响其他服务。

为了使系统可观察,必须从代码中发出一些日志、指标或跟踪,并且必须将这些数据发送到可观察后端。这就是 OpenTelemetry 和 Jaeger 发挥作用的地方。

在本文中,我们将了解如何借助 OpenTelemetry 和 Jaeger 监控应用程序跟踪数据(Traces 和 Spans)。跟踪用于在请求通过分布式系统中的服务传播时观察请求。跨度是跟踪的基本单位;它们代表跟踪中的单个事件,跟踪可以有一个或多个跨度。跨度由日志消息、与时间相关的数据和其他属性组成,以提供有关它跟踪的操作的信息。

我们将使用分布式跟踪方法来观察跨微服务移动的请求,生成有关请求的数据并使其可用于分析。生成的数据将记录我们微服务中的请求流,这将帮助我们了解应用程序的性能。

开放遥测

遥测是使用代理和协议从可观察性的源头收集和传输数据。遥测数据包括日志、指标和跟踪,这有助于我们了解应用程序中发生的情况。

OpenTelemetry (也称为 OTel)是一个开源框架,包含一系列工具、API 和 SDK。 OpenTelemetry 使遥测数据的生成、检测、收集和导出变得容易。从 OpenTelemetry 收集的数据与供应商无关,可以多种格式导出。 OpenTelemetry 是在合并两个项目 OpenCensus 和 OpenTracing 之后形成的。

检测

将可观察性代码添加到您的应用程序的过程称为检测。检测有助于使我们的应用程序可观察,这意味着代码必须生成一些指标、跟踪和日志。 OpenTelemetry 提供了两种检测代码的方法:

  1. 手动仪表
  2. 汽车仪表

1. 手动仪表

用户需要向应用程序添加 OpenTelemetry 代码。手动检测为跨度和跟踪中的自定义提供了更多选项。手动检测支持的语言有 C++、.NET、Go、Java、Python 等。

2、自动化仪表

这是最简单的检测方法,因为它不需要更改代码,也不需要重新编译应用程序。它使用连接到应用程序的智能代理,读取其活动并提取痕迹。自动检测支持 Java、NodeJS、Python 等。

手动和自动仪表之间的区别

手动和自动检测都有优点和缺点,您在编写代码时可能会考虑这些优点和缺点。下面列出了其中的一些:

手动仪表
自动化仪表
需要更改代码。 不需要更改代码。
它支持最多的编程语言。 目前支持 .Net、Java、NodeJS 和 Python。
由于需要更改代码,因此会消耗大量时间。 易于实施,因为我们不需要接触代码。
为跨度和跟踪的自定义提供更多选项。因为您可以更好地控制应用程序生成的遥测数据。 更少的定制选项。
由于需要手动更改,因此出错的可能性很高。 没有错误的可能性。因为我们不必触及我们的应用程序代码。

要使检测过程无忧无虑,请使用自动检测,因为它不需要对代码进行任何修改并减少出错的可能性。自动检测由读取应用程序遥测数据的代理完成,因此无需手动更改。

在本文的范围内,我们将了解如何在基于 Kubernetes 的微服务环境中使用自动检测。

杰格

Jaeger 是一个分布式跟踪工具,最初由 Uber 构建,并于 2015 年作为开源发布。Jaeger 也是 Cloud Native Computing Foundation 的研究生项目,受到 Dapper 和 OpenZipkin 的影响。它用于监控和故障排除基于微服务的分布式系统。

我们在本博客中使用的 Jaeger 组件是:

  1. 积家收藏家
  2. Jaeger 查询
  3. Jaeger 用户界面/控制台
  4. 存储后端

Jaeger Collector: Jaeger 分布式跟踪系统包括 Jaeger 收集器。它负责收集和保存信息。收到跨度后,收集器将它们添加到处理队列中。 Collectors 需要一个持久化的存储后端,因此 Jaeger 也提供了一个可插拔的 span 存储机制。

Jaeger Query: 这是一项用于从存储中获取踪迹的服务。 Jaeger 分布式跟踪系统的基于 Web 的用户界面称为 Jaeger Query。它提供了各种功能和工具来帮助您了解分布式应用程序的性能和行为,并使您能够搜索、过滤和可视化 Jaeger 收集的数据。

Jaeger UI/控制台: Jaeger UI 允许您查看和分析应用程序生成的跟踪。

存储后端: 用于长期存储应用程序生成的痕迹。在本文中,我们将使用 Elasticsearch 来存储痕迹。

将 OpenTelemetry 与 Jaeger 集成需要什么?

OpenTelemetry 和 Jaeger 是帮助我们在 基于微服务的分布式系统中设置可观察性的 工具,但它们旨在解决不同的问题。

OpenTelemetry 为应用程序提供了一个检测层,帮助我们生成、收集和导出遥测数据以供分析。相比之下, Jaeger 用于存储和可视化遥测数据。

OpenTelemetry 只能生成和收集数据。它没有用于可视化的 UI。因此我们需要将 Jaeger 与 OpenTelemetry 集成,因为它有一个存储后端和一个用于遥测数据可视化的 Web UI。借助 Jaeger UI,我们可以快速排查基于微服务的分布式系统。

注意:OpenTelemetry 可以生成日志、指标和跟踪。 Jaeger 不支持日志和指标。

现在您对 OpenTelemetry 和 Jaeger 有了一个了解。让我们看看我们如何将它们相互集成以可视化我们的应用程序生成的跟踪和跨度。

实施 OpenTelemetry 自动检测

我们将 OpenTelemetry 与 Jaeger 集成,其中 OpenTelemetry 将充当我们应用程序的仪器层,而 Jaeger 将充当后端分析工具以可视化跟踪数据。

Jaeger 将从 OpenTelemetry 代理获取遥测数据。它将数据存储在存储后端,我们将从那里查询存储的数据并在 Jaeger UI 中将其可视化。

本文的先决条件是:

  1. 目标 Kubernetes 集群已启动并正在运行。
  2. 您有权对 Kubernetes 集群运行 kubectl 命令以部署资源。
  3. 证书管理器已安装并正在运行。如果未安装,您可以从网站 cert-manager.io 安装它。

我们假设您具备所有先决条件,现在您已准备好进行安装。我们在这篇文章中使用的文件可以在这个 GitHub 存储库 中找到。

安装

安装部分包含三个步骤:

  1. 弹性搜索安装
  2. Jaeger 安装
  3. OpenTelemetry 安装

弹性搜索

默认情况下,Jaeger 使用内存存储来存储跨度,这不是生产环境推荐的方法。 Jaeger 中有多种工具可用作存储后端;您可以在 Jaeger span storage back end 的官方文档中了解它们。

在本文中,我们将使用 Elasticsearch 作为存储后端。您可以使用 Elasticsearch Helm chart 在您的 Kubernetes 集群中部署 Elasticsearch。在部署 Elasticsearch 时,确保您已启用基于密码的身份验证并将该 Elasticsearch 部署在 可观察性 命名空间中。

Elasticsearch 部署在我们的 Kubernetes 集群中,您可以通过运行以下命令查看输出。

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

Jaeger 安装

我们将使用 Jaeger 可视化跟踪数据。让我们在集群上部署 Jaeger Operator。

在继续安装之前,我们将在可观察性命名空间中部署一个 ConfigMap 。在此 ConfigMap 中,我们将传递我们在上一步中部署的 Elasticsearch 的用户名和密码。根据您的设置替换凭据。

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

如果你打算将Jaeger部署到另一个命名空间,并且你已经更改了Jaeger收集器服务名称,那么你需要更改代理收集器下的host-port值的值。

猎人操作员

Jaeger Operator 是一个用于部署和管理 Jaeger 的 Kubernetes 操作器,Jaeger 是一个开源的分布式跟踪系统。它的工作原理是在 Kubernetes 集群上自动部署、扩展和管理 Jaeger 组件。 Jaeger Operator 使用自定义资源和自定义控制器来扩展具有 Jaeger 特定功能的 Kubernetes API。它管理 Jaeger 组件的创建、更新和删除,例如 Jaeger 收集器、查询和代理组件。创建 Jaeger 实例后,Jaeger Operator 会部署必要的组件并设置所需的服务和配置。

我们将在可观察性命名空间中部署 Jaeger Operator。使用下面提到的命令来部署操作员。

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

我们使用的是最新版本的 Jaeger,在撰写本文时为 1.38.0

默认情况下,为集群范围模式提供 Jaeger 脚本。假设您只想监视一个特定的名称空间。在这种情况下,您需要在操作员清单中将 ClusterRole 更改为 Role 并将 ClusterBindingRole 更改为 RoleBinding 并在 Jaeger Operator 部署中设置 WATCH_NAMESPACE env 变量。

要验证 Jaeger 是否部署成功,请运行以下命令:

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

正如我们在上面的输出中看到的那样,我们的 Jaeger Operator 已成功部署,并且它的所有 pod 都已启动并正在运行;这意味着 Jaeger Operator 已准备好安装 Jaeger 实例 (CR)。 Jaeger 实例将包含 Jaeger 组件(Query、Collector、Agent);稍后,我们将使用这些组件来查询 OpenTelemetry 指标。

Jaeger 实例

Jaeger 实例是 Jaeger 分布式跟踪系统的部署。它用于收集和存储来自微服务或分布式应用程序的跟踪数据,并提供一个 UI 来可视化和分析跟踪数据。要部署 Jaeger 实例,请使用以下命令。

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

要验证 Jaeger 实例的状态,请运行以下命令:

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

正如我们在上面的屏幕截图中看到的,我们的 Jaeger 实例已启动并正在运行。

开放遥测

要安装 OpenTelemetry,我们需要安装 OpenTelemetry Operator。 OpenTelemetry Operator 使用自定义资源和自定义控制器来扩展具有 OpenTelemetry 特定功能的 Kubernetes API,从而更轻松地在 Kubernetes 环境中部署和管理 OpenTelemetry 可观察性堆栈。

操作员管理两件事:

  • 收集器: 它提供了与供应商无关的如何接收、处理和导出遥测数据的实现。
  • 使用 OpenTelemetry 检测库 自动检测工作负载 。它不需要最终用户修改应用程序源代码。

OpenTelemetry 运算符

要实现自动检测,我们需要在 Kubernetes 集群上部署 OpenTelemetry 操作符。要为 OpenTelemetry 部署 k8s 运算符,请遵循 K8s 运算符文档

您可以通过运行以下命令来验证 OpenTelemetry 运算符的部署:

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

正如我们在上面的输出中看到的,opentelemetry-operator-controller-manager 部署正在 opentelemetry-operator-system 命名空间中运行。

OpenTelemetry 收集器

OpenTelemetry 有助于通过 OpenTelemetry 收集器收集遥测数据。 Collector 在如何接收、处理和导出遥测数据方面提供了与供应商无关的实现。

收集器由以下组件组成:

  • 接收器: 它管理如何将数据放入收集器。
  • 处理器: 它管理数据的处理。
  • Exporters: 负责发送接收到的数据。

我们还需要将遥测数据导出到 Jaeger 实例。使用以下清单部署收集器。

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

在上面的代码中,Jaeger 端点是在可观察性命名空间内运行的 Jaeger 服务的地址。

我们需要将此清单部署在部署应用程序的同一名称空间中,以便它可以从应用程序中获取跟踪并将它们导出到 Jaeger。

要验证收集器的部署,请运行以下命令。

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

OpenTelemetry 自动检测注入

上面部署的操作员可以在应用程序运行时将 OpenTelemetry 的自动检测库注入和配置到应用程序的代码库中。要在我们的集群上启用自动检测,我们需要使用 SDK 和检测的配置来配置检测资源。

使用下面给出的清单来创建自动检测。

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

在上面的清单中,我们使用了三个东西: exporter, propagator, and sampler

  1. Exporter :用于将数据发送到指定端点的 OpenTelemetry 收集器。在我们的场景中,它是“ http://otel-collector:4317 ”。

  2. 传播者 :在分布式跟踪系统之间承载跟踪、上下文和行李数据。它们具有三种传播机制:

    • tracecontext :这是指 W3C Trace Context 规范,它定义了在服务之间传播跟踪上下文信息的标准方式。

    • baggage :这是指 OpenTelemetry baggage 机制,它允许传播任意键值对以及跟踪上下文信息。

    • b3 :这是指 B3 标头格式,这是 Zipkin 跟踪系统使用的一种流行的跟踪上下文传播格式。

  3. 采样器 :使用“基于父级的跟踪 ID 比率”策略,采样率为 0.25 (25%)。这意味着在跟踪一个请求时,如果它的任何父请求已经被采样(概率为0.25),那么这个请求也会被采样,否则不会被跟踪。

要验证我们的自定义资源是否已创建,我们可以使用下面提到的命令。

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

这意味着我们的自定义资源创建成功。

我们正在使用 OpenTelemetry 自动检测方法,因此我们不需要在我们的应用程序中编写检测代码。我们需要做的就是在应用程序的 pod 中添加一个注解以进行自动检测。

由于我们要演示 Java 应用程序,因此我们必须在此处使用的注释是:

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

注意:注解也可以添加到命名空间,以便该命名空间内的所有 pod 都将得到检测,或者通过将注解添加到单个 PodSpec 对象,作为 Deployment、Statefulset 和其他资源的一部分提供。

下面是添加注释后您的清单的外观示例。在下面的示例中,我们正在为 Java 应用程序使用注解。

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

我们在注释下添加了检测“inject-java”和“container-name”。如果您有多个容器 pod,则可以将它们添加到相同的“容器名称”注释中,以逗号分隔。例如,“container-name1,container-name-2,container-name-3”等。

添加注释后,部署您的应用程序并在浏览器上访问它。在我们的场景中,我们使用端口转发来访问应用程序。

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

要生成跟踪,您可以浏览本网站的所有页面,也可以使用以下 Bash 脚本:

$ kubectl get all -n observability

NAME READY STATUS RESTARTS AGE pod/elasticsearch-0 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None 9200/TCP,9300/TCP 17m

NAME READY AGE statefulset.apps/elasticsearch 1/1 17m

上面给出的脚本将向网站的所有页面发出 curl 请求,我们将在 Jaeger UI 上看到请求的痕迹。我们正在向 https://localhost:8080 发出 curl 请求,因为我们使用端口转发技术来访问应用程序。您可以根据您的情况在 Bash 脚本中进行更改。

现在让我们访问 Jaeger UI,因为我们的服务 jaeger-query 使用服务类型 LoadBalancer ,我们可以使用负载均衡器域/IP 在浏览器上访问 Jaeger UI。

将负载均衡器域/IP 粘贴到浏览器上,您将在那里看到 Jaeger UI。我们必须从服务列表中选择我们的应用程序,它会向我们显示它生成的痕迹。

在上面的截图中,我们在服务选项下选择了我们的应用程序名称“demo-sagar”,它的踪迹在 Jaeger UI 上可见。我们可以进一步单击跟踪以获取有关它的更多详细信息。

概括

在本文中,我们介绍了如何使用 OpenTelemetry 自动检测方法轻松检测应用程序。我们还了解了如何将这些遥测数据导出到 Elasticsearch 后端并使用 Jaeger 将其可视化。

将 OpenTelemetry 与 Jaeger 集成将帮助您进行监控和故障排除。它还有助于对基于微服务的分布式系统中的任何错误/问题进行根本原因分析、性能/延迟优化、服务依赖性分析等。

我们希望您发现这篇文章内容丰富且引人入胜。

参考