cgroupを使ってCPUとメモリの割り当てを制限してみたけど、忘れてしまいそうなのでメモを残す。
試した環境はCentOS 6.4。
インストール
CentOS6でcgroupを使うにはlibcgroupをインストール。
$ sudo yum install libcgroup
cgconfigサービスを起動すると、/cgroup/ディレクトリが有効になる。自動で起動させるならchkconfigで設定。
$ sudo chkconfig cgconfig on $ sudo service cgconfig start
気にしそうなところ
- cpuやmemoryなど利用可能なサブシステムはOSによって異なる?
- cgconfigサービスで起動時にマウントされるサブシステムは/etc/cgconfig.confで設定
- cgredサービスを起動すると、ルールベースでプロセスをグループに自動で追加してくれる
- コマンド群で各種操作できる(lscgroup, cgcreate, cgdelete, cgexecなど)
- cgsnapshotコマンドは、現在のcgroupの状態をcgconfig.confの形式で標準出力
- 1グループごとのリソース制限の指定になるので、リソースを制限する単位でグループを作る
- プロセス毎に個別にリソース制限したい場合はグループたくさん作る?
- プロセスをフォークした場合、同じグループに所属する
- cgroupを指定してコマンドを実行するならcgexecを使う
- cgcreateは既に存在しているグループ名を指定してもエラーにならない(シェルスクリプトでチェック機構なしに毎回実行して大丈夫だった)
グループ作成
今回は、コマンドで作成する。cgconfig.confに設定を書いて有効にする方法もある。
my-groupという名前で作ってみる。サブシステムcpuとmemoryの制限を指定するのでこんな感じ。
$ sudo cgcreate -g cpu,memory:/my-group
作成できたかを確認するにはlscgroupで一覧を見る。
$ sudo lscgroup
作成できていれば、/cgroup/cpu/my-group/と/cgroup/memory/my-group/ディレクトリが作成されている。
$ ls /cgroup/cpu/my-group/ cgroup.event_control cgroup.procs cpu.cfs_period_us cpu.cfs_quota_us cpu.rt_period_us cpu.rt_runtime_us cpu.shares cpu.stat notify_on_release tasks $ ls /cgroup/memory/my-group/ cgroup.event_control memory.failcnt memory.limit_in_bytes memory.memsw.failcnt memory.memsw.max_usage_in_bytes memory.move_charge_at_immigrate memory.soft_limit_in_bytes memory.swappiness memory.use_hierarchy tasks cgroup.procs memory.force_empty memory.max_usage_in_bytes memory.memsw.limit_in_bytes memory.memsw.usage_in_bytes memory.oom_control memory.stat memory.usage_in_bytes notify_on_release
このディレクトリ内のファイルに値を書き込めば各種制限を変更できる。
CPUの割り当て制限
cpu.cfs_period_usとcpu.cfs_quota_usの値を調整する。
$ cat /cgroup/cpu/my-group/cpu.cfs_period_us 100000 $ cat /cgroup/cpu/my-group/cpu.cfs_quota_us -1
1コアの50%に制限するにはcpu.cfs_quota_usに50000と書き込む(cfs_period_usの半分)
$ sudo sh -c "echo 50000 > /cgroup/cpu/my-group/cpu.cfs_quota_us"
メモリの割り当て制限
memory.limit_in_bytes(ユーザーメモリの上限)とmemory.memsw.limit_in_bytes(ユーザーメモリ+スワップの上限)の値。
$ cat /cgroup/memory/my-group/memory.limit_in_bytes 9223372036854775807 $ cat /cgroup/memory/my-group/memory.memsw.limit_in_bytes 9223372036854775807
ユーザーメモリ(物理メモリ)を100MB、スワップを500MBに制限する。
$ sudo sh -c "echo 100M > /cgroup/memory/my-group/memory.limit_in_bytes" $ sudo sh -c "echo 500M > /cgroup/memory/my-group/memory.memsw.limit_in_bytes"
動作の検証
こういうリソースの割り当て制限の検証に便利なツールってあるのだろうか?知らない。
とりあえずスクリプトを作って動作させて、topコマンドやログを眺めるぐらいしかしてない。
CPUの割り当て制限の確認
無限ループでCPUを食いつぶすスクリプトを作る。
test_cpu.py
while True: pass
実行結果:
$ ps aux|grep py$ root 5631 0.0 0.1 173332 2628 pts/1 S+ 22:42 0:00 sudo cgexec -g cpu,memory:my-group python test_cpu.py root 5632 49.5 0.1 115044 3720 pts/1 R+ 22:42 1:00 python test_cpu.py
CPUの使用率が50%前後になった。
メモリの割り当て制限の確認
文字列を連結していってメモリを使い切るようなスクリプトを作る。
test_memory.py:
s = "0123456789" * 100000 while True: s += s
実行結果:
$ sudo cgexec -g cpu,memory:my-group python test_memory.py # 数秒後に終了する $ sudo less +G /var/log/messages Jun 19 22:45:50 localhost kernel: python invoked oom-killer: gfp_mask=0xd0, order=0, oom_adj=0, oom_score_adj=0 Jun 19 22:45:50 localhost kernel: python cpuset=/ mems_allowed=0 Jun 19 22:45:50 localhost kernel: Pid: 5671, comm: python Not tainted 2.6.32-358.el6.x86_64 #1 Jun 19 22:45:50 localhost kernel: Call Trace: Jun 19 22:45:50 localhost kernel: [<ffffffff810cb5d1>] ? cpuset_print_task_mems_allowed+0x91/0xb0 Jun 19 22:45:50 localhost kernel: [<ffffffff8111cd10>] ? dump_header+0x90/0x1b0 Jun 19 22:45:50 localhost kernel: [<ffffffff8121d0bc>] ? security_real_capable_noaudit+0x3c/0x70 Jun 19 22:45:50 localhost kernel: [<ffffffff8111d192>] ? oom_kill_process+0x82/0x2a0 Jun 19 22:45:50 localhost kernel: [<ffffffff8111d0d1>] ? select_bad_process+0xe1/0x120 Jun 19 22:45:50 localhost kernel: [<ffffffff8111d912>] ? mem_cgroup_out_of_memory+0x92/0xb0 Jun 19 22:45:50 localhost kernel: [<ffffffff81173454>] ? mem_cgroup_handle_oom+0x274/0x2a0 Jun 19 22:45:50 localhost kernel: [<ffffffff81170e90>] ? memcg_oom_wake_function+0x0/0xa0 Jun 19 22:45:50 localhost kernel: [<ffffffff81173a39>] ? __mem_cgroup_try_charge+0x5b9/0x5d0 Jun 19 22:45:50 localhost kernel: [<ffffffff81174b3d>] ? mem_cgroup_try_charge_swapin+0xbd/0xd0 Jun 19 22:45:50 localhost kernel: [<ffffffff811438ed>] ? handle_pte_fault+0x35d/0xb50 Jun 19 22:45:50 localhost kernel: [<ffffffff8104baa7>] ? pte_alloc_one+0x37/0x50 Jun 19 22:45:50 localhost kernel: [<ffffffff8114431a>] ? handle_mm_fault+0x23a/0x310 Jun 19 22:45:50 localhost kernel: [<ffffffff810474c9>] ? __do_page_fault+0x139/0x480 Jun 19 22:45:50 localhost kernel: [<ffffffff810097cc>] ? __switch_to+0x1ac/0x320 Jun 19 22:45:50 localhost kernel: [<ffffffff8150d6e0>] ? thread_return+0x4e/0x76e Jun 19 22:45:50 localhost kernel: [<ffffffff8151311e>] ? do_page_fault+0x3e/0xa0 Jun 19 22:45:50 localhost kernel: [<ffffffff815104d5>] ? page_fault+0x25/0x30 Jun 19 22:45:50 localhost kernel: Task in /my-group killed as a result of limit of /my-group Jun 19 22:45:50 localhost kernel: memory: usage 102324kB, limit 102400kB, failcnt 179657 Jun 19 22:45:50 localhost kernel: memory+swap: usage 512000kB, limit 512000kB, failcnt 27 ..(以下略)
cgroupの制限でkillされたログが出ている。