跳到主要内容

仪表

DeepSeek V3 中英对照 Gauges

仪表(gauge)是一个用于获取当前值的句柄。典型的仪表示例包括集合或映射的大小,或者处于运行状态的线程数量。

提示

仪表(Gauge)适用于监控具有自然上限的事物。我们不建议使用仪表来监控诸如请求计数之类的事物,因为这些值在应用程序实例的生命周期内可能会无限增长。

提示

永远不要用 Counter 来测量你可以计数的东西!

Micrometer 认为仪表(gauges)应该是被采样的,而不是被设置的,因此在采样之间可能发生的信息是无法获取的。在仪表值被报告到指标后端时,任何在仪表上设置的中间值都会丢失,因此一开始设置这些中间值的意义不大。

Gauge 视为一个“海森堡仪表”:一个仅在观察时才会变化的仪表。其他所有类型的仪表都会在数据发送到指标后端之前累积中间计数。

MeterRegistry 接口包含用于构建仪表(gauge)以观察数值、函数、集合和映射的方法:

List<String> list = registry.gauge("listGauge", Collections.emptyList(), new ArrayList<>(), List::size); 1
List<String> list2 = registry.gaugeCollectionSize("listSize2", Tags.empty(), new ArrayList<>()); 2
Map<String, Integer> map = registry.gaugeMapSize("mapGauge", Tags.empty(), new HashMap<>());
java
  • 一种稍微更常见的仪表形式是监控某些非数字对象的仪表。最后一个参数设置了在观察仪表时用于确定仪表值的函数。

  • 当您想要监控集合大小时,(1) 的一种更方便的形式。

所有创建 gauge 的不同形式都只保留对被观察对象的弱引用,以防止阻止对象的垃圾回收。

手动增加或减少 Gauge

一个仪表(gauge)可以设置为跟踪任何可设置的 java.lang.Number 子类型,例如在 java.util.concurrent.atomic 中找到的 AtomicIntegerAtomicLong,以及类似的类型,例如 Guava 的 AtomicDouble

// maintain a reference to myGauge
AtomicInteger myGauge = registry.gauge("numberGauge", new AtomicInteger(0));

// ... elsewhere you can update the value it holds using the object reference
myGauge.set(27);
myGauge.set(11);
java

请注意,在这种形式下,与其他仪表类型不同,你在创建一个 Gauge 时不会获得对它的引用。相反,你会获得对被观察对象的引用。这是由于“海森堡仪表”原则:一旦创建,仪表是自给自足的,因此你永远不需要与它进行交互。这使得我们只能返回给你被测量的对象,从而允许快速的一行代码,既能创建被观察的对象,又能围绕它设置指标。

这种模式应该比 DoubleFunction 形式更少见。请记住,频繁设置观察到的 Number 会导致大量中间值从未被发布。只有发布时仪表的瞬时值才会被发送到监控系统。

注意

尝试使用原始数字或其 java.lang 对象形式来构造一个 Gauge 始终是不正确的。这些数字是不可变的。因此,Gauge 无法被更改。尝试使用不同的数字“重新注册” Gauge 是无效的,因为注册表仅为每个唯一的名称和标签组合维护一个 Meter。“重新注册” Gauge 可能会间接发生,例如由于 MeterFilter 修改了两个不同 Gauge 的名称和/或标签,导致在应用过滤器后它们变得相同。

Gauge Fluent Builder

接口包含一个用于仪表的流畅构建器:

Gauge gauge = Gauge
.builder("gauge", myObj, myObj::gaugeValue)
.description("a description of what this gauge does") // optional
.tags("region", "test") // optional
.register(registry);
java

通常返回的 Gauge 实例除了在测试中之外并不太有用,因为该仪表已经在注册时自动设置为跟踪一个值。

为什么我的仪表盘报告 NaN 或消失了?

你有责任持有对使用 Gauge 进行测量的状态对象的强引用。Micrometer 会小心避免对可能被垃圾回收的对象创建强引用。一旦被测量的对象被解除引用并被垃圾回收,Micrometer 将根据注册表实现开始报告 NaN 或不再报告任何值。

如果你看到你的仪表报告了几分钟,然后消失或报告 NaN,这几乎可以肯定地表明被测量的底层对象已经被垃圾回收了。

TimeGauge

TimeGauge 是一种专门用于跟踪时间值的仪表,它将时间值缩放到每个注册表实现所期望的基本时间单位。

TimeGauge 可以按如下方式与 TimeUnit 一起注册:

AtomicInteger msTimeGauge = new AtomicInteger(4000);
AtomicInteger usTimeGauge = new AtomicInteger(4000);
TimeGauge.builder("my.gauge", msTimeGauge, TimeUnit.MILLISECONDS, AtomicInteger::get).register(registry);
TimeGauge.builder("my.other.gauge", usTimeGauge, TimeUnit.MICROSECONDS, AtomicInteger::get).register(registry);
java

例如,如果注册表是 Prometheus,它们将按如下方式转换为秒:

# HELP my_gauge_seconds
# TYPE my_gauge_seconds gauge
my_gauge_seconds 4.0
# HELP my_other_gauge_seconds
# TYPE my_other_gauge_seconds gauge
my_other_gauge_seconds 0.004
none

多仪表盘

Micrometer 支持一种特殊的 Gauge 类型,称为 MultiGauge,用于帮助管理一个不断增长或缩小的条件列表。此功能允许您从类似 SQL 查询的内容中选择一组有界但略微变化的条件集,并将每个 Row(参见下面的示例)报告为一个 Gauge。以下示例创建了一个 MultiGauge

// SELECT count(*) from job group by status WHERE job = 'dirty'
MultiGauge statuses = MultiGauge.builder("statuses")
.tag("job", "dirty")
.description("The number of widgets in various statuses")
.baseUnit("widgets")
.register(registry);

...

// run this whenever you re-run your query
statuses.register(
resultSet.stream()
.map(result -> Row.of(Tags.of("status", result.getAsString("status")), result.getAsInt("count")))
.collect(toList()),
true // whether to overwrite the previous value or only record it once
);
java