ruby で cgroupのeventfd通知機能利用して メモリ使用量や OOM Killer を監視する

Linux Containerでも使われている cgroup には 、メモリ使用量が閾値より高くなったか/低くなったか や OOM Killer が発生したかどうか といったイベントを eventfd を通じて受け取れるようになっています。この仕組みを ruby から扱う方法を調べてみました

なお 検証したカーネルは 3.2.16 です。SL6 2.6.32 のカーネルでは eventfdでの通知は 実装(マージ?)されていないようでした。

rubyで eventfd を使う

ruby で eventfd を扱う方法が分からなかったのですが sleepy_penguin という gem を使う事で解決できました

rackサーバーの Rainbows! の中でも使われている Gem です。

source :rubygems

gem "sleepy_penguin"

cgroup と eventfd

eventfd でイベントを受け取る方法は ↓ に書いてあります。ファイルデスクリプタの扱いがややこい感じです。

後半に ruby のサンプルを載せたのでそれ見た方が分かりやすいかも


OOM Killer を検知する

cgroup の memory.max_usage_in_bytes を設定しておくと、メモリの上限値を設定できます。 使用量が上限に達すると OOM Killer が起動します。

これを eventfd で検知することができます

#!/usr/bin/env ruby 

require 'sleepy_penguin'

efd         = SleepyPenguin::EventFD.new(0,0)
oom_control = File.open("/cgroup/namahage-ruby-0/memory.oom_control", "r")
message     = sprintf "%d %d", efd.fileno, oom_control.fileno 

event_control = File.open("/cgroup/namahage-ruby-0/cgroup.event_control", "w")
event_control.write(message)
event_control.close

while notify = efd.value
  printf "%s OOM killer!", notify
end

監視している cgroup で OOM Killer が発生すると efd.value が値を返します

メモリ使用量の閾値監視

閾値は バイト単位で指定できます。

#!/usr/bin/env ruby 

require 'sleepy_penguin'

efd            = SleepyPenguin::EventFD.new(0,0)
usage_in_bytes = File.open("/cgroup/sushi/memory.usage_in_bytes", "r")
message        = sprintf "%d %d 60000000", efd.fileno, usage_in_bytes.fileno 

event_control = File.open("/cgroup/sushi/cgroup.event_control", "w")
event_control.write(message)
event_control.close

while notify = efd.value
  printf "%d %d\n", notify, File.read("/cgroup/sushi/memory.usage_in_bytes")
end

メモリ使用量が 閾値より高くなったか or 閾値より低くなったら efd.value が値を返します。高くなったのか低くなったのか どっちなのかは自分で判断しないといけないぽい