Как получить согласованные значения с неотрицательной производной influxdb?

используя grafana с influxdb, я пытаюсь показать скорость в секунду некоторого значения, которое является счетчиком. Если я использую non_negative_derivative(1s) функция, значение скорости, кажется, резко меняется в зависимости от временной ширины представления grafana. Я использую last селектор (но также может использовать max который является тем же значением, поскольку он является счетчиком).

в частности, я использую:

SELECT non_negative_derivative(last("my_counter"), 1s) FROM ...

по словам документы influxdb неотрицательная производная:

InfluxDB вычисляет разницу между значениями хронологического поля и преобразует эти результаты в скорость изменения на единицу.

поэтому для меня это означает, что значение в данной точке не должно сильно меняться при расширении представления времени, так как значение должно быть скорость изменения на единицу (1s в моем примере запроса выше).

в графите, они имеют специфическое perSecond функция, которая работает намного лучше:

perSecond(consolidateBy(my_counter, 'max'))

любые идеи о том, что я делаю неправильно С выше запроса приток?

2 ответов


если вы хотите в секунду результаты, которые не меняются, вы хотите, чтобы GROUP BY time(1s). Это даст вам точную perSecond результаты.

рассмотрим следующий пример:

предположим, что значение счетчика в каждую секунду изменяется так

0s → 1s → 2s → 3s → 4s
1  → 2  → 5  → 8  → 11

в зависимости от того, как мы группируем последовательность выше, мы увидим разные результаты.

рассмотрим случай, когда мы группой в 2s ведра.

 0s-2s   →    2s-4s
(5-1)/2  →  (11-5)/2
   2     →      3

против 1s ведра

 0s-1s  →  1s-2s  →  2s-3s  →  3s-4s
(2-1)/1 → (5-2)/1 → (8-5)/1 → (11-8)/1
   1    →    3    →    3    →    3

решение проблемы

поэтому для меня это означает, что значение в данной точке не должно сильно изменяться при расширении представления времени, так как значение должно быть скоростью изменения на единицу (1s в моем примере запроса выше).

на rate of change per unit является нормализующим фактором, независимым от GROUP BY единица измерения времени. Интерпретация нашего предыдущего примера, когда мы меняем интервал производной на 2s может предложить некоторое понимание.

точное уравнение

∆y/(∆x/tu)

рассмотрим случай, когда мы группой в 1s ведра с производным интервал 2s. Результат, который мы должны увидеть, это

 0s-1s    →  1s-2s    →  2s-3s    →  3s-4s
2*(2-1)/1 → 2*(5-2)/1 → 2*(8-5)/1 → (11-8)/1
   2      →    6      →    6      →    6

это может показаться немного странным, но если учесть, что это говорит, это должно иметь смысл. Когда мы указываем производный интервал 2s то, что мы просим, это то, что и

 0s-2s     →    2s-4s
2*(5-1)/2  →  2*(11-5)/2
   4       →      6

то, что мы просим здесь, это то, что


@Michael-Desa дает отличное объяснение.

я хотел бы дополнить этот ответ решением довольно распространенной метрики, в которой заинтересована наша компания: "Что такое максимум значение "операция в секунду" на конкретном поле измерения?".

я буду использовать реальный пример из нашей компании.

Сценарий Фон

мы отправляем много данных из СУБД в Рэдис. При передаче этого данные, мы отслеживаем 5 счетчиков:

  1. TipTrgUp -> обновления бизнес-триггером (хранимая процедура)
  2. TipTrgRm -> удаляет бизнес-триггер (хранимая процедура)
  3. TipRprUp -> обновления автоматической авторемонтных пакетной обработки
  4. TipRprRm -> удаляет пакетным процессом автоматического ремонта
  5. TipDmpUp -> обновления с помощью процесса массового сброса

мы сделали сборщик метрик, который отправляет текущее состояние этих счетчиков для InfluxDB с интервалом в 1 секунду (настраивается).

график Grafana 1: низкое разрешение, не правда максимум ОПС

вот запрос grafana, который полезен, но не показывает истинный max ops при уменьшении масштаба (мы знаем, что он будет идти около 500 ops в обычный рабочий день, когда никаких специальных дампов или обслуживания не происходит-в противном случае он идет в тысячи):

SELECT
    non_negative_derivative(max(TipTrgUp),1s) AS "update/TipTrgUp"
   ,non_negative_derivative(max(TipTrgRm),1s) AS "remove/TipTrgRm"
   ,non_negative_derivative(max(TipRprUp),1s) AS "autorepair-up/TipRprUp"
   ,non_negative_derivative(max(TipRprRm),1s) AS "autorepair-rm/TipRprRm"
   ,non_negative_derivative(max(TipDmpUp),1s) AS "dump/TipDmpUp"
FROM "$rp"."redis_flux_-transid-d-s"
WHERE
    host =~ /$server$/
    AND $timeFilter
GROUP BY time($interval),* fill(null)

заметками на полях истории болезни: $rp - это имя политики хранения, шаблонное в grafana. Мы используем CQ для downsample для политик хранения с большей продолжительностью. Также обратите внимание на 1s как производный параметр: это необходимо, так как значение по умолчанию отличается при использовании GROUP BY. Это можно легко упустить из виду в документации InfluxDB.

график, увиденный 24 часами выглядит так: enter image description here

если мы просто используем разрешение 1s (как предложено @Michael-Desa), an огромное количество данных передается от influxdb клиенту. Это работает достаточно хорошо (около 10 секунд), но слишком медленно для нас.

график Графана 2: низкое и высокое разрешение, true max ops, медленная производительность

однако мы можем использовать подзапросы чтобы добавить true maxops к этому графику, что является небольшим улучшением. Гораздо меньше данных передается клиенту, но сервер InfluxDB должен делать много хруста числа. Серия B (с maxops добавлено в псевдонимы):

SELECT
    max(subTipTrgUp) AS maxopsTipTrgUp
   ,max(subTipTrgRm) AS maxopsTipTrgRm
   ,max(subTipRprUp) AS maxopsRprUp
   ,max(subTipRprRm) AS maxopsTipRprRm
   ,max(subTipDmpUp) AS maxopsTipDmpUp
FROM (
    SELECT
        non_negative_derivative(max(TipTrgUp),1s) AS subTipTrgUp
       ,non_negative_derivative(max(TipTrgRm),1s) AS subTipTrgRm
       ,non_negative_derivative(max(TipRprUp),1s) AS subTipRprUp
       ,non_negative_derivative(max(TipRprRm),1s) AS subTipRprRm
       ,non_negative_derivative(max(TipDmpUp),1s) AS subTipDmpUp
    FROM "$rp"."redis_flux_-transid-d-s"
    WHERE
        host =~ /$server$/
        AND $timeFilter
    GROUP BY time(1s),* fill(null)
)
WHERE $timeFilter
GROUP BY time($interval),* fill(null)

дает: enter image description here

график Графана 3: низкое и высокое разрешение, истинный Макс ОПС, высокая эффективность, пре-высчитывает КК

наше окончательное решение для такого рода метрик (но только тогда, когда нам нужен живой вид, подход подзапроса отлично работает для графиков ad-hoc): используйте непрерывный запрос для предварительного вычисления истинных maxops. Мы генерируем CQ следующим образом:

CREATE CONTINUOUS QUERY "redis_flux_-transid-d-s.maxops.1s"
ON telegraf
BEGIN
    SELECT
        non_negative_derivative(max(TipTrgUp),1s) AS TipTrgUp
       ,non_negative_derivative(max(TipTrgRm),1s) AS TipTrgRm
       ,non_negative_derivative(max(TipRprUp),1s) AS TipRprUp
       ,non_negative_derivative(max(TipRprRm),1s) AS TipRprRm
       ,non_negative_derivative(max(TipDmpUp),1s) AS TipDmpUp
    INTO telegraf.A."redis_flux_-transid-d-s.maxops"
    FROM telegraf.A."redis_flux_-transid-d-s"
    GROUP BY time(1s),*
END

отсюда, это тривиально использовать эти измерения maxops в grafana. Когда downsampling к RP с более длинным удерживанием, мы снова используем max() как функция селектора.

Серия B (с .maxops добавлено в псевдонимы)

SELECT
    max(TipTrgUp) AS "update/TipTrgUp.maxops"
   ,max(TipTrgRm) AS "remove/TipTrgRm.maxops"
   ,max(TipRprUp) as "autorepair-up/TipRprUp.maxops"
   ,max(TipRprRm) as "autorepair-rm/TipRprRm.maxops"
   ,max(TipDmpUp) as "dump/TipDmpUp.maxops"
FROM "$rp"."redis_flux_-transid-d-s.maxops"
WHERE
    host =~ /$server$/
    AND $timeFilter
GROUP BY time($interval),* fill(null)

дает: enter image description here

при увеличении до точности 1s вы можете видеть, что графики становятся идентичными: enter image description here

надеюсь, это поможет, TW