Hateburo: kazeburo hatenablog

SRE / 運用系小姑 / Goを書くPerl Monger

mackerel plugin で瞬間的な負荷を捉える mackerel-plugin-maxcpu

とあるAPIに対するアクセスが、

   回数  時間
   1833 time:27/Oct/2020:21:32:25
   1657 time:27/Oct/2020:21:32:26
   1616 time:27/Oct/2020:21:32:27
   2584 time:27/Oct/2020:21:32:28
  14958 time:27/Oct/2020:21:32:29
   6619 time:27/Oct/2020:21:32:30
   1725 time:27/Oct/2020:21:32:31
   1796 time:27/Oct/2020:21:32:32
   1713 time:27/Oct/2020:21:32:33
   1932 time:27/Oct/2020:21:32:34
   1797 time:27/Oct/2020:21:32:35
   1841 time:27/Oct/2020:21:32:36

という感じで、一瞬だけ急増し、1秒後にはほぼ戻るようなことがあり、この瞬間にCPUが尽きることで全体のレスポンスタイムに影響してしまうようなことがありました。

とりあえず台数を増やしてスケールアウトで対応してるわけですが、大元の原因の解決するまで、CPUの使用率が100%に近くなる瞬間がないか監視しておきたいということで、新しく mackerel plugin を作成しました。

github.com

CPU使用率の計算

Linuxの場合、よくあるツールではCPUの使用率を /proc/stat のファイルを読んで計測します。

$ cat /proc/stat |head
cpu  4102976 0 548407 3258934935 6723 0 115819 0 0 0
cpu0 115620 0 14370 81452406 84 0 2527 0 0 0
cpu1 123341 0 12898 81453921 748 0 2527 0 0 0
cpu2 109211 0 16473 81465621 82 0 2505 0 0 0
cpu3 109706 0 14273 81467250 216 0 2513 0 0 0

cpuの行の数値は、user, nice, system, idle, iowait, irq, softirq.. と各モードに入っていた時間(USER_HZ)、CPU使用率を出すツールは一定周期でこのファイルを確認し、それぞれの数値の増分を使ってCPU使用率を計算しています。

通常のmackerel pluginの場合、1分周期でpluginが実行されるため、1分間の平均CPU使用率しか計算ができません。1分のあいだの最大値は取得できません。そこで、maxcpuでは初回plugin実行時に、1秒毎にCPU使用率を計測するbackgroundプロセスを作成し、次の起動タイミングからはbackgroundプロセスに前回取得タイミングからのCPU使用率の最大・最小・平均・パーセンタイル値を取得しています。

f:id:kazeburo:20201109133143p:plain

backgroudプロセスとの通信はgRPC over UNIXドメインソケットで行ってますが、gRPC(http含む)ではバイナリサイズが大きくなってしまうので変更するべきかもしれません。

maxcpuの使い方

gRPC over UNIXドメインソケットに使う --socket だけ指定します。

[plugin.metrics.maxcpu]
command = "/usr/local/bin/mackerel-plugin-maxcpu --socket /var/run/maxcpu.sock"

maxcpuでは運用がしやすいように、バイナリが入れ替わった際にbackgroundプロセスは自動で再起動(新しいプロセスを作成し、自プロセスを停止)します。このためpluginのアップデート時に手動にて再起動する必要はありません。この機能を実現するため、SO_REUSEPORT を使っています。

また、一定時間gRPCの通信がないと停止して、余計なリソースを使い続けることはないようにしています。

作成されたグラフは以下のようになります。何回かCPUが跳ねているのがわかります。

f:id:kazeburo:20201109133335p:plain

ニッチなpluginですが、ニーズが合えばお使いください。