Мониторинг загрузки CPU (CPU Usage) с помощью системы мониторига Prometheus.

[ prometheus  cpu  linux  monitoring  ]

Итак, сегодня рассмотрим мониторинг загрузки CPU с помощью системы мониторинга prometheus.

Посмотрим что у нас есть изначально, какие значения можно получать в сыром виде. По факту, экспортер собирает данные о загрузке CPU в виде монотонно возрастающего числа. Такой тип данных в prometheus называется counter. Данное число, это время в USER_HZ — сотых долях секунды, которое процессор провел в том или ином режиме, с момента старта ОС до настоящего времени.

Что бы получить все значения метрик по CPU выполним запрос в prometheus.

Пример запроса:
node_cpu{job="node",instance="node-exporter:9100"}

Возвращаемый результат:

Element Value
node_cpu{cpu=”cpu0”,instance=”node-exporter:9100”,job=”node”,mode=”guest”} 0
node_cpu{cpu=”cpu0”,instance=”node-exporter:9100”,job=”node”,mode=”guest_nice”} 0
node_cpu{cpu=”cpu0”,instance=”node-exporter:9100”,job=”node”,mode=”idle”} 1241.12
node_cpu{cpu=”cpu0”,instance=”node-exporter:9100”,job=”node”,mode=”iowait”} 86.91
node_cpu{cpu=”cpu0”,instance=”node-exporter:9100”,job=”node”,mode=”irq”} 0
node_cpu{cpu=”cpu0”,instance=”node-exporter:9100”,job=”node”,mode=”nice”} 0
node_cpu{cpu=”cpu0”,instance=”node-exporter:9100”,job=”node”,mode=”softirq”} 0.92
node_cpu{cpu=”cpu0”,instance=”node-exporter:9100”,job=”node”,mode=”steal”} 0
node_cpu{cpu=”cpu0”,instance=”node-exporter:9100”,job=”node”,mode=”system”} 28.67
node_cpu{cpu=”cpu0”,instance=”node-exporter:9100”,job=”node”,mode=”user”} 42.6

Видим время, потраченное каждым CPU (в моем случае один, cpu0) в каждом из режимов (guest, guest_nice, idle, iowait,irq, nice, softirq, steal, system, user).

Что бы посчитать загрузку CPU, нужно взять изменение значения в режиме idle за какой то небольшой промежуток (например 1m) и поделить значение этого изменения на этот промежуток времени (в секундах). Так как известно, что в случае если эти значения будут равны (результат деления равен 1), то процессор простаивал все 100% времени. Для нахождения загрузки мы должны инвертировать полученный результат, и в результате увидим насколько был загружен процессор. Что бы получить значение в процентах, нужно результат этого отношения умножить на 100.

Для более наглядного примера покажу два графика.

Первый пример, где idle занимает 100% времени: idle_100%

Второй пример, где idle занимает 66,6%, а остальные режимы - 33,3%: idle_100%

В практическом плане, полученные значения вида node_cpu{cpu="cpu0",instance="node-exporter:9100",job="node",mode="iowait"} - 86.91 мало как могут помочь. В этом примере мы можем понять что к моменту получения этого значения CPU провел в режиме iowait 86.91 сотых секунды.

Попробуем сделать выборку за определенное время, например за 1 минуту, и увидеть значение уже не в одной временной точке, а в нескольких, и что немаловажно, с привязкой к относительному времени (time stamp). В запросе ниже получаем значения для только для режима idle.

Пример запроса:
node_cpu{job="node",instance="node-exporter:9100",mode="idle"}[1m]

Возвращаемый результат:

Element Value
node_cpu{cpu=”cpu0”,instance=”node-exporter:9100”,job=”node”,mode=”idle”} 2418.97 @1549983562.011
  2423.32 @1549983567.011
  2427.77 @1549983572.011
  2431.97 @1549983577.011
  2436.32 @1549983582.011
  2440.48 @1549983587.011
  2444.79 @1549983592.011
  2449.13 @1549983597.011
  2453.22 @1549983602.017
  2456.18 @1549983607.013
  2460.12 @1549983612.011
  2464.3 @1549983617.011

Как видно, запрос вернул определенное количество значений за интервал с текущего времени и до 1 минуты назад в прошлое.

В сыром виде с этими данными так же сложно что либо сделать, да и к тому же отобразить их на графике не получится. Но теперь мы можем посчитать скорость возрастания значения, так как у нас есть привязка ко времени каждого значения. Другими словами, если показатель времени (это разница между последним значением (2464.3) и первым значением (2418.97)) будет равна временному интервалу, за который это значение измерялось (разница между временными метками (timestamp) соотвественно последнего значения (1549983617.011) и первого значения (1549983562.011)), то есть отношение будет равно 1, то в этом случае можно говорить о том, что процессор провел 100% своего времени в режиме idle. Если смотреть на значения из запроса выше, то в “человеческом” виде расчет можно записать так:

2464.3 - 2418.97 = 45,33 - разница между последним значением и первым значением

1549983617.011 - 1549983562.011 = 55 (sec) - разница между временными метками (timestamp) соотвественно последнего значения и первого значения

45,33 / 55 = 0,8241818182 - скороть прироста времени, которое процессор провел в режиме idle за минуту времени.

Такого результата мы можем добиться от promeheus через следующий запрос:

rate(node_cpu{job="node",instance="node-exporter:9100",mode="idle"}[1m])

Что бы получить значение в секундах, нужно умножить полученное значение на 100:

(rate(node_cpu{job="node",instance="node-exporter:9100",mode="idle"}[1m])) * 100

Теперь инвертиртируем полученное значение для режима idle и получим значение загрузки процессора:

100 - (rate(node_cpu{job="node",instance="node-exporter:9100",mode="idle"}[1m])) * 100

Для того, что бы взять среднее значение по всем cpu и core выполним следующий запрос:

100 - (avg by (instance) (rate(node_cpu{job="node",instance="node-exporter:9100",mode="idle"}[1m])) * 100)

И напоследок скажу, есть есть еще функция irate, которая работает так же как и rate, но отличается тем, что считает скорость изменения полученного значения не во всем диапазоне (в нашем примере это [1m]), а для последних значений из этого диапазона (в последнем примере это будут 2460.12 @1549983612.011 и 2464.3 @1549983617.011). Как можно догадаться, она дает более точные показатели.

Конечный запрос с применением этой функции будет выглядеть так:

100 - (avg by (instance) (irate(node_cpu{job="node",instance="node-exporter:9100",mode="idle"}[1m])) * 100)

Этот запрос теперь можно использовать в для получения метрик по CPU, например в grafan’е.

Written on February 14, 2019