この記事は、Mackerel アドベントカレンダー(全部CRE)の19日目の記事です。いよいよ終わりが見えてきた......!
Mackerelを使ってサーバーの監視をする場合、通常、監視対象となるサーバーにmackerel-agentという、Mackerel公式のエージェントソフトウェアをインストールします。
このエージェントを、例えば Linux 系OSにインストールした場合、自動的に以下のような項目の監視・モニタリングがスタートします。
- connectivity(死活監視)
- ロードアベレージ
- CPU使用率
- Memory使用量
- disk IOPS
- ネットワークインターフェイス毎の転送量
- filesystem毎の使用量
これらの項目の見方や考え方、といったところについては、以前僕がこのブログで書いた以下の記事などを入門編として活用していただけたら、と思うのですが、
今回この記事では、それぞれの項目がどこからどうやって取得されているか、についてまとめておきたいと思います。
前提とするバージョン
まずそもそもなんですが、上記のようなシステムメトリック項目の取得、mackerel-agentのコード内で実施しているのか、というと現在一部のメトリックはそうではなく、github.com/mackerelio/go-osstatというパッケージに外出しされています。
この記事を書いている今日現在の mackerelio/go-osstat の最新のコミットハッシュは b878220なので、これを前提とします。また、エージェントのバージョンは v0.58.2です。
ロードアベレージ
まずはロードアベレージ。これの取得処理に該当するコードは以下ですね。
go-osstat/loadavg_unix.go at master · mackerelio/go-osstat · GitHub
C.getloadavg
なるほど強い。 getloadavg
のコードを見てみましょう。
glibc/getloadavg.c at master · lattera/glibc · GitHub
なるほど、 /proc/loadavg
の内容をパースしてるみたいですね。/proc/loadavg
の内容は通常どんな感じなのかというとー。
$ cat /proc/loadavg 0.00 0.01 0.05 1/172 7776
この出力例でいくと 0.00
が1分平均、 0.01
が5分平均、 0.05
が15分平均、ですね。mackerel-agentでは、以前は5分平均値のみをサポートしていたのですが、今年9月のリリースで3つ全ての値の取得に対応しています。
CPU使用率
CPU使用率の取得処理に該当する、mackerelio/go-osstat のコードは以下。
go-osstat/cpu_linux.go at master · mackerelio/go-osstat · GitHub
/proc/stat
の中身をパースしてますね。
$ cat /proc/stat cpu 4539975 441 2810320 1946960026 8001 0 14328 960087 0 0 cpu0 2367260 210 1504679 973311005 4287 0 6794 541875 0 0 cpu1 2172715 231 1305641 973649020 3714 0 7533 418211 0 0 intr 7155580662 128 11 0 0 1239 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1903425 2897468 9810434 23688814 20700610 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ctxt 9700818896 btime 1535208165 processes 25990813 procs_running 1 procs_blocked 0 softirq 920913114 0 407577803 2010127 53910949 0 0 759654 327731574 0 128923007
cpu
というところにある、スペースで区切られた10個の数値は、それぞれ以下。
- User
- Nice
- System
- Idle
- Iowait
- Irq
- Softirq
- Steal
- Guest
- GuestNice
また Total の値はこれらの値の合計値から Guest
と GuestNice
を差っ引いたものになっています。理由についてもちゃんとコメントが書かれていて( https://github.com/mackerelio/go-osstat/blob/master/cpu/cpu_linux.go#L69-L70 )、GUESTのcputimeが重複して加算されていることによるもの、のようす。
mackerelio/go-osstat の仕事は /proc/stat
からの値の取得までで、取得できた値を使って実際のCPU使用率の計算をおこなうのは mackerel-agent のお仕事。該当コードはここ。やってることの概要としては、カウンターメトリックであるCPUカウンターの各値を前回(1分前)との差を取り、Totalの値を用いて割合を算出・その1分間でのそれぞれのCPU使用率とする、というかんじ。CPUコア数を乗じているのもここで、です。
Memory使用量
Memory使用状況の取得処理に該当する、mackerelio/go-osstat のコードは以下。
go-osstat/memory_linux.go at master · mackerelio/go-osstat · GitHub
必要な情報は /proc/meminfo
から取得していることがわかります。 free
コマンドの結果とかじゃないですよ。
$ cat /proc/meminfo MemTotal: 476788 kB MemFree: 90232 kB MemAvailable: 227632 kB Buffers: 0 kB Cached: 147940 kB SwapCached: 1096 kB ...(中略)
結構素直な出力結果。ここから拝借した値をMackerelで表示している形になります。
Mackerelで取得しているのは以下のような項目ですが、
- MemTotal
- MemFree
- MemAvailable
- Buffers
- Cached
- Active
- Inactive
- SwapCached
- SwapTotal
- SwapFree
この中で気をつける点があるとすれば、SwapUsed
と Used
、そして MemAvailable
まわりかな?
SwapUsed
については、SwapTotal
から SwapFree
を差っ引いた値をそれとして扱っている、というだけ。そして Used
については、そのホストが MemAvailable
に対応しているかどうかで以下のように分岐します。
MemAvailable
に対応しているMemTotal
からMemAvailable
を差っ引いた値
MemAvailable
に対応していないMemTotal
からMemFree
、Buffers
、Cached
の値を差っ引いた値
MemAvailable
については、しばらく Mackerel でも対応できていない時期があったのですが、今年、エージェントのアップデートにより対応されました。
disk IOPS
コードはこちら!
/proc/diskstats
を読んでいます。
$ cat /proc/diskstats 259 0 nvme0n1 51278 461 3161371 42607 4439999 416208 70871825 3213412 0 690477 3256068 259 1 nvme0n1p1 51192 461 3157227 42580 4435002 416208 70871817 3213281 0 690344 3255607
スペースで区切られた各フィールドの値は https://www.kernel.org/doc/Documentation/iostats.txt このとおりで、概要 - Mackerel ヘルプ にも記載しているとおり、カーネルバージョン2.6以降のフォーマットを前提としているかんじ。
たくさんある項目のうち、disk IOPS の計算に使っているのは reads completed
と writes completed
の値。いずれもカウンターメトリックのため、前回値と今回値の差分を取ってメトリック取得間隔(60秒)で割り、その1分間における秒あたりの read / write それぞれのIOPS値を計算、disk.デバイス名.reads.delta
disk.デバイス名.writes.delta
というシステムメトリックとして扱っています。
ネットワークインターフェイス毎の転送量
この値の取得に関わるコードは以下。
go-osstat/network_linux.go at master · mackerelio/go-osstat · GitHub
/proc/net/dev
を読んでいますね。
$ cat /proc/net/dev Inter-| Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed ens5: 7849794393 24296257 0 0 0 0 0 0 7937298204 24463307 0 0 0 0 0 0 lo: 3502578773 9789245 0 0 0 0 0 0 3502578773 9789245 0 0 0 0 0 0
出力フォーマット、頑張ってる。
上記のコードでは、ローカルループバックインターフェイスは除外した上で、ネットワークデバイスごとに Receive bytes
と Transmit bytes
の値を抽出しています。差分の計算については disk IOPS と同様で、それを実施しているのも mackerel-agent サイド( https://github.com/mackerelio/mackerel-agent/blob/d9e3082a32b96c17560a375e5e78babcb0f34e8d/metrics/interface.go )です。つまり、MackerelのWebコンソールで確認できる値は bytes/sec ですね。
filesystem毎の使用量
システムメトリックではこれが最後!コードは以下!
これまでの疑似ファイルからの抽出ではなく、コマンド df -Pkl
(もしくは df -k
)の実行結果からパースしていますね!
$ df -Pkl Filesystem 1024-blocks Used Available Capacity Mounted on /dev/nvme0n1p1 10474240 3750956 6723284 36% / devtmpfs 215804 0 215804 0% /dev tmpfs 238392 0 238392 0% /dev/shm tmpfs 238392 29112 209280 13% /run tmpfs 238392 0 238392 0% /sys/fs/cgroup tmpfs 47680 0 47680 0% /run/user/1001
/dev/mapper/docker-
や /dev/dm-
ではじまるデバイス名のものなどを読み飛ばしたのち、 /dev/
で始まる名前のファイルシステムを対象としています。Mackerelのグラフで表示させる size
used
の値の計算はエージェント側( mackerel-agent/filesystem.go at d9e3082a32b96c17560a375e5e78babcb0f34e8d · mackerelio/mackerel-agent · GitHub )で実施しており、used
はそのまんまですが、size
は df コマンドの Used
と Available
の和を採用しています。
ちなみに、mackerel-agent は ignore = "/dev/ram.*"
や use_mountpoint = true
といったオプション指定をサポートしていて( https://mackerel.io/ja/docs/entry/spec/agent#config-file-filesystems )、その考慮をおこなっているのもエージェント側のコードになります。
ちなみに、connectivity(死活監視)は?
こちらについては、すでにFAQが存在していますので、こちらをご確認ください!
まとめ
以上、mackerel-agent が取得しているシステムメトリック(Linux系OSのみ)がどういうところから計算されているか?を紐解いてみました。ちょいちょい端折ってる部分もあるので、細かい部分はぜひコードを読んでみてくれ!!
今回のこの記事は、書いてる私にとっても一部なぁなぁにしてしまっていたところがあり、改めて勉強になりました。あと、結構フォーマットがバラバラでパースする側の気持ちになると大変だな、と。w
眠い目をこすりながら調べて書いたので、なんかコードを読み間違っちゃってるかも......? マサカリ、お待ちしております!!