1

我正在使用io.prometheus.client.Gauge实现一个线程安全计数器来计算一个时间范围内处理的事件数。现在有几个线程正在处理这些事件。并且所有人都可以在完成处理后更新计数器。我的问题是Gauge计数器本质上是线程安全的吗?以下是我的实现。

    private Map<String, Gauge> gaugeMap = new ConcurrentHashMap<>();
    
    // This method will be called to register the Gauge
    private void registerCounter(String metricName) {
        Gauge gauge = Gauge.build()
                .name(metricName)
                .help(metricName)
                .register(meterRegistry.getPrometheusRegistry());
        gaugeMap.put(metricName, gauge);
    }
    
    public void incrementCounter(String metricName) {
        if (isCounterPresent(metricName)) {
            gaugeMap.get(metricName).inc();
        }
    }
   public void incrementCounter(String metricName, long value) {
        if (isCounterPresent(metricName)) {
            gaugeMap.get(metricName).inc(value);
        }
    }

以下是我的客户端代码。

// on application startup I am calling registerCounter for all metrics
@PostConstruct
private void registerMetrics(List<String> metricList) {
    // for each of metricList --> call registerCounter(String metricName)
}


Thread1
-------------------
// process N events
// call incrementCounter("metric-1", N);

Thread2
-------------------
// process N events
// call incrementCounter("metric-1", N);

Thread3
-------------------
// process N events
// call incrementCounter("metric-1", N);

现在我的问题是多个线程正在递增同一个计数器,那么它会给我正确的值吗?

4

2 回答 2

2

该仪表是线程安全的,并使用 CAS 操作来支持非阻塞状态更新。所有的度量收集器都是。最后,它们必须由端点在单独的线程中公开。因此,读取和写入的状态应该是一致的。要记住的一件事是,争用越高,CAS 操作的效率就越低。因此,请确保不要将它暴露给试图同时更新它的数十个线程。

其次,使用仪表作为计数器不是一个好主意,因为有一种特殊的类型 - 计数器。一些 Prometheus 函数经过专门实现和优化以用于计数器 - rate、irate 等。因此,如果您需要收集和公开多个线程处理的事件数量,建议使用 Counter。

于 2020-09-30T08:02:31.447 回答
1

Prometheus JVM Client README指出:

默认inc(), Gauge 上dec()set()方法负责线程安全

于 2020-09-27T21:28:42.143 回答