将 Prometheus 用作 OpenTelemetry 后端
Prometheus 支持通过 OTLP (即“OpenTelemetry 协议”)的HTTP 方式进行数据接收。
启用 OTLP 接收器
默认情况下,OTLP 接收器是禁用的,类似于远程写入接收器。这是因为 Prometheus 可以在没有任何身份验证的情况下工作,因此除非明确配置,否则接受传入流量是不安全的。
要启用接收器,你需要切换 CLI 标志 --web.enable-otlp-receiver。这将使 Prometheus 在 HTTP 路径 /api/v1/otlp/v1/metrics 上提供 OTLP 指标接收服务。
$ prometheus --web.enable-otlp-receiver
将 OpenTelemetry 指标发送到 Prometheus 服务器
通常,你需要告知 OTLP 指标流量的来源关于 Prometheus 端点的信息,以及应使用 OTLP 的HTTP 模式(gRPC 通常是默认值)。
OpenTelemetry SDK 和插桩库通常可以通过标准环境变量 进行配置。以下是将 OpenTelemetry 指标发送到本地 Prometheus 服务器所需的 OpenTelemetry 变量:
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://:9090/api/v1/otlp/v1/metrics
关闭跟踪和日志
export OTEL_TRACES_EXPORTER=none
export OTEL_LOGS_EXPORTER=none
OpenTelemetry 指标的默认推送间隔是 60 秒。以下设置将推送间隔设为 15 秒:
export OTEL_METRIC_EXPORT_INTERVAL=15000
如果你的插桩库没有开箱即用地提供 service.name 和 service.instance.id,强烈建议设置它们。
export OTEL_SERVICE_NAME="my-example-service"
export OTEL_RESOURCE_ATTRIBUTES="service.instance.id=$(uuidgen)"
以上假设你的系统上可用 uuidgen 命令。请确保 service.instance.id 对每个实例都是唯一的,并且每当资源属性更改时都会生成一个新的 service.instance.id。 推荐的 做法是在每个实例启动时生成一个新的 UUID。
配置 Prometheus
本节解释了 Prometheus 服务器的各种推荐配置,以启用和调整你的 OpenTelemetry 流程。
请参阅我们将在下文使用的示例 Prometheus 配置文件 。
启用乱序接收
你可能希望启用乱序接收的原因有很多。
例如,OpenTelemetry 收集器鼓励批处理,你可能有多个收集器副本向 Prometheus 发送数据。由于没有机制对这些样本进行排序,它们可能会变得乱序。
要启用乱序接收,你需要使用以下内容扩展 Prometheus 配置文件:
storage:
tsdb:
out_of_order_time_window: 30m
30 分钟的乱序时间对于大多数情况已经足够,但请随时根据你的需求调整此值。
提升资源属性
根据经验和与我们社区的交流,我们发现,在所有常见的资源属性中,有一些值得附加到你所有的 OTLP 指标上。
默认情况下,Prometheus 不会提升任何属性。如果你想提升它们中的任何一个,可以在 Prometheus 配置文件的这一部分进行操作。以下代码片段分享了要提升的最佳实践属性集:
otlp:
# Recommended attributes to be promoted to labels.
promote_resource_attributes:
- service.instance.id
- service.name
- service.namespace
- service.version
- cloud.availability_zone
- cloud.region
- container.name
- deployment.environment
- deployment.environment.name
- k8s.cluster.name
- k8s.container.name
- k8s.cronjob.name
- k8s.daemonset.name
- k8s.deployment.name
- k8s.job.name
- k8s.namespace.name
- k8s.pod.name
- k8s.replicaset.name
- k8s.statefulset.name
在查询时包含资源属性
默认情况下,除了 service.instance.id、service.namespace 和 service.name 之外,所有 OTel 资源属性都会被转换为特殊指标 target_info 上的标签。这意味着,对于你没有提升的 OTel 资源属性,你仍然可以通过与 target_info 连接来在查询中包含相应的标签。为了实现这一点,我们建议通过以下标志启用实验性的 PromQL 函数 info 以方便连接:
--enable-feature=promql-experimental-functions
此类查询的示例如下所示:
info(rate(http_server_request_duration_seconds_count[2m]), {k8s_cluster_name=~".+"})
或者,同样的事情也可以通过原始的连接查询来完成:
rate(http_server_request_duration_seconds_count[2m])
* on (job, instance) group_left (k8s_cluster_name)
target_info
在上面两个查询中发生的事情是,rate(http_server_request_duration_seconds_count[2m]) 产生的时间序列被 target_info 序列中的 k8s_cluster_name 标签增强了,这些序列共享相同的 job 和 instance 标签。换句话说,job 和 instance 标签在 http_server_request_duration_seconds_count 和 target_info 之间共享,类似于 SQL 的外键。而 k8s_cluster_name 标签则对应于 OTel 资源属性 k8s.cluster.name(除非另有配置,Prometheus 会将点转换为下划线)。
但请注意,info 函数通常比原始连接查询性能更好,因为它只选择具有匹配 job 和 instance 标签的 target_info 序列。也许更重要的是,info 函数解决了一个古老且相当深奥的连接查询方法问题。当连接所依据的标签(即所谓的标识标签)之外的其他标签的值发生变化(即流失)时,除非旧的 target_info 版本被标记为陈旧,否则在 PromQL 回溯窗口(默认为 5 分钟)的持续时间内,旧版本和新版本的 target_info 会存在重叠。在此期间,针对 target_info 的连接查询会因为存在两个匹配的不同 target_info 时间序列而失败。幸运的是,info 函数没有这个问题,因为它总是选择具有最新样本的时间序列!
那么,target_info 指标与 OTel 资源属性之间有什么关系呢?当 Prometheus 处理 OTLP 写入请求时,如果包含的资源包含 service.instance.id 和/或 service.name 属性,Prometheus 会为每个(OTel)资源生成信息指标 target_info。它会为每个这样的 target_info 序列添加标签 instance(值为 service.instance.id 资源属性)和标签 job(值为 service.name 资源属性)。如果存在 service.namespace 资源属性,它会作为前缀加到 job 标签值前面(即 <service.namespace>/<service.name>)。
默认情况下,service.name、service.namespace 和 service.instance.id 本身不会添加到 target_info 中,因为它们被转换为了 job 和 instance。但是,可以启用以下配置参数,将它们直接添加到 target_info 中(如果 otlp.translation_strategy 为 UnderscoreEscapingWithSuffixes,则会进行归一化,用下划线替换点),同时保留其到 job 和 instance 的转换。
otlp:
keep_identifying_resource_attributes: true
其余的资源属性也会作为标签添加到 target_info 序列中,如果 otlp.translation_strategy 是 UnderscoreEscapingWithSuffixes,名称会转换为 Prometheus 格式(例如,点转换为下划线)。如果资源同时缺少 service.instance.id 和 service.name 属性,则不会生成相应的 target_info 序列。
对于资源的每个 OTel 指标,Prometheus 会将其转换为相应的 Prometheus 时间序列,并(如果生成了 target_info)为其添加正确的 instance 和 job 标签。
UTF-8
从 3.x 版本开始,Prometheus 支持指标名称和标签使用 UTF-8,因此可以省略 OpenTelemetry 的Prometheus 归一化翻译器包 。请注意,当 Prometheus 通过内容协商宣布它允许 UTF-8 字符时,它并不要求指标名称包含以前不支持的字符。OTLP 指标可以根据端点的配置以多种不同的方式进行转换。因此,虽然 UTF-8 在 Prometheus 存储和 UI 中默认启用,但你需要为 OTLP 指标接收器设置 translation_strategy,默认情况下该值设置为旧的归一化方式 UnderscoreEscapingWithSuffixes。
有四种可能的翻译策略,其中两种需要 Prometheus 启用 UTF-8 支持:
UnderscoreEscapingWithSuffixes,默认值。这将完全转义指标名称以实现经典的Prometheus 指标名称兼容性,并包括附加类型和单位后缀。UnderscoreEscapingWithoutSuffixes。这将完全转义指标名称,类似于 UnderscoreEscapingWithSuffixes,但不附加类型和单位后缀。这种模式从多个角度来看都是不可取的,用户应该意识到缺少后缀可能会导致指标名称冲突,只有在经过仔细测试后才能启用此模式。一些组织倾向于这种 Otel 对称性和有限字符支持的平衡,因此会使用它。NoUTF8EscapingWithSuffixes将禁用将特殊字符更改为_,这允许原生使用 OpenTelemetry 指标格式,尤其是与语义约定 一起使用时。请注意,像单位和计数器的_total这样的特殊后缀将被附加,以防止同名但不同类型或单位的多个指标可能发生冲突。此模式需要启用 UTF-8。NoTranslation。此策略绕过所有指标和标签名称的翻译,将它们原封不动地传递。此模式需要启用 UTF-8。请注意,如果没有后缀,当多个同名但不同类型或单位的指标存在时,可能会发生冲突。
otlp:
# Ingest OTLP data keeping UTF-8 characters in metric/label names.
translation_strategy: NoTranslation
增量时间性(Delta Temporality)
OpenTelemetry 规范指出 ,同时支持增量时间性(Delta temporality)和累积时间性(Cumulative temporality)。虽然增量时间性在 statsd 和 graphite 等系统中很常见,但累积时间性是 Prometheus 中的默认设置。
如今,Prometheus 内嵌了来自 OpenTelemetry-Collector-contrib 的增量到累积处理器 ,它能够接收增量数据并将其转换为等效的累积表示,然后存储在 Prometheus 的时序数据库(TSDB)中。
此功能是实验性的,因此启动 Prometheus 时需启用功能标志 otlp-deltatocumulative 才能使用它。
团队仍在努力寻找一种更有效处理 OTLP 增量数据的方法。