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 が値を返します。高くなったのか低くなったのか どっちなのかは自分で判断しないといけないぽい