← 返回蜂巢洞察

如何使用OpenTelemetry收集器将Prometheus提供的直方图数据转换为OTLP格式的数据

现代应用程序通常会通过 ` /metrics ` 端点以 Prometheus 格式公开各种指标数据。 在这些指标中,直方图尤其实用。它们能够显示数值落在不同区间的频率,比如 HTTP 请求的耗时、数据库查询的时间,或者队列处理的延迟等。 与简单的平均值不同,直方图能够呈现完整的图像:你可以清楚地看到有多少请求处理得很快,有多少请求处理得很慢,以及那些偶尔出现的异常值是如何影响用户体验的。 例如,在支付系统中,交易数量的突然增加可能会暴露出隐藏的瓶颈。虽然大多数请求会迅速完成,但那一小部分处理速度缓慢的交易却可能对整个系统产生连锁反应,导致重试次数增加、失败率上升,进而影响整体的吞吐量。直方图

现代应用程序通常会通过 `/metrics` 端点以 Prometheus 格式公开各种指标数据。

在这些指标中,直方图尤其实用。它们能够显示数值落在不同区间的频率,比如 HTTP 请求的耗时、数据库查询的时间,或者队列处理的延迟等。

与简单的平均值不同,直方图能够呈现完整的图像:你可以清楚地看到有多少请求处理得很快,有多少请求处理得很慢,以及那些偶尔出现的异常值是如何影响用户体验的。

例如,在支付系统中,交易数量的突然增加可能会暴露出隐藏的瓶颈。虽然大多数请求会迅速完成,但那一小部分处理速度缓慢的交易却可能对整个系统产生连锁反应,导致重试次数增加、失败率上升,进而影响整体的吞吐量。直方图通过展示数值的分布情况,并突出那些被平均值掩盖的异常值,帮助我们尽早发现这些问题。

然而,并非所有的后端服务都能原生理解 Prometheus 标准。许多现代的可观测性平台更倾向于使用 OTLP(OpenTelemetry 协议)。如果直接转发 Prometheus 数据而不进行转换,就可能会导致数据不完整或被错误解读。因此,我们需要一个流程来抓取、转换这些数据,并将其以 OTLP 格式导出,这样才能确保我们的可观测性系统能够保持一致性并具备实际操作价值。

在本文中,我们将使用 OpenTelemetry Collector 来从应用程序的 `/metrics` 端点抓取 Prometheus 直方图数据,将其映射到 OpenTelemetry 的直方图数据模型中,然后通过 OTLP 将这些数据导出到我们的可观测性后端系统中。Collector 充当了连接桥梁的角色,它在保证数据完整性的同时,也确保了与你的监控平台的兼容性。

为了具体说明这一过程,我们将使用一个模拟支付交易的小型 FastAPI 应用程序作为示例。该应用程序会公开两个 Prometheus 指标:`payment_transaction_duration_seconds`(用于记录每笔交易的耗时)和 `payment_transactions_total`(记录已完成交易的数量)。你也可以使用自己开发的应用程序来进行测试,因为任何在 `/metrics` 端点公开 Prometheus 数据的应用程序,其操作方式都是相同的。这就是我们将在本文中从头到尾使用的示例数据。

我们将涵盖的内容:

先决条件

在开始之前,请确保您具备以下条件:

  • 已安装Docker

  • 有一个应用程序,它通过/metrics端点公开Prometheus指标

  • 拥有一个兼容OpenTelemetry的可观测性后端系统

  • 具备关于Prometheus指标的基本知识

  • 了解YAML语言的基础知识

  • 对Docker和OpenTelemetry有基本的熟悉程度

阅读本教程并不需要掌握高级的OpenTelemetry知识。我会一步步讲解Prometheus直方图的工作原理,以及这些数据在通过OpenTelemetry收集器处理时会发生什么变化。

1. 如何使用Prometheus接收器抓取指标

首先,我们需要从应用程序中收集指标。演示应用程序会将它的Prometheus指标公开在/metrics端点上,而Prometheus接收器会定期访问这个端点,并将收集到的指标纳入可观测性处理流程中。您也可以直接查看/metrics端点上的数据,从而了解在收集器读取这些数据之前它们的实际内容。

配置示例:

receivers:
  prometheus:
    config:
      scrape_configs:
        - job_name: payment-demo
          scrape_interval: 15s
          staticConfigs:
            - targets: ["payment-api:8080"]
FastAPI /metrics端点输出的数据,以Prometheus格式展示了支付交易耗时情况

这里背后实际发生了什么:

scrape_interval决定了收集器访问目标端点的频率。在这里我们设置了15秒的间隔;您可以根据自己对指标更新频率的需求,以及应用程序所能承受的负载来调整这个值。

在像支付平台或实时处理服务这样的高吞吐量系统中,设置合适的抓取间隔尤为重要。如果间隔时间过长,可能会错过一些短暂出现的性能问题或临时性错误;而如果间隔时间过短,则可能会导致收集请求过多,从而使系统负担过重,甚至产生过多的网络流量。

targets列出了那些公开Prometheus指标的具体端点。当需要从多个服务中抓取数据时,可以添加多个目标地址。

最后,job_name是一个标识符,它有助于将收集到的指标进行逻辑分类,这样在它们被传输到后端系统后,就更容易进行管理和分析了。

示意图展示了OpenTelemetry收集器如何发现指标目标、分配抓取任务、查询相关端点并最终抓取数据。

2. 转换 Prometheus 直方图

在获取到这些指标数据后,下一步就是对它们进行转换。Prometheus 将直方图以多种时间序列的形式呈现出来:

  • _bucket 用于显示有多少请求的耗时低于某个特定值。

  • _sum 表示所有观测到的耗时值的总和。

  • _count 代表观测到的数据条目数量。

payment_transaction_duration_seconds 直方图记录了每笔支付交易所花费的时间。Prometheus 将该数据以 _bucket_count_sum 这三种形式呈现出来。当 Prometheus 收集器获取到这些指标后,会将其转换为 OpenTelemetry 直方图的数据模型,然后通过 OTLP 导出这些数据,在此过程中所有用于分析交易延迟及计算百分位数的信息都会被保留下来。

如果没有直方图,平均值就无法反映真实的延迟分布情况。例如,如果大多数请求的耗时为 50 毫秒,但有 5% 的请求耗时超过 2 秒,那么 150 毫秒的平均值就会掩盖这一严重的性能问题。而直方图通过记录落入不同延迟区间的数据条目数量,从而呈现出完整的延迟分布情况。

了解这种延迟分布有助于你发现其中的变化,并进一步排查诸如数据库查询缓慢、服务负载过重,或是下游依赖项导致的延迟等问题。

实际的 Prometheus 直方图

以下就是你的实际 /metrics 输出结果示例:

Prometheus /metrics 的输出结果,其中 payment_transaction_duration_seconds 指标以不同延迟区间的直方图形式呈现

而以下则是 OpenTelemetry 所呈现的直方图形式:

OpenTelemetry 收集器输出的结果,其中 payment_transaction_duration_seconds 指标以直方图的形式显示,包括不同的延迟区间及其对应的数据条目数量

上述两种输出方式实际上表示的是相同的数据——即每笔交易所花费的时间。不过,OpenTelemetry 直方图将这三个独立的 Prometheus 数据序列合并成了一个直方图,其中包含了数据条目数量、总和、具体的延迟区间以及每个区间的数据条目数量等信息。

3. 通过 OTLP 导出指标数据

在获取并处理完这些指标数据后,收集器会使用 OTLP 将它们发送到你的可观测性后端系统。OTLP 输出工具会将处理后的指标数据(包括直方图、计数器等信息)传输到后端系统。

exporters:
  otlp:
    endpoint: "otlpbackend.example.com:4317"
    tls:
      insecure: false
endpoint指定了用于接收OTLP指标的后端地址。这个地址通常指向一个中央观测平台,该平台会汇总来自您基础设施中多个服务的指标数据。 tls确保收集器与后端之间的数据传输安全。只有当您有意连接到不使用TLS的终端点时,才应设置insecure: true,例如在某些本地开发环境中。

4. 将各个组件组合起来

我们已经分别了解了管道中的每个组成部分。现在,让我们将它们连接起来,追踪一个指标从应用程序开始,一直传输到后端。

service:
  pipelines:
    metrics:
      receivers: [prometheus]
      exporters: [otlp]

这就是我们的payment_transaction_duration_seconds指标所经过的完整路径,从FastAPI应用程序一直传输到观测后端。上面的图表展示了这一流程。下一节将介绍如何实际运行这个流程,并将其连接到SigNoz。

管道流程:

Pipeline flow architecture

上述架构图显示了一个FastAPI应用程序,它通过//metrics路径暴露指标数据;OpenTelemetry收集器使用Prometheus接收器抓取这些数据,然后对它们进行处理,并通过OTLP将其传输到观测后端。

5. 运行OpenTelemetry收集器

我们将运行整个管道流程,确认交易指标数据能够从应用程序顺利传输到SigNoz。请按照以下步骤操作(下面我会详细说明每个步骤):

  1. 配置SigNoz Cloud:设置收集器将使用的终端点和数据导入密钥。

  2. 启动FastAPI应用程序:该应用程序会在/metrics路径上暴露Prometheus指标数据。

  3. 启动OpenTelemetry收集器:收集器会使用Prometheus接收器开始抓取应用程序的/metrics端点上的数据。

  4. 生成测试交易记录:向应用程序发送请求,以创建用于测量交易时长的数据。

  5. 验证收集器和后端的运行状态:检查收集器的日志,确认整个管道流程正在正常运行;然后打开SigNoz,确认payment_transaction_duration_seconds指标数据已经到达。

  6. 故障排除

5.1 配置SigNoz Cloud

SigNoz提供了用于接收OpenTelemetry收集器所导出指标数据的观测后端。在这个演示中,我们将使用SigNoz Cloud作为观测后端,因此无需在本地进行任何安装操作。

首先,前往signoz.io注册一个免费账户。在SigNoz Cloud控制面板中,选择设置 → 数据采集键选项。该页面会显示您的数据采集URL、所在地区以及数据采集键。

将这些信息添加到项目目录中的.env文件中:

SIGNOZ_ingESTION_KEY=你的实际密钥
SIGNOZ_OTLP_ENDPOINT=ingest..signoz.cloud:443

请将这个数据采集键视为密码,切勿将其提交或公开分享。

在收集器的配置文件中引用这些变量:

exporters:
  otlp:
    endpoint: "${SIGNOZ_OTLP_ENDPOINT}"
    tls:
      insecure: false
    headers:
      signoz-ingestion-key: "${SIGNOZ_ingESTION_KEY}"

接下来,将.env文件添加到.gitignore中,这样这个密钥就不会被提交到代码仓库中:

echo ".env" >> .gitignore

5.2 启动FastAPI应用程序。

在8080端口上启动该应用程序:

uvicorn app.main:app --reload --port 8080

确认应用程序已经成功运行:

curl http://localhost:8080/
FastAPI支付演示程序在127.0.0.1:8080上本地运行,返回JSON响应,证明支付演示功能已正常启动

现在可以查看Prometheus提供的指标数据了:

curl -Ls http://localhost:8080/metrics
浏览器页面显示FastAPI支付演示程序在localhost:8080上成功运行

/metrics端点会公开应用程序的Prometheus指标数据,其中就包括收集器会抓取的payment_transaction_duration_seconds直方图。

5.3 启动收集器

在应用程序已经运行且收集器的配置也已完成之后,就可以启动收集器了:

docker compose up --build
Docker Compose日志显示支付API正在运行,同时收集器也成功抓取到了其 /metrics端点的数据

请查看收集器的日志,以确认数据采集流程是否正常进行,以及指标数据是否正在被处理。

通过这些步骤,系统会生成payment-api镜像,在共享的telemetry网络中启动两个容器,同时收集器也会立即开始使用Prometheus接收器从应用程序中抓取/metrics端点的数据,并自动读取来自.env文件中的数据采集键和URL信息。

5.4 生成测试交易记录

生成处理时间各不相同的交易记录:

curl -X POST "http://localhost:8080/transactions?delay_ms=50"

curl -X POST "http://localhost:8080/transactions?delay_ms=250"

curl -X POST "http://localhost:8080/transactions?delay_ms=2500"

如果希望在直方图中看到更多数据,可以再生成一些请求记录。

这些请求会生成用于记录交易处理时长的数据,这些数据会被保存到payment_transaction_duration_seconds直方图中。收集器会在下一次数据采集时获取这些更新后的指标值。

5.5 确认后端是否已接收数据

打开SigNoz Cloud,然后搜索以下内容:

payment_transaction_duration_seconds

该指标应该以直方图的形式呈现,其各个分桶的统计数据_bucket_sum_count应当被后端系统接收和处理,而不会作为无关的Prometheus指标系列显示出来。

通过OpenTelemetry Collector导出后,SigNoz Metrics Explorer将payment_transaction_duration_seconds以直方图的形式展示,并附带相关的分桶数据、计数和总和信息。

5.6 故障排除

如果指标数据没有正常传输,首先检查日志信息:

docker logs 

查找其中是否包含连接错误、认证失败、数据采集失败或配置错误等信息。

同时还需要验证以下内容:

  • FastAPI应用程序是否正在运行中。

  • 能否正常访问/metrics路径。

  • 收集器是否能够成功连接到该应用程序。

  • SigNoz的端点地址和数据导入配置是否正确。

  • 收集器是否能够读取到.env文件中的配置变量。

  • 接收器和导出器的名称是否与管道配置相匹配。

如果可能的话,可以使用--dry-run参数在部署前进行验证测试。

结论

Prometheus直方图能够通过展示数据在不同分桶中的分布情况,帮助我们更直观地了解交易处理的延迟情况,而不会将所有数据简化为单一的平均值。

在本教程中,我们展示了如何通过OpenTelemetry Collector将FastAPI应用程序/metrics端点提供的payment_transaction_duration_seconds指标数据导入到SigNoz系统中。

Prometheus的接收器会将_bucket_count_sum这些指标系列映射到OpenTelemetry直方图的数据模型中,从而保留交易处理时长的分布信息,便于后端进行分析和处理。

<这使得相同的指标能够从使用 Prometheus 进行数据收集的应用程序中转移到基于 OTLP 的观测平台中,而无需手动重新生成直方图。>

相关文章

技术实践

人工智能评估工程:从零开始构建一款可用于生产环境的大型语言模型评估平台【完整使用手册】

一个令人印象深刻的演示与一个值得信赖的系统之间的差距,其实是通过各种评估来衡量的。 我想先讲一个目前正在数百个工程团队中发生的真实案例。 有一个团队为法律研究开发了一个RAG应用程序。他们用40个精心挑选的问题对该程序进行了测试,结果看起来很不错,于是便向合作方展示了这个系统。合作方对它印象深刻,随后便决定将其正式投入使用。 然而在系统投入生产三周后,一名法律助理发现其中一个答案错误地引用了某项法规。工程团队查看了相关数据,发现“准确性得分”为0.91,这个数值看起来是正常的;他们还检查了答案的相关性,结果也符合标准。 但他们忽略了一个重要的指标:即“上下文完整性”。这个指标用于判断系统是否检

阅读全文
技术实践

移动设备在后台的执行机制:iOS的后台运行模式、Android的WorkManager以及Dart语言中的后台服务功能

每一位移动应用开发者最终都会遇到同样的问题:当用户正在使用应用程序时,它运行得非常正常。 但一旦用户按下主屏幕按钮,所有事情就会出问题。本应在后台完成的同步操作根本没有进行;应该发出的通知也没有出现;用户在应用程序中开始进行的文件上传,在他们离开应用程序的瞬间就无声无息地失败了。 在移动设备上实现后台执行功能,是整个移动开发领域中最容易被误解的话题之一。大多数开发者认为这只是一个简单的问题——只要让代码在后台持续运行即可。而操作系统则将这个问题视为一个直接影响电池寿命、性能以及设备整体运行的资源管理问题。 只有真正了解iOS和Android系统对后台任务的处理方式,再进一步理解Flutter是

阅读全文
技术实践

演讲主题:推动发展:大规模实施自主化的软件开发生命周期管理流程

Andrew Swerdlow讲述了Roblox是如何将自动化软件开发从开发阶段扩展到实际生产环境的。他讨论了如何构建可靠的安全测试环境,如何通过代码审查来挖掘机构内部积累的知识,如何更新工程基础设施,以及如何重新定义衡量生产效率的指标——将这些指标从功能开发的速度转变为AI模型训练的效率——从而实现大规模、可信赖的自动化部署。 作者:Andrew Swerdlow

阅读全文
技术实践

如何使用Python和Neo4j构建知识图谱【完整指南】

你所处理的大部分数据实际上都反映了各种关系:一个客户属于某个账户,某次事件会影响某种服务,而一名工程师负责维护某个代码库。你把所有这些信息存储在表格中,长期以来,这种存储方式一直运行得非常顺利。 然而,有时会有人提出这样的问题: 哪些工程师最近了解过昨晚那次事件所影响的服务情况? 这类问题很容易理解,但编写相应的SQL查询却相当困难。通常需要使用四到五次连接操作,每次连接都会生成一个比最终结果范围更广的中间数据集,而大部分这些中间数据最终都会被丢弃。随着表格规模的扩大,查询速度会变得越来越慢,而且每次查看这个查询语句时,都很难理解其具体逻辑。 为了解决这类问题,人们才创造了图数据库。 在这本手

阅读全文