Мониторинг загрузки 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 занимает 66,6%, а остальные режимы - 33,3%:

В практическом плане, полученные значения вида
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’е.
