目次
概要
PrometheusでCPUとメモリを監視するためのPromQLの例。
関連記事
Prometheus、Node Exporterの環境構築手順はこちらを参照。
Prometheus環境を構築手順
PromQLを書くための基礎知識はこちらを参照。
PrometheusでPromQLを扱う前に知っておいたほうがよい知識
CPU使用率
| PromQL | 意味 |
| --- | --- | --- |
| node_cpu_seconds_total | 各コア,各モードのCPU使用時間の累計を記録したメトリック(秒) |
example.com:9100(node-exporterが入っている)の各mode(idleを除く)の直近1分間のCPU使用時間の平均を計算するPromQL。
rate(node_cpu_seconds_total{mode!="idle"}[1m])
以下の表は各modeとその意味をまとめたもの。上記の例では、結果からidleを取り除いている。
引用元:https://www.codetd.com/ja/article/12249521
mode | desc |
---|---|
user | ユーザープロセスがCPUを使用する時間 |
system | カーネルプロセスがCPUを使用する時間 |
nice | ユーザープロセススペースで優先度が変更されたプロセスによって使用されるCPU時間 |
idle | アイドル(誰も使用しない)CPU時間 |
iowait | ioを待機しているCPU時間 |
irq | ハード割り込みのCPU時間(hardware interrupts) |
softirq | ソフト割り込みのCPU時間(software interrupts) |
steal | ハイパーバイザーによって使用されるCPU時間 |
topコマンドを実行すると以下のような行があるが、ここに表示されているus, sy, niなどが、これらのmodeに当たる。
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
マルチコアCPUの場合
マルチコアノードの場合、以下で各modeの平均値を出す。
without(cpu)
は、各CPUの平均を出すため、計算時にCPU番号を無視するための式。
avg without(cpu) (rate(node_cpu_seconds_total{instance="example.com:9100", mode!="idle"}[1m]))
avg
の他に、avg_over_time
もある。
avg
、rate
の組み合わせで算出するのに対し、avg_over_time
は単純にその時間の範囲の平均値を算出する。
以下のように使う。
avg_over_time(node_cpu_seconds_total{mode!="idle"}[1m])
参考:サンプルで学ぶ!PromQLで自在にグラフを描こう (Prometheus + Grafana)
CPU使用率が80%を超えているものを出力する例
avg without(cpu) (rate(node_cpu_seconds_total{instance="example.com:9100", mode!="idle"}[1m])) >= 0.8
ロードアベレージ
PromQL | 意味 |
---|---|
node_load1 | 1分間のロードアベレージ |
node_load5 | 5分間のロードアベレージ |
node_load15 | 15分間のロードアベレージ |
normalizeする場合はCPUのコア数で割る。
FYI: Which is Better: CPU Load or Normalized CPU Load?
ロードアベレージが1を超えたものを出力(normalizeする)
# ロードアベレージ / CPUコア数
node_load1 / count(count(node_cpu_seconds_total{instance="example.com:9100"}) without (mode)) without (cpu) > 1
メモリ使用率
PromQL | 意味 |
---|---|
node_memory_MemTotal_bytes | メモリ総容量 |
node_memory_MemAvailable_bytes | メモリ空き容量 |
# メモリ総容量 - メモリ空き容量 = 現在の使用量
node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes
メモリ使用率が80%以上のものを出力
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes >= 0.8
ディスク容量
PromQL | 意味 |
---|---|
node_filesystem_size_bytes | ディスク総容量(bytes) |
node_filesystem_avail_bytes | 残りディスク容量(bytes) |
ディスク使用率
1 - (node_filesystem_avail_bytes / node_filesystem_size_bytes)
inode使用率
PromQL | 意味 |
---|---|
node_filesystem_files_free | freeのinode数 |
node_filesystem_files | 総inode数 |
inode使用率
1 - (node_filesystem_files_free / node_filesystem_files)
I/OリクエストによるCPU使用率
PromQL | 意味 |
---|---|
node_disk_io_time_seconds_total | IOに費やされた時間の合計秒数 |
Prometheusのrate(node_disk_io_time_seconds_total[1m])
は、iostat
コマンドの%utilの値と同義。
%util = デバイスへのI/OリクエストによるCPU使用率
参考:iostat 見方
I/O負荷を与えてみる
I/O負荷を与え、iostatコマンドとPormQL rate(node_disk_io_time_seconds_total[1m])
の結果を比べてみる。
負荷を与える
stress-ngコマンドを使い30GBの書き込みを行い負荷を与える。
参考:stress-ngコマンドでCPU、メモリ、ディスクに負荷をかける
$ stress-ng -d 3 --hdd-bytes 30G
iostatの結果
option | desc |
---|---|
-d | デバイス使用率のみを出力する |
-t | 計測した時刻を出力する |
-x | ディスク統計情報を出力する |
10 | 10秒ごとの結果を出力する |
$ iostat -dtx 10
Linux 3.10.0-1127.19.1.el7.x86_64 (example.com) 06/09/2021 _x86_64_ (8 CPU)
# stress-ngコマンド実行前
06/09/2021 03:35:04 PM
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.00 0.14 0.19 1.52 16.90 44.59 72.03 0.00 4.61 0.56 5.11 0.11 0.02
scd0 0.00 0.00 0.00 0.00 0.00 0.00 9.96 0.00 0.72 0.72 0.00 0.72 0.00
# stress-ngコマンド実行後
06/09/2021 03:35:14 PM
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.00 0.10 2.10 2051.00 91.60 1031840.25 1005.24 86.22 82.18 0.14 82.26 0.33 67.81
scd0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
# stress-ngコマンド実行後、utilが100%近くなっている
06/09/2021 03:35:24 PM
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.00 2.40 0.20 2980.60 3.20 1498235.60 1005.26 127.44 84.47 4.50 84.48 0.34 99.97
scd0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
PromQLの結果
I/OリクエストによるCPU使用率
rate(node_disk_io_time_seconds_total[1m])
stress-ngコマンド実行後
1.0、つまり100%になっている。
iostat
コマンドの%utiでも、PromQLの結果、どちらも100%近くになっていることを確認できた。
I/Oレイテンシ
PromQL | 意味 |
---|---|
node_disk_read_time_seconds_total | IOのreadに費やされた時間の合計秒数 |
node_disk_reads_completed_total | 正常に完了したreadの合計数 |
node_disk_write_time_seconds_total | IOのwriteに費やされた時間の合計秒数 |
node_disk_writes_completed_total | 正常に完了したwriteの合計数 |
これらは/proc/diskstatsから値を取得している。
node_disk_read_time_seconds_total
node_disk_reads_completed_total
node_disk_write_time_seconds_total
node_disk_writes_completed_total
$ cat /proc/diskstats
252 0 vda 4682174 4304 929662806 2502865 27994455 2461794 1996846903 172438082 0 3754119 98035986
252 1 vda1 152 0 1216 61 0 0 0 0 0 61 61
252 2 vda2 4681923 4304 929656982 2502765 27816578 2461786 1996846823 172315078 0 2975909 96782251
11 0 sr0 53 0 528 38 0 0 0 0 0 38 38
PromQLの結果と/proc/diskstatsで値が同じことが確認できる。
小数点の位置が異なるものもあるが、millisecondsかsecondsかで計測しているかの違い(だと思われる)。
PromQL | sr0(Prom) | sr0(diskstats) | vda(Prom) | vda(diskstats) |
---|---|---|---|---|
node_disk_read_time_seconds_total (/proc/diskstats:7列目) |
0.038 | 38 | 2502.8650000000002 | 2502865 |
node_disk_reads_completed_total (/proc/diskstats:4列目) |
53 | 53 | 4682174 | 4682174 |
node_disk_write_time_seconds_total (/proc/diskstats:11列目) |
0 | 0 | 172438.082 | 172438082 |
node_disk_writes_completed_total (/proc/diskstats:8列目) |
0 | 0 | 27994455 | 27994455 |
Read
IOのreadに費やされた時間の合計秒数 / 正常に完了したreadの合計数 = Read1回あたりにかかった秒数
rate(node_disk_read_time_seconds_total[1m]) / rate(node_disk_reads_completed_total[1m])
Write
IOのwriteに費やされた時間の合計秒数 / 正常に完了したwriteの合計数 = Write1回あたりにかかった秒数
rate(node_disk_write_time_seconds_total[1m]) / rate(node_disk_writes_completed_total[1m])
平均I/Oリクエストサイズ
PromQL | 意味 |
---|---|
node_disk_io_time_weighted_seconds_total | The weighted number of seconds spent doing I/Os |
"The weighted number of seconds"は直訳すると「加重秒数」だが、意味がよく分からない。加重平均なら分かるが。何かに重み付けをした上での秒数なのか?何に?サイズ?I/O数?
加重平均とは - 【プログラマーのための統計学】平均値の算出方法は1つじゃない
これは/proc/diskstatsの最後の列の値を取得している。diskstatsの最後の列の値についての説明は以下。
the weighted number of milliseconds spent doing I/Os
With the exception of operations in progress, all of the fields are cumulative counters that increase over time. The last field, the weighted number of milliseconds spent doing I/O operations, is special because it includes operations currently in-flight; it is basically the sum of the time spent for every operation, plus those not yet completed:
引用元:https://www.xaprb.com/blog/2010/01/09/how-linux-iostat-computes-its-results/
PromQLと/proc/diskstatsの値を比較してみる。
$ cat /proc/diskstats
252 0 vda 4682204 4304 929664814 2502877 27998500 2462121 1996915380 172444038 0 3754432 98041060
252 1 vda1 152 0 1216 61 0 0 0 0 0 61 61
252 2 vda2 4681953 4304 929658990 2502777 27820589 2462113 1996915300 172321011 0 2976171 96787196
11 0 sr0 53 0 528 38 0 0 0 0 0 38 38
PromQLの結果と/proc/diskstatsで値が同じことが確認できる。
小数点の位置が違うのは、以下の違いがあるため。
- /proc/diskstats => the weighted number of milliseconds spent doing I/Os
- node_disk_io_time_weighted_seconds_total => the weighted number of seconds spent doing I/Os
PromQL | sr0(Prom) | sr0(diskstats) | vda(Prom) | vda(diskstats) |
---|---|---|---|---|
node_disk_io_time_weighted_seconds_total (/proc/diskstats:最後の列目) |
0.038 | 38 | 98041.06 | 98041060 |
加重秒数の意味が分かっていないが、I/Oリクエストの平均サイズの算出は以下、らしい。
rate(node_disk_io_time_weighted_seconds_total[1m])
負荷をかけてから実行するとこんな感じ。
$ stress-ng -d 3 --hdd-bytes 30G
alert.rules記述例
groups:
- name: sample001
rules:
- alert: cpu_usage_exceeds_80%
# CPU使用率が80%を超えているもの
expr: avg without(cpu) (rate(node_cpu_seconds_total{mode!="idle"}[1m])) >= 0.8
for: 5m
labels:
severity: critical
annotations:
firing_text: "[{{ $labels.env }}] {{ $labels.instance }} CPU usage exceeds 80%"
resolved_text: "[{{ $labels.env }}] {{ $labels.instance }} CPU usage falls"
- alert: cpu_load_avg_exceeds_1
# ロードアベレージが1を超えたもの
expr: node_load1 / count(count(node_cpu_seconds_total) without (mode)) without (cpu) > 1
for: 5m
labels:
severity: critical
annotations:
firing_text: "[{{ $labels.env }}] {{ $labels.instance }} CPU load average exceeds 1"
resolved_text: "[{{ $labels.env }}] {{ $labels.instance }} CPU load average falls"
- alert: memory_usage_exceeds_80%
# メモリ使用率が80%以上のもの
expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes >= 0.8
for: 5m
labels:
severity: critical
annotations:
firing_text: "[{{ $labels.env }}] {{ $labels.instance }} Memory usage exceeds 80%"
resolved_text: "[{{ $labels.env }}] {{ $labels.instance }} Memory usage falls"
- alert: disk_usage_exceeds_80%
# ディスク使用率が80%以上のもの
expr: 1 - (node_filesystem_avail_bytes / node_filesystem_size_bytes) >= 0.8
for: 5m
labels:
severity: critical
annotations:
firing_text: "[{{ $labels.env }}] {{ $labels.instance }} Disk usage exceeds 80%"
resolved_text: "[{{ $labels.env }}] {{ $labels.instance }} Disk usage falls"
- alert: disk_usage_exceeds_80%
# inode使用率が80%以上のもの
expr: 1 - (node_filesystem_files_free / node_filesystem_files) >= 0.8
for: 5m
labels:
severity: critical
annotations:
firing_text: "[{{ $labels.env }}] {{ $labels.instance }} Inode usage exceeds 80%"
resolved_text: "[{{ $labels.env }}] {{ $labels.instance }} Inode usage falls"
- alert: io_usage_exceeds_80%
# I/OリクエストによるCPU使用率が80%以上のもの
expr: rate(node_disk_io_time_seconds_total[1m]) >= 0.8
for: 5m
labels:
severity: critical
annotations:
firing_text: "[{{ $labels.env }}] {{ $labels.instance }} I/O usage exceeds 80%"
resolved_text: "[{{ $labels.env }}] {{ $labels.instance }} I/O usage falls"
その他
ちなみに、Node ExporterではCPUエラーやメモリエラーは取れない。