company_banner

Grafana, InfluxDB, два тега и одна сумма. Или как посчитать сумму подгрупп?

  • Tutorial

Всем привет!

Занимаюсь тестированием производительности. И очень люблю настраивать мониторинг и любоваться метриками в Grafana. А стандартом для хранения метрик в инструментах для подачи нагрузки является InfluxDB. В InfluxDB можно сохранять метрики из таких популярных инструментов, как:


Работая с инструментами по тестированию производительности и их метриками, накопил подборку рецептов программирования для связки Grafana и InfluxDB. Предлагаю рассмотреть интересную задачу, которая возникает там, где есть метрика с двумя и более тегами. Думаю, это не редкость. И в общем случае задача звучит так: подсчёт суммарной метрики по группе, которая делится на подгруппы.

Есть три варианта:


  1. Просто сумма с группировкой по тегу Type
  2. Grafana-way. Используем стек значений
  3. Сумма максимумов с подзапросом

Как всё начиналось


Настраивал мониторинг JVM MBean с помощью Jolokia, Telegraf, InfluxDB и Grafana. И визуализировал метрики по пулам памяти — сколько памяти выделено каждым пулом памяти в HEAP и за её пределами.

Графики по пулам памяти JVM и активности сборщика мусора с 13:00 предыдущего дня по 01:00 ночи текущего дня (период в 12 часов). Тут видно, что пулы памяти делятся на две группы: HEAP и NON_HEAP. И что примерно в 17:00 была сборка мусора, после чего размер пулов памяти уменьшился:



Для сбора метрик по пулам памяти указал в конфигурационном файле telegraf следующие настройки:

telegraf.conf
[outputs.influxdb]
  urls = ["http://influxdb_server:8086"]
  database = "telegraf"
  username = "login-InfluxDb"
  password = "*****"
  retention_policy = "month"
  influx_uint_support = false

[agent]
  collection_jitter = "2s"
  interval = "2s"
  precision = "s"

[[inputs.jolokia2_agent]]
  username = "login-Jolokia"
  password = "*****"
  urls = ["http://127.0.0.1:7777/jvm-service"]

[[inputs.jolokia2_agent.metric]]
  paths = ["Usage","PeakUsage","CollectionUsage","Type"]
  name = "java_memory_pool"
  mbean = "java.lang:name=*,type=MemoryPool"
  tag_keys = ["name"]

[[processors.converter]]
  [processors.converter.fields]
    integer = ["CollectionUsage.*", "PeakUsage.*", "Usage.*"]
    tag = ["Type"]

А в Grafana сконструировал запрос к InfluxDB, чтобы вывести в виде графиков максимальное значение метрики Usage.Committed за период времени с шагом $granularity (1m) и группировкой по двум тегам Type (HEAP или NON_HEAP) и name (Metaspace, G1 Old Gen, ...):



Этот же запрос в текстовом виде, с учетом всех переменных Grafana (обратите внимание на экранирование значений переменных с помощью :regex — это важно для корректной работы запроса):

SELECT max("Usage.committed")
FROM "telegraf"."month"."java_memory_pool"
WHERE
    host =~ /^${host:regex}$/ AND
    jolokia_agent_url =~ /^${jolokia:regex}$/ AND
    $timeFilter
GROUP BY
    "Type", "name", time($granularity)

Этот же запрос в текстовом виде, с учетом конкретных значений переменных Grafana:

SELECT max("Usage.committed")
FROM "telegraf"."month"."java_memory_pool"
WHERE
    host =~ /^serverName$/ AND
    jolokia_agent_url =~ /^http:\/\/127\.0\.0\.1:7777\/jvm-service$/ AND
    time >= 1583834400000ms and time <= 1583877600000ms
GROUP BY
    "Type", "name", time(1m)

Группировка по времени GROUP BY time($granularity) или GROUP BY time(1m) используется, чтобы сократить количество точек на графике. Для периода времени 12 часов и шага группировки 1 минута получаем: 12 х 60 = 720 отрезков времени или 721 точку (последняя точка со значением null).

Запомним, что 721 — ожидаемое количество точек в ответе на запросы к InfluxDB при текущих настройках интервала времени (12 часов) и шага группировки (1 минута).

Пул памяти NON_HEAP: Metaspace (синий) в лидерах потребления памяти на момент 20:00. А по HEAP: G1 Old Gen (желтый) был небольшой локальный всплеск в 17:03. И на момент 20:00 в сумме на все NON_HEAP-пулы ушло 172.5 MiB (113.2 + 45.9 + 13.4), а на HEAP-пулы 128 MiB (67 + 57 + 4).



Запомним значения для 20:00: NON_HEAP-пулы 172.5 MiB, и HEAP-пулы 128 MiB. Будем ориентироваться на эти значения в будущем.

В разрезе Type: name значение метрики мы получили легко.
В разрезе только тега name значение метрики получить тоже легко, так как все имена пулов памяти уникальны, и достаточно оставить группировку результатов только по name.

Остается вопрос: как получить, какой размер выделен под все HEAP-пулы и все NON_HEAP-пулы в сумме?

1. Просто сумма с группировкой по тегу Type


1.1. Сумма с группировкой по тегу


Первое решение, которое может придти на ум — сгруппировать значения по тегу Type и вычислить сумму значений в каждой группе. Такой запрос будет выглядеть так:



Текстовое представление запроса вычисления суммы с группировкой по тегу Type со всеми переменными Grafana:

SELECT sum("Usage.committed")
FROM "telegraf"."month"."java_memory_pool"
WHERE
    host =~ /^${host:regex}$/ AND
    jolokia_agent_url =~ /^${jolokia:regex}$/ AND
    $timeFilter
GROUP BY
    "Type"

Это валидный запрос, но он вернёт всего две точки: сумма вычислится с группировкой лишь по тегу Type с двумя значениями (HEAP и NON_HEAP). Мы даже график не увидим. Будут две отдельностоящие точки с огромной суммой в значениях (более 3-х TiB):



Такая сумма не годится, нужна разбивка на интервалы времени.

1.2. Сумма с группировкой по тегу за минуту


В исходном запросе мы группировали метрики по настраиваемому интервалу $granularity. Сделаем и сейчас группировку по настраиваемому интервалу.

Получится такой запрос, в нём добавилось GROUP BY time($granularity):



Получаем завышенные значения, вместо 172.5 MiB по NON_HEAP видим, 4.88 GiB:



Так как метрики отправляются в InfluxDB раз в 2 секунды (смотри telegraf.conf выше), то сумма показаний за одну минуту, даст сумму не в моменте, а сумму тридцати таких сумм.

Поделить результат на константу 30 мы тоже не можем. Так как $granularity — параметр, его можно задать как равным 1 минуте, так и 10-ти минутам. И значение суммы будет меняться.

1.3. Сумма с группировкой по тегу за секунду


Чтобы верно получить значение метрики для текущей интенсивности сбора метрик (2 секунды), нужно считать сумму за фиксированный интервал, не превышающий интенсивность сбора метрик.

Попробуем выводить статистику с группировкой по секундам. Добавим в GROUP BY группировку time(1s):



При такой малой гранулярности получаем для нашего интервала времени в 12 часов огромное количество точек (12 часов * 60 минут * 60 секунд = 43 200 интервалов, 43 201 точка на линию, последняя из которых со значением null):



43 201 точка в каждой линии графика. Точек так много, что InfluxDB будет долго формировать ответ, Grafana будет дольше принимать ответ, а потом браузер будет долго отрисовывать такое огромное количество точек.

И не в каждой секунде есть точки: метрики собирались раз в 2 секунды, а группировка по каждой секунде, значит, каждая вторая точка будет со значением null. Чтобы увидеть плавную линию, настроим соединение непустых значений. Иначе графиков мы не увидим:



Раньше Grafana была такой, что браузер зависал во время отрисовки большого количества точек. Сейчас версия Grafana имеет возможность отрисовать несколько десятков тысяч точек: браузер просто пропускает часть из них, рисует график по прореженным данным. Но график сглаживается. Максимумы отображаются, как средние максимумы.

В результате график есть, отображается точно, метрики в 20:00 посчитаны верно, метрики в легенде графика посчитаны верно. Но график сглаженный: на на нём не видны всплески с точностью до 1 сек. В частности всплеск по HEAP в 17:03 пропал с графика, график HEAP очень гладкий:



Минус в производительности отчетливо проявится на большем интервале времени. Если попытаться построить график за месяц (720 часов), а не за 12 часов, то всё зависнет при такой малой гранулярности (1 секунда), точек будет слишком много. И есть минус в отсутствии пиков, парадокс — из-за высокой точности получения метрик, мы получаем низкую точность их отображения.

2. Grafana-way. Используем стек значений


Сделать простое и производительное решение с InfluxDB и конструктором запросов Grafana не получилось. Попробуем лишь средствами Grafana просуммировать метрики, выдаваемые в исходном графике. И да, такое возможно!

2.1. Просто сделаем Hover tooltip / Stacked value: cummulative


Запрос выбора метрик оставим без изменений, такой же как в разделе «Как всё начиналось»:



Метрики будут группироваться по Type и name. Но в названия графиков будем выводить только тег Type:



А в настройках визуализации сделаем группировку метрик по стекам Grafana:



Сначала добавим разделение двух тегов на два разных стека A и B, чтобы их значения не пересекались:

  1. Add series override / HEAP / Stack: A
  2. Add series override / NON_HEAP / Stack: B

Затем настроим визуализацию метрик на отображение суммарных значений во всплывающей подсказке с графикам:

  1. Stacking & Null value / Stack: On
  2. Hover tooltip / Stacked value: cummulative
  3. Hover tooltip / Mode: Single

Из-за разных особенностей Grafana нужно выполнять действия именно в таком порядке. Если изменить порядок действий или оставить некоторые поля с настройками по умолчанию, то что-нибудь не сработает:

  • если разделить метрики на Stack A и B уже после активации Stacking & Null value / Stack: On, то метрики не разделятся;
  • если оставить Hover tooltip / Mode со значением по умолчанию, не перевести в Single, то Hover tooltip не будет отображаться вообще.

А теперь так — видим множество линий, такое себе. Но! Если навести указатель на самый верхний NON_HEAP, то во всплывающей подсказке будет видна сумма значений всех NON_HEAP. Сумма считается верно, уже средствами Grafana:



А если навести курсор на самый верхний график с именем HEAP, то увидим сумму по HEAP. График отображается верно. Даже всплекск по HEAP в 17:03 виден:



Формально, задача выполнена.

Но есть минусы — отображается много лишних графиков. Нужно попасть курсором в самый верхний из них. И в легенде к графику отображается не кумулятивные, а отдельные значения, поэтому легенда стала бесполезной.

2.2. Stacked value: cummulative со скрытием промежуточных линий


Поправим первый минус предыдущего решения: сделаем так, чтобы лишние графики не отображались.

Для этого:

  1. Добавим в результаты новые метрики с другим именем и значением 0.
  2. Новые метрики добавим в Stack A и Stack B, на вершину стека.
  3. Скроем из отображения — оригинальные линии HEAP и NON_HEAP.

Добавим после основного запроса два новых: запрос B на получение серии со значениями 0 и именем [NON_HEAP] и запрос C на получение серии со значениями 0 и именем [HEAP]. Чтобы получить 0, берем в каждой временной группе первое значение поля «Usage.committed» и вычитаем его же: first(«Usage.committed»)-first(«Usage.committed») — получим стабильный 0. Названия графиков изменены без потери смысла за счёт квадраных скобок: [NON_HEAP] и [HEAP]:



[HEAP] и HEAP объединены в Stack A, а ещё скроем все HEAP. [NON_HEAP] и NON_HEAP объединим в Stack B и скроем NON_HEAP:



Получаем корректную сумму по [NON_HEAP] в Tooltip при наведении на график:



Получаем корректную сумму по [HEAP] в Tooltip при наведении на график. И даже видны все всплески:



И график формируется быстро. Но в легенде отображается всегда 0, легенда стала бесполезной.

Всё получилось! Правда в обход — через стеки Grafana. Именно из-за этого статья добавлена в категорию Ненормальное программирование.

3. Сумма максимумов с подзапросом


Раз мы уже ступили на путь ненормального программирования на связке Grafana и InfluxDB, давайте продолжим. Сделаем так, чтобы InfluxDB вернул небольшое количество точек и чтобы легенда отображалась.

3.1 Сумма приращений кумулятивной суммы максимумов


Углубимся в возможности InfluxDB. Раньше меня часто выручало взятие производной от кумулятивной суммы, поэтому попробуем применить этот подход и сейчас. Перейдем в режим ручного редактирования запросов:



Составим такой запрос:

SELECT sum("U") FROM (
        SELECT non_negative_difference(cumulative_sum(max("Usage.committed"))) AS "U" 
        FROM "month"."java_memory_pool" 
        WHERE 
            (
                "host" =~ /^${host:regex}$/ AND 
                "jolokia_agent_url" =~ /^${jolokia:regex}$/
            ) AND 
            $timeFilter 
        GROUP BY time($granularity), "Type", "name"
)
GROUP BY "Type", time($granularity)

Тут берётся максимальное значение метрики в группе по времени и считается сумма таких значений с момента начала отсчёта с группировкой по тегам Type и name. В результате в каждый момент времени будет сумма всех показаний по типу (HEAP или NON_HEAP) с разделением по имени пула, но просуммируется не 30 значений, как было в варианте 1.2, а только одно — максимальное.

И если взять приращение non_negative_difference такой накопительной суммы за последний шаг, то мы получим значение суммы всех пулов данных с группировкой по тегам Type и name на момент начала интервала времени.

Теперь, чтобы получить сумму только по тегу Type, без группировки по тегу name, надо сделать запрос верхнего уровня, с похожими параметрами группировки, но без группировки по name.

В результате выполнения такого сложного запроса получим сумму по всем типам.

Идеальный график. Сумма максимумов посчитана верно. Есть легенда с корректными значениями, ненулевыми. Во всплывающей подсказке можно отразить все метрики, а не только Single. Отображаются даже всплески по HEAP:



Одно но — запрос получился непростым: сумма приращения кумулятивной суммы максимумов со сменой уровня группировки.

3.2 Сумма максимумов со сменой уровня группировки


Может можно сделать что-то попроще, чем в варианте 3.1? Ящик Пандоры уже открыт, мы перешли в режим ручного редактирования запросов.

Есть подозрение, что получение приращения от кумулятивной суммы приводит к нулевому эффекту — одно гасит другое. Избавимся от non_negative_difference(cumulative_sum(...)).

Упростим запрос.

Оставим просто сумму максимумов, с уменьшением уровня группировки:

SELECT sum("A")
FROM (
    SELECT max("Usage.committed") as "A"
    FROM "month"."java_memory_pool" 
    WHERE
            (
                "host" =~ /^${host:regex}$/ AND 
                "jolokia_agent_url" =~ /^${jolokia:regex}$/
            ) AND 
            $timeFilter
    GROUP BY time($granularity), "Type", "name"
)
WHERE $timeFilter
GROUP BY time($granularity), "Type"

Это быстрый простой запрос, который возвращает всего 721 точку на серию за 12 часов, при группировке по минутам: 12 (часов) * 60 (минут) = 720 интервалов, 721 точка (последняя пустая). Обратите внимание, что фильтр по времени дублируется. Он есть в подзапросе и в группирующем запросе:



Без $timeFilter во внешнем группирующем запросе количество возвращённых точек будет не 721 за 12 часов, а больше. Так как загруппировка подзапроса выполняется для интервала fromto, а группировка внешнего запроса без фильтра будет для интервала fromnow. И если в Grafana будет выбран интервал времени не последние X-часов (не такой, что to = now), а за интервал из прошлого (to < now), то появятся пустые точки со значением null в конце выборки.

Результирующий график получился простым, быстрым, корректным. С легендой, в которой отображаются суммарные метрики. С tooltip для нескольких линий сразу. А также с отображением всех всплесков значений:



Результат достигнут!

Ссылки (вместо списка литературы)


Дистрибутивы используемых в статье инструментов:



Документация о возможностях инструментов, используемых в статье:
Сущность Описание
Retention policy, InfluxDB Data Retention Retention policy montn длиной в 30 дней использую, чтобы хранить метрики производительности JVM и другие оперативные метрики. Обычно политикой по умолчанию является политика auto, которая не имеет максимальной длительности. Используется в «Как всё начиналось» в содержимом telegraf.conf и в текстах запросов к InfluxDB всех разделов, и на снимках конструкторов запросов Grafana
Telegraf / InfluxDB v1.x Output Plugin Настройка отправки метрик из Telegraf в InfluxDB. Используется в в содержимом telegraf.conf
Telegraf / agent / interval В статье описан случай, когда метрики собираются каждые 2 секунды. Используется в «Как всё начиналось» в содержимом telegraf.conf. И в «1.2. Сумма с группировкой по тегу за минуту» и «1.3. Сумма с группировкой по тегу за секунду»
Java 8 / Interface MemoryPoolMXBean Описание интерфейса MemoryPool, где видно, что все поля либо bool, либо long. Поэтому все метрики в telegraf.conf приводятся в типу int
Telegraf / Jolokia2 Input Plugins Используется в telegraf.conf для выбора MBean-полей, которые будут сохраняться в InfluxDB
Telegraf / Converter Processor Используется в telegraf.conf, чтобы сконвертировать метрики из типа float в тип int перед сохранением в InfluxDB. И чтобы сконвертировать строковое поле Type в тег Type, именно по нему и выполняется группировка в статье
Grafana / Variables / Advanced Formatting Options / Regex Переменные Grafana, для которых настроен Multiselect не нуждаются в экранировании, а остальным необходимо экранирование, если они используются в фильтрах, как регулярные выражения ~ /^${переменная}$/ — недостаточно, нужно ~ /^${переменная:regex}$/
Grafana / Variables / Global Built-in Variables / The $timeFilter or $__timeFilter Variable Описание Grafana-макроподстановки $timeFilter, которая используется во всех запросах
InfluxDB / MAX() Описание селектора MAX() из InfluxDB 1.7, который используется для выбора максимального значения поля
InfluxDB / SUM() Описание функции аггрегирующей функции SUM() из InfluxDB 1.7
InfluxDB / Subqueries Описание механизма подзапросов в InfluxDB 1.7, который используется в разделе 3 статьи
InfluxDB / Transformation / CUMULATIVE_SUM() Описание трансформации CUMULATIVE_SUM(), которая часто пригождается при написании запросов к InfluxDB, в всязке с NON_NEGATIVE_DERIVATIVE()
InfluxDB / Transformation / NON_NEGATIVE_DERIVATIVE() Описание трансформации NON_NEGATIVE_DERIVATIVE(), которая использовалась в разделе 3 статьи. И которая компенсирует эффект CUMULATIVE_SUM() — мы получили нулевой эффект от их связки в разделе 3
Using Grafana’s Query Inspector to troubleshoot issues Описание Query Inspector, которое используется в статье для просмотра количества возвращаемых значений, для просмотра финального запроса со всеми подстановками Grafana-переменных
Grafana / Graph / Draw Options Описание настроек Stack, Tooltip,… которые использовались для отображения суммарного значения во всплывающих подсказках к графикам в разделе «2. Grafana-way. Используем стек значений» статьи
Grafana / Graph / Series overrides Описание возможности переопределить настройки отображения серий значений (отдельной линии графика или группы линий) в Grafana

Итоги


Связку Grafana и InfluxDB нужно хорошо знать инженерам по тестированию производительности. И в этой связке многие простые задачи являются очень интересными, и их не всегда можно решить методами нормального программирования.

Иногда могут понадобиться навыки ненормального программирования с помощью особенностей Grafana и тонкостей языка запросов InfluxDB.

В статье по шагам разобрали четыре варианта реализации суммирования метрики с группировкой по одному тегу, но у которой есть несколько тегов. Задача получилась интересной. И таких задач много.

Готовлю доклад на тему тонкостей программирования с Grafana и InfluxDB. Буду периодически публиковать материалы на эту тему. А пока буду рад вашим вопросам по текущей статье.
Райффайзенбанк
Развеиваем мифы об IT в банках

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

    +1
    Я тоже занимаюсь тестированием производительности и тоже использую jMeter + TICK stack.
    Есть такая проблема, в конфигурации Telegraf есть глобальный тег ip с адресом машины на котором запущен Telegraf, и в графане хочу рядом hostname показывать этот ip. Может и вы сталкивались с этим?
      0
      Пока не сталкивался. Но если задача — вывод hostname и ip в наименовании серии, то можно сделать группировку метрик по двум тегам сразу:

      USE telegraf;
      SELECT mean("usage")
      FROM "cpu"
      WHERE
          hostname =~ /^${hostname:regex}$/ AND
          $timeFilter
      GROUP BY
          "hostname", "ip", time($granularity)

      А в поле ALIAS BY написать:
      $tag_hostname ($tag_ip) mean cpu


      Это как в самом первом запросе статьи в разделе «Как всё начиналось», только теги называться будут не Type и name, а hostname и ip.

      Чтобы вывести в ALIAS BY переменную, можно использовать $tag_{Имя тега} (только такого тега, по которому есть группировка) или $col — имя поля. И ради вывода значения тега в подписи к серии, просто добавляем группировку значений по этому тегу: hostname, а если по два тега нужно вывести, то группируем по двум тегам: hostname и ip.

      Верно понял задачу? Или нужно выводить ip в другом месте: в выпадающем списке, таблице?
        0

        Спасибо за ответ. Мне нужно вывести ip в дропдауне серверов дешборда (в переменных дешборда есть переменная server).

          0

          Понял — задача со звёздочкой.
          Вариант 1
          Вывести в выпадающем списке комбинацию hostname (ip), и по выбранным значениям успешно фильтровать метрики по полям hostname или ip.


          Можно попробовать решить с помощью магии регулярных выражений. Сформировав задачу так: как сформировать регулярное выражение с опциональной частью?


          Чтобы выражение вида


          performanceAgent (10.11.100.111)*

          применилось к списку серверов:


          performanceAgent
          databaseServer
          applicationServer
          moniringServer

          И оставался только один результат: performanceAgent


          Да, такое можно попробовать сделать. Ещё не пробовал.


          Вариант 2
          А пробовал вот как: использовать для фильтрации не выпадающий список, а отдельный dashboard с таблицей ссылок на другие доски. Где все ячейки таблицы являются фильтрами. Тут возможности вывода не ограничены ничем. Можно в таблицу вывести хоть пять колонок.


          Документация на такой способ есть в самом интерфейсе Grafana:



          Specify an URL (relative or absolute)
          Use special variables to specify cell values:
          ${__cell} refers to current cell value
          ${__cell_n} refers to Nth column value in current row. Column indexes are started from 0. For instance,
          ${__cell_1} refers to second column's value.
          ${__cell:raw} syntax. By default values are URI encoded. If the value is a complete URL you can disable all encoding using


          Пример такой фильтрации подготовил в докладе для Heisenbug, конференцию пока перенесли. Если достаточно одного слайда, то он такой:

          Конкретно для случая server, ip пример можно подготовить, но позже.

            0

            Вариант 3 (не рабочий)
            Посмотрел ещё на постпроцессоры telegraf, среди них не нашел такого, который бы ещё на этапе записи метрик в InfluxDB объединил бы hostname и ip_address в одно поле.


            Вот все постпроцессоры:
            https://github.com/influxdata/telegraf#processor-plugins


            Вариант 4 (рабочий)
            Но есть вариант решения, через переменные окружения и небольшое изменение в файле конфигурации telegraf.conf. Решение в обход, ещё один пример ненормального программирования с InfluxDB.


            Можно:


            • периодически обновлять переменную окружения hostname_with_ip: export hostname_with_ip="hostname(hostname -I | awk '{print $1}')"
            • в файле telegraf.conf настроить сохранение переменной окружения hostname_with_ip в тег hostname_with_ip:
            • фильтровать метрики по готовому тегу

            Можно сделать так:


            # Global tags can be specified here in key="value" format.
            [global_tags]
              # dc = "us-east-1" # will tag all metrics with dc=us-east-1
              # rack = "1a"
              ## Environment variables can be used as tags, and throughout the config file
              # user = "$USER"
              hostname_with_ip = "$hostname_with_ip"
            
            [[inputs.exec]]
              commands = ["sh /opt/telegraf_update_hostname_with_ip.sh"]
              timeout = "60s"
              data_format = "influx"

            Можно выполнение export hostname_with_ip="hostname(hostname -I | awk '{print $1}')" поместить куда-нибудь в /etc/profile.d/telegraf_update_hostname_with_ip.sh
            тогда не надо будет делать секцию [[inputs.exec]]


            И просто фильтруем по готовой переменной.

        +3

        В influx уже давно завезли вложенные query. Вы можете сделать так:


        select a+b from (select ... as a from ..; select ... as b from ..) group by time(1m).

        В многоточии — ваши обычные запросы.

          0

          Да, подзапросы есть. Да, за счёт подзапросов можно преобразовать теги в поля. Но у hostname и ip тип — String, а операция + не работает для строк в InfluxDB.

            0

            В комментарии выше всё же описал Вариант 1. Там предположил, что подобная конструкция будет работать. Позже прочел ваш amarao комментарий, про сложение, и понял, что Вариант 1 не получится реализовать. Строки не комбинируются в InfluxDB 1.7, в InfluxDB 2.0, возможно комбинируются.

          +1

          Про $granularity не очень понятно. Это переменная dashboard-ы со списком, чтобы вручную выбирать интервал группировки? А чем не подходит GROUP BY ($__interval)?

            +1

            Хороший вопрос, спасибо.


            Да, $granularity — список констант, с интервалом времени.


            Сделан для ускорения отображения большого количества графиков, чтобы показать меньше точек. Чтобы можно было задать группировку по минутам, и получить на графике 100 точек вместо 1900 точек (при ширине монитора 1980 точек).


            Также для отладки неудачных запросов. И для возможности предсказания ожидаемого количества точек => для наличия критериев соответствия результата запроса настройкам.


            Причина — не самое производительное оборудование для станций мониторинга.


            И для обратной ситуации, чтобы иногда показать больше точек, чем поддерживает монитор. Показать на отдельном графике три месяца, но с группировкой по минутам. Это используется, чтобы найти на графике отдельный кратковременный запуск теста. Или метрики по отдельному процессу, который фиксировался однажды в момент тестирования, ссылки на временной интервал не сохранилось, и теперь надо его визуально найти. Представьте, что вы выполняли когда-то в этом году тестирование длительностью 30 минут, и вот сейчас отображаете последние 6 месяцев на графике. В этом случае для разрешения 1900 точек получается, что в каждой точке будет 6×30×24×60÷1900=136,42 минут, примерно с такой группировкой выполнится запрос при настройке auto. А если все метрики собирались всего 30 минут, и на графике отображается одна точка, то точку не видно. Некоторые графики для отображения нуждаются в двух точках, и при группировке превышающей весь набор сбора метрик вообще график не получить. Например, функции NON_NEGATIVE_DERIVATIVE(), DERIVATIVE(), NON_NEGATIVE_DIFFERENCE(), DIFFERENCE(),… в таком случае не вернут числовой результат им нужно две точки минимум.


            Причина почему из 6 месяцев сбора метрик бывает нужно найти только интервал в 30 минут — нерегулярные запуски тестов, нерегулярный сбор метрик из-за переключений между проектами. Стенд может собраться, тесты будут выполнены (30 минут). А следующий запуск тестов, через недели три, а может через месяц.


            Кстати эту проблему уже решил, на связке Grafana + InfluxDB можно сделать ссылки на конкретные участки временного ряда, и кликом по гиперссылке получить нужный интервал времени. Это интересная и полезная задача. Расскажу скоро и о ней.


            Из-за таких причин приучил себя везде использовать настраиваемый интервал времени. Иметь такую возможность.


            Если отдавать разработанную доску во внешний мир, то можно в $granularity оставить одно значение = auto, а саму переменную скрыть. Тогда у пользователей всегда будет одно значение, основанное на количестве пикселей в графике. Но пока идёт разработка, параметр $granularity полезен с разными значениями.


            The $__interval Variable


            Цитата
            The $__interval is calculated using the time range and the width of the graph (the number of pixels).

            Approximate Calculation: (from - to) / resolution

            For example, when the time range is 1 hour and the graph is full screen, then the interval might be calculated to 2m — points are grouped in 2 minute intervals. If the time range is 6 months and the graph is full screen, then the interval might be 1d (1 day) — points are grouped by day.
              +1

              Спасибо за развёрнутый ответ! У меня опыт с Prometheus и я как-то предположил, что тамошние операции с указанием интервала это примерно тоже самое что и GROUP BY ($__interval) в Influx. Там есть семейство операций *_over_time и вот они как раз умеют работать с $__interval с учётом данных во всех промежуточных точках, которые есть в базе.


              Чтобы не пропустить редкие случаи проблем и при этом не запрашивать много точек, помогают min_over_time/max_over_time/count_over_time, но можно пойти дальше и сократить количество запрашиваемых точек, т.к. важен только факт присутствия какого-то статуса в промежутке времени. Собственно так и появился плагин grafana-statusmap, с ним количество запрашиваемых точек выходит меньше, чем для $__interval, но при этом всё равно можно видеть редкие проблемы. Т.е. в вашем случае на доске с тестами я бы сделал отдельный график «Запуск тестов» или «Статус тестов» с этим плагином и показывал бы на нём наличие метрик по тестам или метрику успешности тестов. При этом на графиках с DERIVATIVE() может быть пусто, но в «Статус тестов» будут квадратики — значит в то время был неуспешный тест, значит можно уточнить time range, $__interval уменьшиться и на графиках что-то появится.
              Если есть желание попробовать, можно в личке обсудить, я бы потом утащил в README как пример использования для influx.

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое