当 OpenTelemetry 遇上阿里云 Prometheus

作者:逸陵

背景

在云原生可观测蓬勃发展的当下,想必大家对 OpenTelemetry & Prometheus 并不是太陌生。OpenTelemetry 是 CNCF(Cloud Native Computing Foundation)旗下的开源项目,它的目标是在云原生时代成为应用性能监控领域的事实标准,它提供了一套统一的 API 和 SDK,用于生成、收集和处理分布式系统的遥测数据。总而言之,OpenTelemetry 是一套观察性的标准,具有语言无关性,支持各种编程语言和框架,并可与多种观察平台集成。

而 Prometheus 作为目前最受欢迎的开源监控系统,并且已经被 Kubernetes、Envoy 等广泛使用的云原生项目所采用。虽然 Prometheus 的查询语言十分强大,但是其数据格式还是 Prometheus 自己定义的。因此,它只能与 Prometheus 服务器集成,不能与其他系统集成。

而 OpenTelemetry 承诺在 Trace、Log 和 Metric 之间创建一个统一标准,所以它的数据格式是统一的,并具有足够的灵活性与交互性,同时完全兼容 Prometheus,所以吸引越来越多的开发运维人员使用 OpenTelemetry 在承载 Trace & Log 同时将其用于 Metric 的统计,与 Prometheus 生态进行结合,实现更好的观测监控。

图片

本文以构建系统可观测(重点为指标监控体系)为切入点,对比 OpenTelemetry 与 Prometheus 的相同与差异,粗浅的谈下个人选择的一些观点与看法;后重点介绍如何将应用的 OpenTelemetry 指标接入 Prometheus 及背后原理,最后介绍阿里云可观测监控 Prometheus 版拥抱 OpenTelemetry 及相关落地实践案例,希望能更好的帮助读者更好的理解 OpenTelemetry 及与 Prometheus 的生态融合。

站在 OpenTelemetry 与 Prometheus 的十字路口

如果你作为研发运维人员在进行系统观测时,特别是构建指标监控体系时,会有很多困惑,到底选择 OpenTelemetry 还是 Prometheus。在回答这个问题之前我们首先需要明确的了解 OpenTelemetry 与 Prometheus 的同异。

图片

而在对比之前,我们还是有必要对 OpenTelemetry 的指标模型进行深入的介绍。

2.1 OpenTelemetry 指标模型介绍

OpenTelemetry 将指标分解为三个交互模型,事件模型、Timeseries 模型以及指标(Metric)流模型。其中事件模型表示仪器如何报告指标数据;Timeseries 模型表示后端如何存储指标数据;指标(Metric)流模型定义 OpenTelemetry 协议 (OTLP),表示如何在事件模型和时间序列存储之间操作和传输指标数据流。

2.1.1 事件模型

事件模型是数据记录发生的地方,它的基础由 Instruments [ 1] 组成,Instruments 用于通过事件记录可观测数据。然后,这些原始事件在发送到其他系统之前以某种方式进行转换。OpenTelemetry 指标的设计使得使用相同的 Instruments 和事件使用不同的方式来生成 metric 指标流。

图片

尽管观测事件可以直接报告给后端,但实际上这是不可行的,因为可观测系统中使用的数据量巨大,并且可用于遥测收集目的的网络/CPU 资源有限,最好的例子是直方图指标,其中原始事件以压缩格式而不是单个时间序列记录。

注意:上图显示了一个 Instrument 如何将事件转换为多种类型的指标流。

2.1.2 时间序列模型

在 low-level 指标数据模型中,时间序列是由多个元数据属性组成的实体定义:

  • 指标名称
  • 属性(维度)
  • 点的值类型(整数、浮点数等)
  • 测量单位

每个时间序列的原始数据都是有序的(时间戳,值)点,其值类型如下:

  • Counter
  • Gauge
  • Histogram
  • Exponential Histogram
2.1.3 OpenTelemetry 协议数据模型

OpenTelemetry 协议(OTLP)数据模型由 Metric 数据流组成,这些流又由度量数据点组成,指标数据流可以直接转换为时间序列。指标流被分组为单独的指标对象,通过以下方式标识:

  • 原始 Resource 属性
  • Instrumentation Scope(例如 instrumentation lib 名称、版本)
  • 指标流的 name

包括 name 在内,Metric 对象由以下属性定义:

  • 数据点类型(例如 Sum、Gauge、Histogram、ExponentialHistogram、Summary)
  • 指标流的单位(unit)
  • 指标流的描述(description)
  • 内部数据点属性(如果适用):AggregationTemporality、Monotonic

数据点类型、单位和内在属性被认为是识别性的,而描述字段本质上不具备识别性。特定点的外在属性不被视为识别;这些包括但不限于:

  • 直方图(Histogram)数据点的桶边界
  • 指数直方图(ExponentialHistogram)数据点的大小或桶数量

Metric 对象包含不同流,由 Attributes 标识。在各个流中,点由一个或者两个时间戳标识,详细信息因数据点类型而异。

2.1.4 点类型介绍
2.1.4.1 Sum

OTLP 中的 Sums [ 2] 由以下部分组成:

  1. 增量(delta)或累积(cumulative)的 Aggregation Temporality。2. 一个表示 Sum 是否单调(monotonic [ 3] )的标志。
  • 对于增量单调(delta monotonic) Sums,这意味着读者应该期望非负值
  • 对于累积单调(cumulative monotonic) Sums,这意味着读者应该期望不小于先前值的值

一组数据点,每个数据点包含:

  • 一组独立的属性名称-值对
  • 计算 Sum 的时间窗口
  • (可选)一组 examplars [ 4]

当聚合时间性为"delta"时,我们期望度量流的时间窗口没有重叠,如下图所示:

图片

而当与聚合时间性为"cumulative"的时候,我们期望报告自“开始”以来的全部总和(其中通常开始意味着进程/应用程序启动)。

图片

在各种用例中,使用 Delta 与累积聚合之间存在各种权衡,例如:

  • 检测进程重新启动
  • 计算 rate
  • 基于推与拉的指标报告

OTLP 支持这两种模型,并允许 API、SDK 和用户在其各自的场景中确定最佳的折衷方案。

2.1.4.2 Gauge

OTLP 中的 Gauge [ 5] 表示给定时间的采样值。Gauge 流包括一组数据点,每个数据点包含:

  • 一组独立的属性名称-值对
  • 采样值(例如当前 CPU 温度)
  • 对值进行采样时的时间戳(time_unix_nano)
  • (可选)时间戳(start_time_unix_nano),它最能代表可以记录测量的第一个可能时刻,这通常设置为指标收集系统启动时的时间戳
  • (可选)一组 examplars

在 OTLP 中,Gauge 流中的点表示给定时间窗口的最后采样事件。

图片

在此示例中,我们可以看到我们使用 Gauge 采样的基础时间序列,虽然事件模型可以在给定的指标报告间隔内多次采样,但通过 OTLP 在指标流中仅报告最后一个值。

Gauge 不提供聚合语义,而是在执行时间对齐或调整分辨率等操作时使用“最后一个样本值”。可以通过转换为直方图或其他度量类型来聚合 Gauge。这些操作默认情况下不执行,需要用户直接配置。

2.1.4.3 Histogram

Histogram [ 6] 度量数据点以压缩格式传达大量记录的测量结果。直方图将一组事件分为为多个群体,并提供总体事件计数和所有事件的总和。

图片

直方图 Histogram 由以下部分组成:

  1. 增量(delta)或累积(cumulative)的 Aggregation Temporality2. 一组数据点,每个数据点包含:
  • 一组独立的属性名称-值对
  • 捆绑直方图的时间窗口((start, end])
  • 直方图中点总数的计数(count)
  • 直方图中所有值的总和(sum)
  • (可选)直方图中所有值的最小值(min)
  • (可选)直方图中所有值的最大值(max)
  • (可选)一系列桶:明确的边界值,这些值表示存储桶的下限和上限,以及是否将给定的观察结果记录在该存储桶中;属于该存储桶的观测值数量的计数。
  • (可选)一组 examplars

与 Sums 一样,直方图也定义聚合时间性。上图表示 Delta 时间性,其中累积的事件计数在报告后重置为零,并发生新的聚合。另一方面,累积继续聚合事件,并使用新的开始时间进行重置。聚合时间性 Aggregation Temporality 也对最小和最大字段有影响,最小值和最大值对于增量时间性(Delta)更有用,因为随着记录更多事件,累积最小值和最大值表示的值将稳定。此外,可以将最小值和最大值从 Delta 转换为 Cumulative,但不能从 Cumulative 转换为 Delta。从累积转换为增量时,可以删除最小值和最大值,或者以替代表示形式(例如仪表)捕获最小值和最大值。

桶数是可选的。没有桶的直方图仅根据总和和计数来传达总体,并且可以解释为具有单桶覆盖的直方图(-Inf,+Inf),如下为 Cumulative 型 Histogram 样例数据。

2023-11-29T13:43:45.238Z  info  ResourceMetrics #0
Resource SchemaURL: 
Resource attributes:
     -> service.name: Str(opentelemetry-metric-demo-delta-or-cumulative)
     -> service.version: Str(0.0.1)
     -> telemetry.sdk.language: Str(java)
     -> telemetry.sdk.name: Str(opentelemetry)
     -> telemetry.sdk.version: Str(1.29.0)
ScopeMetrics #0
ScopeMetrics SchemaURL: 
InstrumentationScope aliyun 
Metric #0
Descriptor:
     -> Name: cumulative_long_histogram
     -> Description: ot cumulative demo cumulative_long_histogram
     -> Unit: ms
     -> DataType: Histogram
     -> AggregationTemporality: Cumulative
HistogramDataPoints #0
StartTimestamp: 2023-11-29 13:43:15.181 +0000 UTC
Timestamp: 2023-11-29 13:43:45.182 +0000 UTC
Count: 2
Sum: 141.000000
Min: 62.000000
Max: 79.000000
ExplicitBounds #0: 0.000000
ExplicitBounds #1: 5.000000
ExplicitBounds #2: 10.000000
ExplicitBounds #3: 25.000000
ExplicitBounds #4: 50.000000
ExplicitBounds #5: 75.000000
ExplicitBounds #6: 100.000000
ExplicitBounds #7: 250.000000
ExplicitBounds #8: 500.000000
ExplicitBounds #9: 750.000000
ExplicitBounds #10: 1000.000000
ExplicitBounds #11: 2500.000000
ExplicitBounds #12: 5000.000000
ExplicitBounds #13: 7500.000000
ExplicitBounds #14: 10000.000000
Buckets #0, Count: 0
Buckets #1, Count: 0
Buckets #2, Count: 0
Buckets #3, Count: 0
Buckets #4, Count: 0
Buckets #5, Count: 1
Buckets #6, Count: 1
Buckets #7, Count: 0
Buckets #8, Count: 0
Buckets #9, Count: 0
Buckets #10, Count: 0
Buckets #11, Count: 0
Buckets #12, Count: 0
Buckets #13, Count: 0
Buckets #14, Count: 0
Buckets #15, Count: 0
2.1.4.4 ExponentialHistogram

指数直方图数据点是直方图数据点的替代表示形式,用于以压缩格式传达一组记录的测量值。ExponentialHistogram 使用指数公式压缩桶边界,与类似大小的替代表示相比,使其适合以较小的相对误差传输高动态范围数据。

直方图 Histogram 涉及聚合时间性、属性和时间戳以及 sum、count、min、max 和 exemplars 字段,ExponentialHistogram 与 Histogram 类似,这些字段都与直方图 Histogram 具有相同的解释,只是这两种类型之间的存储 bucket 结构不同。如下为一个 delta 形式的 ExponentialHistogram 数据格式:

2023-11-29T13:13:09.866Z  info  ResourceMetrics #0
Resource SchemaURL: 
Resource attributes:
     -> service.name: Str(opentelemetry-metric-demo-delta-or-cumulative)
     -> service.version: Str(0.0.1)
     -> telemetry.sdk.language: Str(java)
     -> telemetry.sdk.name: Str(opentelemetry)
     -> telemetry.sdk.version: Str(1.29.0)
ScopeMetrics #0
ScopeMetrics SchemaURL: 
InstrumentationScope aliyun 
Metric #0
Descriptor:
     -> Name: cumulative_long_e_histogram
     -> Description: ot cumulative demo cumulative_long_e_histogram
     -> Unit: ms
     -> DataType: ExponentialHistogram
     -> AggregationTemporality: Cumulative
ExponentialHistogramDataPoints #0
StartTimestamp: 2023-11-29 13:11:54.858 +0000 UTC
Timestamp: 2023-11-29 13:13:09.86 +0000 UTC
Count: 3
Sum: 191.000000
Min: 15.000000
Max: 89.000000
Bucket (14.993341, 15.321652], Count: 1
Bucket (15.321652, 15.657153], Count: 0
Bucket (15.657153, 16.000000], Count: 0
Bucket (16.000000, 16.350354], Count: 0
Bucket (16.350354, 16.708381], Count: 0
Bucket (16.708381, 17.074246], Count: 0
Bucket (17.074246, 17.448124], Count: 0
Bucket (17.448124, 17.830188], Count: 0
Bucket (17.830188, 18.220618], Count: 0
Bucket (18.220618, 18.619598], Count: 0
Bucket (18.619598, 19.027314], Count: 0
Bucket (19.027314, 19.443958], Count: 0
Bucket (19.443958, 19.869725], Count: 0
Bucket (19.869725, 20.304815], Count: 0
Bucket (20.304815, 20.749433], Count: 0
Bucket (20.749433, 21.203786], Count: 0
Bucket (21.203786, 21.668089], Count: 0
Bucket (21.668089, 22.142558], Count: 0
Bucket (22.142558, 22.627417], Count: 0
Bucket (22.627417, 23.122893], Count: 0
Bucket (23.122893, 23.629218], Count: 0
Bucket (23.629218, 24.146631], Count: 0
Bucket (24.146631, 24.675373], Count: 0
Bucket (24.675373, 25.215694], Count: 0
Bucket (25.215694, 25.767845], Count: 0
Bucket (25.767845, 26.332088], Count: 0
Bucket (26.332088, 26.908685], Count: 0
Bucket (26.908685, 27.497909], Count: 0
Bucket (27.497909, 28.100035], Count: 0
Bucket (28.100035, 28.715345], Count: 0
Bucket (28.715345, 29.344129], Count: 0
Bucket (29.344129, 29.986682], Count: 0
Bucket (29.986682, 30.643305], Count: 0
Bucket (30.643305, 31.314306], Count: 0
Bucket (31.314306, 32.000000], Count: 0
Bucket (32.000000, 32.700709], Count: 0
Bucket (32.700709, 33.416761], Count: 0
Bucket (33.416761, 34.148493], Count: 0
Bucket (34.148493, 34.896247], Count: 0
Bucket (34.896247, 35.660376], Count: 0
Bucket (35.660376, 36.441236], Count: 0
Bucket (36.441236, 37.239195], Count: 0
Bucket (37.239195, 38.054628], Count: 0
Bucket (38.054628, 38.887916], Count: 0
Bucket (38.887916, 39.739450], Count: 0
Bucket (39.739450, 40.609631], Count: 0
Bucket (40.609631, 41.498866], Count: 0
Bucket (41.498866, 42.407573], Count: 0
Bucket (42.407573, 43.336178], Count: 0
Bucket (43.336178, 44.285116], Count: 0
Bucket (44.285116, 45.254834], Count: 0
Bucket (45.254834, 46.245786], Count: 0
Bucket (46.245786, 47.258437], Count: 0
Bucket (47.258437, 48.293262], Count: 0
Bucket (48.293262, 49.350746], Count: 0
Bucket (49.350746, 50.431387], Count: 0
Bucket (50.431387, 51.535691], Count: 0
Bucket (51.535691, 52.664175], Count: 0
Bucket (52.664175, 53.817371], Count: 0
Bucket (53.817371, 54.995818], Count: 0
Bucket (54.995818, 56.200069], Count: 0
Bucket (56.200069, 57.430690], Count: 0
Bucket (57.430690, 58.688259], Count: 0
Bucket (58.688259, 59.973364], Count: 0
Bucket (59.973364, 61.286610], Count: 0
Bucket (61.286610, 62.628612], Count: 0
Bucket (62.628612, 64.000000], Count: 0
Bucket (64.000000, 65.401418], Count: 0
Bucket (65.401418, 66.833522], Count: 0
Bucket (66.833522, 68.296986], Count: 0
Bucket (68.296986, 69.792495], Count: 0
Bucket (69.792495, 71.320752], Count: 0
Bucket (71.320752, 72.882473], Count: 0
Bucket (72.882473, 74.478391], Count: 0
Bucket (74.478391, 76.109255], Count: 0
Bucket (76.109255, 77.775831], Count: 0
Bucket (77.775831, 79.478900], Count: 0
Bucket (79.478900, 81.219261], Count: 0
Bucket (81.219261, 82.997731], Count: 0
Bucket (82.997731, 84.815145], Count: 0
Bucket (84.815145, 86.672355], Count: 0
Bucket (86.672355, 88.570232], Count: 1
Bucket (88.570232, 90.509668], Count: 1

2.1.4.4.1 Exponential Scale

指数直方图的分辨率由 scale 参数来表征,scale 值越大,精度越高。指数直方图的 bucket 边界位于 base 的整数次幂,也称为“增长因子”,其中:

base = 2**(2**(-scale))

这些公式中的符号 ** 表示求幂,因此 2**x 读作“2 的 x 次方”,通常由 math.Pow(2.0, x) 等表达式计算,如下为 OpenTelemetry 官方中的样例,所选 scale 的计算 base 如下所示:

图片

该设计的一个重要属性被描述为“完美子集”,具有给定比例的指数直方图的桶精确地映射到具有较小比例的指数直方图的桶中,这允许消费者降低直方图的分辨率(即缩小比例)而不会引入误差。上述 delta ExponentialHistogram 数据使用默认的 Base2ExponentialHistogramAggregation,其中 max scale 为 20。

private static final int DEFAULT_MAX_BUCKETS = 160;
    private static final int DEFAULT_MAX_SCALE = 20;
    private static final Aggregation DEFAULT = new Base2ExponentialHistogramAggregation(160, 20);
    private final int maxBuckets;
    private final int maxScale;

    private Base2ExponentialHistogramAggregation(int maxBuckets, int maxScale) {
        this.maxBuckets = maxBuckets;
        this.maxScale = maxScale;
    }

    public static Aggregation getDefault() {
        return DEFAULT;
    }

    public static Aggregation create(int maxBuckets, int maxScale) {
        Utils.checkArgument(maxBuckets >= 1, "maxBuckets must be > 0");
        Utils.checkArgument(maxScale <= 20 && maxScale >= -10, "maxScale must be -10 <= x <= 20");
        return new Base2ExponentialHistogramAggregation(maxBuckets, maxScale);
    }

2.1.4.4.2 Exponential Buckets

由索引(有符号整数)标识的指数直方图桶表示总体中大于基数索引且小于或等于基数(索引+1)的值,直方图的正负范围分别表示。使用与正值范围相同的比例,将负值按其绝对值映射到负值范围。请注意,因此,在负范围内,直方图桶使用下限边界。ExponentialHistogram 数据点的每个范围都使用桶的密集表示,其中桶的范围表示为单个偏移值、有符号整数和计数值数组,其中数组元素 i 表示桶索引的桶计数偏移 +i。

对于给定范围(正数或负数):

  • 存储 bucket 索引 0 对范围 (1, base] 内的测量进行计数
  • 正索引对应于大于 base 的绝对值
  • 负索引对应于绝对值小于或等于 1
  • 连续的 2 次幂之间有 2** scale 个 bucket

例如,当 scale=3 时,1和2之间有 2**3 个桶,请注意,scale=3 直方图中存储桶索引 4 的下边界映射到 scale=2 直方图中存储桶索引 2 的下边界,并映射到 scale=3 直方图中存储桶索引 1(即基数)的下边界。1 个直方图——这些是完美子集的示例。

图片

Ps:由于最新版本中 Summay 已经不推荐,所以这里不做详细的介绍。

2.2 OpenTelemetry VS Prometheus

在本文中我们就不详细的介绍 Prometheus 的指标类型了,详细介绍参考 Prometheus 官网介绍 [ 7] 。我们通过对比 OpenTelemetry 指标类型以及 Prometheus 指标类型,我们会发现:

  • OpenTelemetry 可以将 Metric 表示为增量,而不是累计,存储每个数据点之间的差异,而不是累计总和。然而Prometheus 在设计上不允许这样做。
  • OpenTelemetry 允许 Metric 值为整数,而 Prometheus 无法表达浮点数。
  • OpenTelemetry 可以将一些额外的元数据附加到直方图中,允许您跟踪最大值和最小值,这一点在有些场景是非常有用的。
  • OpenTelemetry 具有指数直方图聚合类型(使用公式和刻度来计算 bucket 大小),Prometheus 不支持,但是可以实现兼容。

从上面的模型对比总结来说,OpenTelemetry 允许表示所有 Prometheus 度量类型(计数器、仪表、摘要和直方图),尽管如此 Prometheus 无法表示 OpenTelemetry 度量的某些配置,包括 delta 表示和指数直方图(尽管这些将很快添加到 Prometheus 中)以及整数值。所以换句话说,Prometheus 度量是 OpenTelemetry 度量的严格子集。

图片

尽管这样,但是两者还是存在一些差异的,这里需要强调一下。

  • Prometheus 提供 Metric 收集、存储和查询,它通过通过抓取目标来采集集指标,当然也可以通过 pushgateway形式,相关 Metric 数据最后存储在 Prometheus 本地数据库或者其他远端时许数据库中,最后通过 Prometheus 查询语言 PromQL 进行数据的读取,所以 Prometheus 是一个完整的可观测解决方法,集数据的采集、计算、存储、报警、查询等于一体。
  • OpenTelemetry 作用域要小很多。它通过推送或拉取使用整合的 API 收集指标(以及跟踪和日志),并将其发送到其他系统进行存储或查询。所以 OpenTelemetry 只关注应用程序交互的可观测性部分,从而将信号的创建与存储和查询信号的操作问题脱钩。所以在指标的存储上 OpenTelemetry Metric 通常回到 Prometheus 或者 Prometheus 兼容的系统中。

2.3 如何选择

不可否认 OpenTelemetry 与 Prometheus 都是非常优秀的,有时候选择上确实会比较纠结,所以总的原则还是结合实际的业务场景出发,因地制宜,以发展的眼光看待问题。如下的浅谈如有不妥欢迎交流、批评与指正。

  • 如果你尝试构建统一的可观测体系包含 Trace、Log 和 Metric,那么 OpenTelemetry 将允许使用相同的库来对所有三种信号类型进行检测,减少包依赖,方便运维管理。这是一个显著的好处,可以将三种相同的信号发送到同一一个后端也可以发送到不同的后端,OpenTelemetry 都支持。
  • 如果你希望你的应用/系统/组件在云原生、容器化的场景下监控指标能更好的被观测,特别是开源、被第三方使用的场景,这种场景一般建议使用 Prometheus,比如常见的中间 Redis、MySQL、Zookeeper 等都支持 Prometheus Exporter 形式暴露指标。
  • 比如特殊的网络环境或者其他限制条件下,不能采用 Prometheus pull 形式,但在 Prometheus pushgateway 形式又存在多种弊端的情况下,可以尝试使用 OpenTelemetry push 形式。

但无论如何选择,有点尴尬的就是即使客户端选择了 OpenTelemetry,实际情况 OpenTelemetry Metric 存储往往回到了 Prometheus 上。这也是当前的现状,大多数组织可能会混合使用这两种标准:用于基础设施监控的 Prometheus,利用更成熟的集成生态系统从数百个组件中提取指标,以及用于已开发服务的 OpenTelemetry。

图片

下一章节,我们重点介绍如何将 OpenTelemetry 指标接入到 Prometheus。

如何将 OpenTelemetry Metric 接入 Prometheus

3.1 原理介绍

将 OpenTelemetry 指标接入 Prometheus 的核心要素是需要将 OpenTelemetry 指标转化为 Prometheus 指标格式,所以无论是 OpenTelemetry Collector 形式,还是直接在客户端采用 Prometheus exporter bridge 形式,本质上就是进行数据格式转化。

1)OpenTelemetry 官网

下图为 OpenTelemetry 官网文档建议的 OpenTelemetry 指标到 Prometheus 指标的转化路径。

详细参考文档:otlp-metric-points-to-prometheus [ 8]

图片

2)OpenTelemetry Collector的实现

而 OpenTelemetry Collector 具体实现与官网的建议实现略有不同,详细实现参考 prometheus-client-bridge [ 9] 。具体的转化关系如下图所示,与 OpenTelemetry 官方文档的核心差异在于如下几点。

  • OpenTelemetry 官方文档建议将 monotonic & delta Sum 转化为 Prometheus cumulative 的 Counter;而 OpenTelemetry Collector 的 Prometheus bridge 中将该中类型直接转化为 Prometheus 的 gauge。
  • OpenTelemetry 官方文档建议 Histogram delta 转化为 cumulative,从而转化为 Prometheus Histogram;虽然 OpenTelemetry Collector 代码中没有区分 Histogram 的 cumulative 及 delta,实际仅支持 cumulative 型 Histogram 转化为 Prometheus Histogram。
  • OpenTelemetry 官方文档建议 Exponential Histogram cumulative 转化为 Prometheus 的 Histograms,而在 OpenTelemetry Collector 中 Exponential Histogram cumulative & Exponential Histogram delta 都做丢弃处理。

图片

3.2 传统接入方式

以 Java 应用为例,当前 Java 应用(其他多语言应用类似) 将 OpenTelemetry 指标接入到 Prometheus 有如下几种常见的方式,当然还有其他解决方案如使用 micrometer,这里就不赘述。

方式 1: 应用暴露 OpenTelemetry 指标,通过 gRpc/HTTP 上报到 OpenTelemetry Collector,OpenTelemetry Collector 中以 Prometheus exporter 形式暴露 Prometheus 指标,Prometheus 可通过静态 Job 形式进行采集(或者其他服务发现的形式)。

详细的代码参考 Demo:https://github.com/OuyangKevin/opentelemetry-metric-java-demo/blob/main/metric-http/README.md

图片

方式 2: 应用暴露 OpenTelemetry 指标通过,gRpc/HTTP 上报到 OpenTelemetry Collector,OpenTelemetry Collector 中直接将指标转化为 Prometheus 指标格式,然后通过 remote write 形式写入远端 Prometheus。

详细的代码参考 Demo:https://github.com/OuyangKevin/opentelemetry-metric-java-demo/blob/main/metric-grpc/README.md

Ps:老版本 OpenTelemetry Collector 不支持 remote write 形式,如需验证请使用最新版本。

图片

方式3: Java 应用引入 OpenTelemetry-exporter-prometheus lib,将 OpenTelemetry 指标直接以 Prometheus Exporter 形式进行暴露,Prometheus 直接以拉的形式进行采集。

图片

如下为初始化的核心代码:

详细代码参考 Demo:https://github.com/OuyangKevin/opentelemetry-metric-java-demo/blob/main/metric-prometheus/README.md

PrometheusHttpServer prometheusHttpServer = PrometheusHttpServer.builder().setPort(1000).build();
Resource resource = Resource.getDefault().toBuilder().put(SERVICE_NAME, "opentelemetry-metric-demo-http").put(SERVICE_VERSION, "0.0.1").build();
SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
        .registerMetricReader(prometheusHttpServer)
        .setResource(resource)
        .build();

LongCounter longCounter = sdkMeterProvider
        .get("aliyun")
        .counterBuilder("ping_long_counter")
        .setDescription("ot http demo long_counter")
        .setUnit("ms")
        .build();

可观测监控 Prometheus 版零距离拥抱OpenTelemetry

目前,阿里云可观测监控 Prometheus 版已全面支持 OpenTelemetry 指标接入,用户仅需修改相关的上报地址以及鉴权配置即可无缝接入可观测监控 Prometheus 版,欢迎前往 Prometheus 控制台 [ 10] 进行体验。

详细的使用限制说明参考 OpenTelemetry 指标上报地址使用说明:https://help.aliyun.com/zh/prometheus/user-guide/instructions-for-using-the-reporting-address-of-opentelemetry-indicator/

图片

4.1 准备工作

在接入可观测监控 Prometheus 版之前,请您确保已经创建如下类型的 Prometheus 实例,具体操作请参考:

  • Prometheus 实例 for 容器服务 [ 11]
  • Prometheus 实例 for 通用 [ 12]
  • Prometheus 实例 for ECS [ 13]
  • Prometheus 实例 for 云服务 [ 14]

4.2 获取 OpenTelemetry 指标上报地址

  1. 登录 Prometheus 控制台。

  2. 在左侧导航栏单击监控列表,进入可观测监控 Prometheus 版的实例列表页面。

  3. 在页面顶部选择 Prometheus 实例所在的地域,并在目标 Prometheus 实例右侧的操作列单击设置。

  4. 在设置页签上,根据需求复制公网或内网的 OpenTelemetry 指标上报地址(当前仅支持 HTTP 形式,暂不支持使用 gRPC)。

图片

4.3 应用程序改造

如下以 Java 语言为例,在 SpringBoot 项目中进行 OpenTelemetry 指标的埋点。添加依赖


  <properties>
      <java.version>1.8</java.version>
      <org.springframework.boot.version>2.7.17</org.springframework.boot.version>
      <org.projectlombok.version>1.18.0</org.projectlombok.version>
      <opentelemetry.version>1.31.0</opentelemetry.version>
  </properties>

  <dependencies>
      <!-- springboot -->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
          <version>${org.springframework.boot.version}</version>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-actuator</artifactId>
          <version>${org.springframework.boot.version}</version>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-aop</artifactId>
          <version>${org.springframework.boot.version}</version>
      </dependency>


      <!-- opentelemetry -->
      <dependency>
          <groupId>io.opentelemetry</groupId>
          <artifactId>opentelemetry-api</artifactId>
          <version>${opentelemetry.version}</version>
      </dependency>
      <dependency>
          <groupId>io.opentelemetry</groupId>
          <artifactId>opentelemetry-sdk</artifactId>
          <version>${opentelemetry.version}</version>
      </dependency>

      <dependency>
          <groupId>io.opentelemetry</groupId>
          <artifactId>opentelemetry-exporter-otlp</artifactId>
          <version>${opentelemetry.version}</version>
      </dependency>
  </dependencies>

初始化 OpenTelemetry Bean

修改 OtlpHttpMetricExporterBuilder 中的  Endpoint 参数,将其替换为上文获取的 OpenTelemetry 指标上报地址,即可将应用的 OpenTelemetry 指标接入可观测监控 Prometheus 版。

详细请参考示例 Demo:https://github.com/OuyangKevin/opentelemetry-metric-java-demo/blob/main/metric-http/README.md

 @Bean
  public OpenTelemetry openTelemetry() {
    String endpoint = httpMetricConfig.getOetlExporterOtlpEndpoint();//自己修改
    Resource resource = Resource.getDefault().toBuilder()
                       .put("service.name", "opentelemetry-metric-demo-http")
                       .put("service.version", "0.0.1").build();

    SdkMeterProvider defaultSdkMeterProvider = SdkMeterProvider.builder()
            .registerMetricReader(PeriodicMetricReader.builder(
                    OtlpHttpMetricExporter.builder()
                            .setEndpoint(endpoint)
                            .build())
                    .setInterval(15, TimeUnit.SECONDS).build())
            .setResource(resource)
            .build();


    OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
            .setMeterProvider(defaultSdkMeterProvider)
            .buildAndRegisterGlobal();
    return openTelemetry;
  }

在初始化 OpenTelemetry bean 时,可以对上报的客户端进行详细地参数设置,具体配置说明如下:

1)OpenTelemetry 相关客户端默认没有开启压缩,建议设置 Compression 参数为 gzip,减少网络传输消耗。

OtlpHttpMetricExporter.builder()
 .setEndpoint("******")
 .setCompression("gzip")
 .build()

2)OpenTelemetry 指标上报可观测监控 Prometheus 版后,若需要针对所有的指标加上前缀,可以设置 Header “metricNamespace”,如下所示设置 metricNamespace 为 ot,所有的上报的指标将会加上"ot_"前缀。

OtlpHttpMetricExporter.builder()
  .setEndpoint("******")
  .setCompression("gzip")
  .addHeader("metricNamespace","ot")
   .build()

3)OpenTelemetry 指标上报到可观测监控 Prometheus 版后,所有的指标默认会带上 OpenTelemetry Scope Lables,如果不希望添加默认的 Scope Lables,可以设置 Header skipGlobalLabel=true,如下所示。

OtlpHttpMetricExporter.builder()
  .setEndpoint("******")
  .setCompression("gzip")
  .addHeader("skipGlobalLabel","true")
  .build()

定义业务指标,如下样例设置了一个 LongCounter 及 LongHistogram。

@RestController
public class MetricController {

    @Autowired
    private OpenTelemetry openTelemetry;

    @GetMapping("/ping")
    public String ping(){
         long startTime = System.currentTimeMillis();
         Meter meter = openTelemetry.getMeter("io_opentelemetry_metric_ping");

         LongCounter longCounter = meter.counterBuilder("ping_long_counter")
                 .setDescription("ot http demo long_counter")
                 .setUnit("ms")
                 .build();

         LongHistogram longHistogram= meter.histogramBuilder("ping_long_histogram")
             .ofLongs()
             .setDescription("ot http demo histogram")
             .setUnit("ms")
             .build();

         try{
             longCounter.add(1,Attributes.of(AttributeKey.stringKey("regionId"),"cn-hangzhou"));
             TimeUnit.MILLISECONDS.sleep(new Random().nextInt(10));
         }catch (Throwable e){

         }finally {
             longHistogram.record(System.currentTimeMillis() - startTime);
         }
         return "ping success!";
    }
}

关于 OpenTelemetry 指标模型与阿里云可观测监控 Prometheus 版指标模型转化的映射关系如下。由于 Prometheus 对于 delta Histogram 支持需要转化为 cumulative Histogram,所以可观测监控 Prometheus 版暂时不支持 OpenTelemetry delta Histogram 转化,建议在该场景下使用 OpenTelemetry cumulative Histogram。

图片

4.4 Grafana 中查看监控数据

  1. 登录可观测可视化 Grafana 版控制台 [ 15]
  2. 在工作区管理页面单击 Grafana 共享版,然后选择对应的公网地址单击登录
  3. 在左侧导航栏单击图标,然后 Explore 右侧选择对应的 Datasource。
  4. 配置自己的大盘与告警,如下为客户利用 OpenTelemetry 指标配置的大盘。

图片

阿里云可观测监控 Prometheus 版 VS 开源 Prometheus

阿里云可观测监控 Prometheus 版全面对接开源 Prometheus 生态,支持类型丰富的组件监控,覆盖绝大部分开源基础设施软件指标采集能力。提供多种开箱即用的预置监控大盘,并集成丰富的 Kubernetes 基础监控以及常用服务预设看板,且提供全面托管的 Prometheus 服务。阿里云可观测监控 Prometheus 版的优势可以归纳为 “开箱即用”、“低成本”、“开源兼容”、“数据规模无上限”、“高性能”、“高可用性”

图片

参考文档:

https://www.timescale.com/blog/prometheus-vs-opentelemetry-metrics-a-complete-guide/

https://opentelemetry.io/docs/specs/otel/metrics/data-model/

https://opentelemetry.io/docs/specs/otel/compatibility/prometheus_and_openmetrics/

https://github.com/open-telemetry/opentelemetry-collector-contrib

相关链接:

[1] Instruments

https://opentelemetry.io/docs/specs/otel/metrics/api/#instrument

[2] Sums

https://github.com/open-telemetry/opentelemetry-proto/blob/v0.9.0/opentelemetry/proto/metrics/v1/metrics.proto#L230

[3] monotonic

https://en.wikipedia.org/wiki/Monotonic_function

[4] examplars

https://opentelemetry.io/docs/specs/otel/metrics/data-model/#exemplars

[5] Gauge

https://github.com/open-telemetry/opentelemetry-proto/blob/v0.9.0/opentelemetry/proto/metrics/v1/metrics.proto#L200

[6] Histogram

https://github.com/open-telemetry/opentelemetry-proto/blob/v0.9.0/opentelemetry/proto/metrics/v1/metrics.proto#L258

[7] 介绍

https://prometheus.io/docs/concepts/metric_types/

[8] otlp-metric-points-to-prometheus

https://opentelemetry.io/docs/specs/otel/compatibility/prometheus_and_openmetrics/#otlp-metric-points-to-prometheus

[9] prometheus-client-bridge

https://github.com/open-telemetry/opentelemetry-java-contrib/blob/main/prometheus-client-bridge/src/main/java/io/opentelemetry/contrib/metrics/prometheus/clientbridge/MetricAdapter.java

[10] Prometheus 控制台

https://account.aliyun.com/login/login.htm?oauth_callback=https%3A%2F%2Fprometheus.console.aliyun.com%2F#/home

[11] Prometheus 实例 for 容器服务

https://help.aliyun.com/zh/prometheus/user-guide/create-a-prometheus-instance-to-monitor-an-ack-cluster

[12] Prometheus 实例 for 通用

https://help.aliyun.com/zh/prometheus/user-guide/create-a-prometheus-instance-for-remote-storage

[13] Prometheus 实例 for ECS

https://help.aliyun.com/zh/prometheus/user-guide/create-a-prometheus-instance-to-monitor-an-ecs-instance

[14] Prometheus 实例 for 云服务

https://help.aliyun.com/zh/prometheus/user-guide/create-a-prometheus-instance-to-monitor-alibaba-cloud-services

[15] 可观测可视化 Grafana 版控制台

https://account.aliyun.com/login/login.htm?oauth_callback=/#/grafana/workspace/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/339118.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第十五届蓝桥杯单片机组——DS1302

文章目录 一、DS1302介绍二、使用DS1302需要注意的点2.1 写保护2.2 写入的时间需要以BCD码形式2.3 12小时模式 or 24小时模式 三、代码编写3.1 初始化时间3.2 读取RTC时间 一、DS1302介绍 1.时钟数据&#xff1a;DS1302可以提供秒、分钟、小时、天、日期、月份和年份数据&#…

即插即用篇 | 超越自注意力:面向医学图像分割的可变形大卷积核注意力

医学图像分割在转换器模型的应用下取得了显著的进展,这些模型擅长捕捉广泛的上下文和全局背景信息。然而,这些模型随着标记数量的平方成比例增长的计算需求限制了它们的深度和分辨率能力。大多数当前的方法通过逐层处理D体积图像数据(称为伪3D),在处理过程中错过了关键的跨…

MySQL与PostgreSQL对比

对比 许可证 License MySQL 社区版采用 GPL 许可证。Postgres 发布在 PostgreSQL 许可下&#xff0c;是一种类似于 BSD 或 MIT 的自由开源许可。 即便 MySQL 采用了 GPL&#xff0c;仍有人担心 MySQL 归 Oracle 所有&#xff0c;这也是为什么 MariaDB 从 MySQL 分叉出来。 …

推开放平台战略,Qt Group加速生态化转型

本文作者&#xff1a;李佳师&#xff08;科技媒体人、前《中国电子报》主编&#xff09; 在软件定义时代&#xff0c;不断降低软件开发、测试和生产成本&#xff0c;提升开发效率、缩短开发周期&#xff0c;是一个永远在路上没有完结的课题。目前&#xff0c;由生成式人工智能引…

SpringCloud Alibaba 深入源码 - Nacos 和 Eureka 的区别(健康检测、服务的拉取和订阅)

目录 一、Nacos 和 Eureka 的区别 1.1、以 Nacos 注册流程来解析区别 一、Nacos 和 Eureka 的区别 1.1、以 Nacos 注册流程来解析区别 a&#xff09;首先&#xff0c;我们的服务启动时。都会把自己的信息提交给注册中心&#xff0c;然后注册中心就会把信息保存下来. 注册的…

opencv009 滤波器01(卷积)

图像卷积操作&#xff08;convolution&#xff09;&#xff0c;或称为核操作&#xff08;kernel&#xff09;&#xff0c;是进行图像处理的一种常用手段&#xff0c; 图像卷积操作的目的是利用像素点和其邻域像素之前的空间关系&#xff0c;通过加权求和的操作&#xff0c;实现…

【UEFI基础】EDK网络框架(DNS4)

DNS4 DNS4协议说明 IP地址是一串数据&#xff0c;不便记忆。一般用户在使用TCP/IP协议进行通信时也不使用IP地址&#xff0c;而是使用英文和点号组成的字符串&#xff0c;两者的转换通过DNS&#xff08;Domain Name System&#xff09;来完成。 DNS也有v4和v6版本&#xff0…

kubeadm 安装k8s集群后,master节点notready问题解决方案

使用kubeadm 安装k8s集群后&#xff0c;加载calico cni 网络组件后&#xff0c;master节点notready问题 表现为&#xff1a; 使用命令查看日志&#xff1a;journalctl -f -u kubelet 报错如下&#xff1a; Failed to start ContainerManager failed to initialize top level…

vue3中Fragment特性的一个bug,需要留意的注意事项

vue3中的Fragment 模版碎片特性是什么&#xff0c;简单的理解就是template模板代码不在像vue2中那样必须在根节点在包裹一层节点了。 vue2写法 <template><div><h1>标题</h1><p>正文内容</p></div> </template>vue3写法 &l…

【RT-DETR有效改进】Google | EfficientNetV2一种超轻量又高效的网络 (轻量化网络)

前言 大家好&#xff0c;我是Snu77&#xff0c;这里是RT-DETR有效涨点专栏。 本专栏的内容为根据ultralytics版本的RT-DETR进行改进&#xff0c;内容持续更新&#xff0c;每周更新文章数量3-10篇。 专栏以ResNet18、ResNet50为基础修改版本&#xff0c;同时修改内容也支持Re…

SpikingJelly笔记之IFLIF神经元

文章目录 前言一、脉冲神经元二、IF神经元1、神经元模型2、神经元仿真 三、LIF神经元1、神经元模型2、神经元仿真 总结 前言 记录整合发放(integrate-and-fire, IF)神经元与漏电整合发放(leaky integrate-and-fire, LIF)神经元模型&#xff0c;以及在SpikingJelly中的实现方法…

中期国际1.18黄金市场分析:零售销售强劲增长,美联储降息可能性大幅降低!

金价在周四下跌&#xff0c;其中一个主要原因是美国国债收益率的持续上升。此外&#xff0c;强劲的美国零售销售报告也对金价造成了影响&#xff0c;该报告显示零售销售额大幅上涨&#xff0c;超出预期值&#xff0c;这使得美联储3月份降息的可能性大幅降低。 12月份的消费者价…

Spring Boot 集成 API 文档 - Swagger、Knife4J、Smart-Doc

文章目录 1.OpenAPI 规范2.Swagger: 接口管理的利器3.Swagger 与 SpringFox&#xff1a;理念与实现4.Swagger 与 Knife4J&#xff1a;增强与创新5.案例&#xff1a;Spring Boot 整合 Swagger35.1 引入 Swagger3 依赖包5.2 优化路径匹配策略兼容 SpringFox5.3 配置 Swagger5.4 S…

国产操作系统:VirtualBox安装openKylin-1.0.1虚拟机并配置网络

国产操作系统&#xff1a;VirtualBox安装openKylin-1.0.1虚拟机并配置网络 openKylin 操作系统目前适配支持X86、ARM、RISC-V三个架构的个人电脑、平板电脑及教育开发板&#xff0c;可以满足绝大多数个人用户及开发者的使用需求。适用于在VirtualBox平台上安装openKylin-1.0.1…

不同开发语言在进程、线程和协程的设计差异

不同开发语言在进程、线程和协程的设计差异 1. 进程、线程和协程上的差异1.1 进程、线程、协程的定义1.2 进程、线程、协程的差异1.3 进程、线程、协程的内存成本1.4 进程、线程、协程的切换成本 2. 线程、协程之间的通信和协作方式2.1 python如何实现线程通信&#xff1f;2.2 …

智能小程序多语言适配指南

i18n 配置 启用多语言配置&#xff0c;需开启项目配置&#xff08;project.tuya.json&#xff09;中的 {"i18n": true} 选项。多语言的配置内容存放在小程序开发者平台 多语言管理。 本章节的多语言仅适用于智能小程序。如果您开发的是面板小程序&#xff0c;请查阅…

华南理工大学数字信号处理实验实验二源码(薛y老师)

一、实验目的 ▪ 综合运用数字信号处理的理论知识进行信号分析并利用MATLAB作为编程工具进行计算机实现&#xff0c;从而加 深对所学知识的理解&#xff0c;建立概念。 ▪ 掌握数字信号处理的基本概念、基本理论和基本方法。 ▪ 学会用MATLAB对信号进行分析和处理。 ▪ 用F…

QCustomPlot开源库使用

1.简介 QCustomPlot是用于绘图和数据可视化的Qt C 小部件。它没有进一步的依赖关系&#xff0c;并且有据可查。该绘图库专注于制作美观&#xff0c;出版质量的2D绘图&#xff0c;图形和图表&#xff0c;以及为实时可视化应用程序提供高性能。看一下“ 设置”和“ 基本绘图”教…

【系统调用IO】open、close、read、write、lseek

目录 3 系统调用IO3.1 文件描述符3.1.1 FILE结构体3.2.2 文件描述符 3.3 open、close、read、write、lseek3.3.1 文件权限3.3.2 open3.3.3 close3.3.4 read3.3.5 write3.3.6 lseek3.3.7 代码示例 文件io和标准io的区别 橙色 3 系统调用IO 3.1 文件描述符 3.1.1 FILE结构体 …

链表|数据结构|C语言深入学习

什么是链表 离散&#xff0c;就是“分离的、散开的” 链表是什么样子的&#xff1a; 有限个节点离散分配 彼此间通过指针相连 除了首尾节点&#xff0c;每个节点都只有一个前驱节点和一个后继节点 首节点没有前驱结点&#xff0c;尾节点没有后继节点 基本概念术语&#xf…