Несоответствие счетчика Prometheus

#java #prometheus #prometheus-java

#java #prometheus #prometheus-java

Вопрос:

Я использую Prometheus Java simpleclient в веб-службе, чтобы отслеживать, сколько событий приводят к тому или иному статусу.

Я могу проверить в журналах, что счетчик вызывается и увеличивается внутренне, но кажется, что часто данные не доходят до конечной точки / metrics.

Например, только что, после увеличения счетчика в 3 раза для одного и того же состояния с интервалом в несколько минут каждый, журнал трижды напечатает «Текущее значение = 0, новое значение = 1». Первые два раза не отображалось никаких данных в конечной точке /metrics, и после 3-го увеличения оно, наконец, показало значение 1, что означает, что я потерял запись о первых 2 событиях.

Код, который у меня есть, следующий ниже, помимо некоторых изменений имени.

 private static final Counter myCounter = Counter.build()
        .name("myMetric")
        .help("My metric")
        .labelNames("status").register();
...

private static void incrementCounter(String status) {
    Counter.Child counter = myCounter.labels(status);
    Logger.info("Before Incrementing counter for status= "   status   ". Current value="   counter.get());
    counter.inc();
    Logger.info("After Incrementing counter for status= "   status   ". New value="   counter.get());
}
  

Я в недоумении относительно того, почему Prometheus, похоже, не может последовательно отслеживать эти счетчики. Кто-нибудь может увидеть, что не так, или лучший способ записать эти показатели счетчика?

Комментарии:

1. Вы создаете дочерние счетчики Counter.Child counter = myCounter.labels(status); , поэтому у вас в основном есть отдельный счетчик для каждого статуса.

2. Я это понимаю. Все это было для одного и того же статуса.

3. Есть ли что-нибудь, вызывающее remove или clear в myCounter?

4. Ничего из того, что мы написали явно, нет. Единственные методы, которые мы использовали, это . labels(), а затем .inc(), .get() для дочернего объекта счетчика. Не уверен, есть ли что-нибудь в библиотеке Prometheus, что могло бы это делать.

Ответ №1:

Единственная причина, о которой я могу догадаться, — это одновременные incrementCounter вызовы. io.prometheus.client.SimpleCollector#labels Метод не является потокобезопасным (несмотря на то, что у children поля есть ConcurrentMap тип), поэтому при каждом вызове можно получать разные данные io.prometheus.client.Counter.Child .

Что касается получения показателей через http — каждый вызов /metrics конечной точки приводит к io.prometheus.client.Counter#collect вызову метода, который извлекает значение только одного дочернего элемента.

Я бы посоветовал вам использовать вашу собственную параллельную карту для хранения счетчиков:

 private static final ConcurrentMap<String, Counter.Child> counters = new ConcurrentHashMap<>();   

// ...

private static void incrementCounter(String status) {
  Counter.Child counter = counters.computeIfAbsent(status, myCounter::labels) ;
  // ...
}