virtualingとは、わりとセキュアでCPUやメモリ・IOといったリソースの制御が可能なプロセス実行環境上で、設定や構成を変える事なくミドルウェアのようなプロセスを動作させることができるツールです。実装はmrubyです。
リソース制御なので、例えばプロセスのメモリ使用量の上限を制限していた場合に、その制限を超えると従来通りOoM-Killerが走るわけですが、virtualingの特徴的な機能として、そのイベントを自動で検知し任意のRubyブロックをコールバックする機能があります。
それを利用して、今回はOoM-Killer判定が下されたイベントを検知したら、メモリ制限値を自動で拡張していくような処理を試してみました。
virtualingの設定
設定はRubyで書く事ができます。今回は、OoM-Killerを検知した時にOoM-Killerを走らせずに処理をブロックさせるような設定:oom => false
にした後、コールバック処理でメモリの制限値を自動拡張するようにします。
cgroup = "virtualing-group" mem = 512 * 1024 Virtualing.new({ #(snip) :resource => { #(snip) :oom => false, :mem => mem, }, #(snip) }).run_with_mem_eventfd_loop do puts "OOM KILLER!!! current memory: #{mem}" sleep 2 c = Virtualing::MEMORY.new group mem = mem * 2 c.limit_in_bytes = mem c.modify puts "current memory expand to #{mem}" end
設定の詳細はGitHubをみてもらうとして、必要な部分だけを上記に書きました。このrun_with_mem_eventfd_loop
メソッドによって、OoM-Killerのeventを検知するループに入り、検知したらブロックの処理を実行して再度eventループに入ります。
そして、このブロック内に予め設定していたメモリの上限値、上記例では512KiB
、をeventが通知されるタイミングで倍に自動拡張するという処理を実装しました。
では、これを実際に動かしてみましょう。すると、
$ sudo ./virtualing httpd.rb OOM KILLER!!! current memory: 524288 current memory expand to 1048576 OOM KILLER!!! current memory: 1048576 current memory expand to 2097152
このように、最初の設定値はすぐにOoM-Killerのイベントが発生し、そこでRubyブロックが呼ばれ自動拡張し、さらに倍々と処理をして、最終的に2MiBあたりで落ち着いたようです。イベントが通知されメモリが拡張されるまではブロックされ、拡張と同時にプロセスの処理が再開されるような動きをします。
またこの時に、Virtualing::MEMORY.usage_in_bytes
で使用量を取得すると大体1.5MiBあたりの値となっており、メモリの上限値とも合致します。
ふむふむ、うまく応用するといい感じの自動リソース制御アルゴリズムがRubyで簡単に実装できそうですね。
まとめ
ということで、virutalingのイベント検知機能を利用して、virtualingで実行されているプロセスのメモリ使用量制限を自動拡張してみました。
また、今回はOoMの検知で自動拡張しましたが、例えば、メモリの使用量の任意の値にさしかかったイベントを検知してブロックをコールバックすることも可能です。それらについては前回の記事を御覧ください。
ちなみにですが、今日ロリポのテスト環境にて、ロリポのApacheの設定やディレクトリ構成(それなりに複雑)を全く変える事なく、virtualing経由でchrootかつリソース制御が可能な実行環境上でロリポApacheを起動出来たことをお伝えしておきます。
つまりは、ある程度複雑な構成のミドルウェアであっても、virtualingによって、わりとセキュアでリソース制御可能なプロセス実行環境上で手軽にミドルウェアを動かせるだろうと予想できますので、是非お試し下さい。