mruby-cgroupとmod_mrubyでApacheのリソースを制御、そこから得られるcgroupの挙動とは

C言語で書かれた任意のホストプログラムにmrubyを組み込み、そのプロセスリソースを簡単かつ強力に制御するために、mruby-cgroupというmrbgemを作り、以前の記事で紹介しました。

もちろん、mruby-cgroupmod_mrubyに組み込むことで、ホストプログラムであるmod_mruby、さらにはApacheそのもののリソース制御が可能になり、Webサーバへのリクエスト単位でもリソース制御が可能になります。

しかし、軽量なリクエストに対して、無条件にリソース制御の機能を適応してしまうと、リソース制御を適応すること自体がボトルネックになる可能性が十分あります。また、それとは別に、cgroupの想定していない挙動が得られるかもしれません。それがどういうものなのかを評価してみました。

Webサーバのリクエストをリソース制御

まずは簡単にリソース制御を可能にする設定方法を説明します。mrubyにmrbgemであるmruby-cgroupを組み込んでビルドします。

mod_mrubyをcloneしてsubmoduleであるmrubyもcloneします。

[program lang=’bash’ escaped=’true’]

git://github.com/matsumoto-r/mod_mruby.git
cd mod_mruby
git submodule init
git submodule update
cd mruby

[/program]

build_config.rbに以下の設定を追記し、

[program lang=’ruby’ escaped=’true’]

conf.gem :git => 'git://github.com/matsumoto-r/mruby-cgroup.git'

[/program]

mrubyとmod_mrubyをビルドします。Fedora64bit環境などでは-fPICが必要です。

[program lang=’bash’ escaped=’true’]

cd mod_mruby
cd mruby
rake CFLAGS="-fPIC"
cd ..
./configure
make
make install

[/program]

そして、httpd.confに以下のように設定します。

[program lang=’apache’ escaped=’true’]

mrubyAccessCheckerMiddle /etc/httpd/hooks/cgroup_attach.rb
mrubyLogTransactionMiddle /etc/httpd/hooks/cgroup_detach.rb

[/program]

それぞれ、cgroup_attach.rbとcgroup_detach.rbは以下のように処理を記述します。

cgroup_attach.rb

[program lang=’ruby’ escaped=’true’]

r = Apache::Request.new

if r.filename == "/var/www/html/while.cgi"
  c = Cgroup::CPU.new("apache/mod_mruby_group")
  c.cfs_quota_us = 10000
  if c.exist?
    c.modify
  else
    c.create
  end
  c.attach
end

[/program]cgroup_detach.rb

[program lang=’ruby’ escaped=’true’]

r = Apache::Request.new

if r.filename == "/var/www/html/while.cgi"
  c = Cgroup::CPU.new("apache/mod_mruby_group")
  if c.exist?
    c.delete
  end
end

[/program]

このように書くことで、while.cgiにアクセスがあった場合は、そのプロセスをCPU10%に制限することができます。また、Apacheのプロセスはapache権限で動作しているので、事前にcgroup以下にapache権限でアクセスできるcgroupを作っておく必要があります。例えば/sys/fs/cgroup/cpu/apacheを作り、chmod -R apache.aparchで権限を変更しておきましょう。

実際にリソース制限できているか確認

では実際にCPUを100%食うようなwhile.cgiを適当に作って、適切にCPU制御できているかを確認しました。

while.cgi

[program lang=’bash’ escaped=’true’]

#!/bin/sh

while :; do true ; done

[/program]

このスクリプトにcurl等でアクセスします。そして、topコマンドにてCPU使用率を確認すると、

[program lang=’bash’ escaped=’true’]

  PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND
18504 apache    20   0 11548 1120  936 R   9.9  0.0   0:23.07 while.cgi

[/program]

きちんとCPU10%で制御できていますね。

cgroupへのattachによるパフォーマンスの影響について

では、it works!!を出力するような軽量な静的コンテンツindex.htmlに対して、cgroupに都度attachした場合、どのようにパフォーマンスに影響するかを評価しました。これによって、ある程度外から見たcgroupの挙動が理解できそうです。

cgroup_detach.rbのフックは除外し、cgroup_attach.rbのwhile.cgiのマッチ条件を無しにしました。これで、すべてのアクセスに対してCPU10%のcgroupにプロセスがattachされるはずです。しかし、index.htmlはCPUをそこまで使う処理ではないので、本来はリソースを制限することなくそのまま処理することが期待されます。

では、実際にindex.htmlに対して同時接続数100、総接続数10万でabで負荷をかけ、1秒間に処理できたリクエスト数を計測しました。以下がその結果になります。

cgroup_attach.rbをフックした場合(すべてのリクエストをCPU10%に制限)

  • 230req/sec

cgroup_attach.rbをフックした場合(while.cgiのみをCPU10%に制限、実質cgroupのattachは生じない)

  • 5000req/sec

このように、大きく性能に差がでました。cgroupにattachしない場合と比べて、cgroupにattachした場合は5%程度の性能に落ち込みました。

むむむ…?

5%…少し気になる数値ですね。

考察

ここからは、推測を前提に考察してみます。

index.htmlに対して5%程度しか性能がでなかった理由は、cgroupにattachするコストによる性能劣化なのでしょうか。CPUを10%も使わないような軽量な処理は、cgroupにattachする事自体がボトルネックとなり、そこで性能が劣化してしまうのでしょうか?

しかし、一方で次のように理解することもできます。このあたりはcgroupの実装をきちんと読めていないので、あくまで推測になります。

index.htmlはCPUを10%も使いませんが、abコマンドによる同時多発的に連続したリクエストを処理する際にも、cgroupはトータルでCPUコアの10%となるように処理をしているのでは?、ということです。

今回の検証環境は2コアですので、制限しない場合は単純に計算すると100% * 2コア分のCPU200%が使用できるとします。それが今回、「cgroup_attach.rbをフックした場合(while.cgiのみをCPU10%に制限、実質cgroupのattachは生じない)」に該当し、これが5000req/secです。

一方、「cgroup_attach.rbをフックした場合(すべてのリクエストをCPU10%に制限)」では、cpu.cfs_quota_usの設定値である10%が全体の10%を示していたとすると、5000req/secの200分の10で、250req/secになります。むむむ、上記の実験結果の値である230req/secにかなり近い値ですね。

このように、cgroupにattachしたプロセスの処理は、最終的にトータルでそのcgroupの設定値となるように実装されているのであれば、上記の値は正常であるといえますし、むしろcgroupは緻密でとても賢いことになります。

そうでなければ、単なるボトルネックとして、あまりうれしい結果ではありません。

最後に

もうちょっと他の比較実験を追加すれば明らかになるのでは?という突っ込みもありそうですが、今回はここまでにとどめておきます。今後は、その他の比較実験をしてみたり、予測の元cgroupのコードを読んでいくことになりそうです。もし、この記事を読んだだけで、理由を説明できそうな方がいればぜひとも記事にして頂けたらうれしいです。必ずはてブします!