linuxのコントロールグループ(cgroup)でリソース制御 memo

今更だけど便利そうな機能なので勉強。

Red Hat Enterprise Linux 6 では、コントロールグループ と呼ばれる新たなカーネル機能を搭載しています。本ガイドでは、この機能を cgroup という略称で記載しています。cgroup により、ユーザーは、CPU 時間、システムメモリー、ネットワーク帯域幅などのリソースやそれらのリソースの組み合わせを、システム上で実行中のユーザー定義タスクグループ (プロセス) の間で割り当てることができるようになります。

RHEL6系の場合

# yum install libcgroup
# service cgconfig start

関連するファイル

  • /etc/init.d/cgconfig
  • /etc/cgconfig.conf
  • /etc/init.d/cgred
  • /etc/cgrules.conf

cgconfig を起動すると/cgroup 以下にcgroup file systemがマウントされる。

# ls -1d /cgroup/*
/cgroup/blkio
/cgroup/cpu
/cgroup/cpuacct
/cgroup/cpuset
/cgroup/devices
/cgroup/freezer
/cgroup/memory
/cgroup/net_cls
# cat /proc/mounts
(snip)
cgroup /cgroup/cpuset cgroup rw,relatime,cpuset 0 0
cgroup /cgroup/cpu cgroup rw,relatime,cpu 0 0
cgroup /cgroup/cpuacct cgroup rw,relatime,cpuacct 0 0
cgroup /cgroup/memory cgroup rw,relatime,memory 0 0
cgroup /cgroup/devices cgroup rw,relatime,devices 0 0
cgroup /cgroup/freezer cgroup rw,relatime,freezer 0 0
cgroup /cgroup/net_cls cgroup rw,relatime,net_cls 0 0
cgroup /cgroup/blkio cgroup rw,relatime,blkio 0 0
# cat /proc/cgroups 
#subsys_name	hierarchy	num_cgroups	enabled
cpuset	1	1	1
ns	0	1	1
cpu	2	1	1
cpuacct	3	1	1
memory	4	1	1
devices	5	1	1
freezer	6	1	1
net_cls	7	1	1
blkio	8	1	1
perf_event	0	1	1
net_prio	0	1	1
  • コマンド
    • cgcreate, cgdelete, cgset, cgclassify, cgexec, lscgroup, cgset, cgget, cgget -g cpuset / など
  • プロセスの確認
    • ps の -o cgroup の項目
    • cat /proc/pid/cgroup

実験

# コントローラによっては必須パラメータを指定しておかないと、コントローラへのプロセスの割り当てが失敗するので注意。例えばcpuset ではcpuset.cpusとcpuset.mems が必須。

4コアのcpuのマシンで、hoge ユーザのプロセスを0にのみ割り当てる
  • コントロールグループ名をtestで作成
  • 設定できる値は自分のH/W情報を確認するか親コントローラの設定
  • /cgroup/cpuset 以下のファイルの中身 を見て確認
# cgcreate cpuset:/test
### /cgroup/cpuset/test 以下が作成される
# cgset -r cpuset.cpus=0 test
# cgset -r cpuset.mems=0
### or echoで書き込み
補足

hoge ユーザ自身にcpuset のリソース制限の内容許可を与える場合は-a でユーザ、グループを指定。
これで/cgroup/cpuset/test のオーナがhoge:hoge になって自分で変更できるようになる。(tasks以外?)

cgcreate -a hoge:hoge cpuset:/test

コントローラグループへのプロセスの移動

↑で設定したcpuset を適用する例

手動 で行う

1. cgclassify を使う

#### hoge ユーザ何か実行
$ perl -e '1 while 1'
#### pid 調べる
# pgrep -fl perl
27136 perl -e 1 while 1
# cgclassify -g cpuset:hoge 27136
# date
2012年  4月 15日 日曜日 14:52:35 JST

2. echo でpidをtasksに書き込む
redhatの例でもechoのリダイレクトが追記(>>)じゃなくて書き込み(>)になっているけど、既存のpid情報は消えるわけじゃなくて、実際には追記されるだけなので大丈夫。(通常のファイルじゃなくて cgroupファイルシステムの擬似ファイルだから?)

# echo 27136 > /cgroup/cpuset/test/tasks
  • cgclassify 前後のsar -P ALL の結果

ループを回していたperlのプロセスがcpu3番からcpu0番に移動したのがわかる。

14時52分33秒     CPU     %user     %nice   %system   %iowait    %steal     %idle
14時52分34秒     all      0.00     25.00      0.50      0.25      0.00     74.26
14時52分34秒       0      0.00      0.00      0.99      0.00      0.00     99.01
14時52分34秒       1      0.00      0.00      0.00      0.00      0.00    100.00
14時52分34秒       2      0.00      0.00      1.94      0.97      0.00     97.09
14時52分34秒       3      0.00    100.00      0.00      0.00      0.00      0.00

14時52分34秒     CPU     %user     %nice   %system   %iowait    %steal     %idle
14時52分35秒     all      0.00     27.94      1.31      2.35      0.00     68.41
14時52分35秒       0      0.00     27.45      0.98      6.86      0.00     64.71
14時52分35秒       1      0.00      2.94      0.98      0.00      0.00     96.08
14時52分35秒       2      0.00      1.94      2.91      1.94      0.00     93.20
14時52分35秒       3      0.00     97.37      0.00      0.00      0.00      2.63

14時52分35秒     CPU     %user     %nice   %system   %iowait    %steal     %idle
14時52分36秒     all      0.00     23.64      0.71      0.00      0.00     75.65
14時52分36秒       0      0.00    100.00      0.00      0.00      0.00      0.00
14時52分36秒       1      0.00      0.00      0.00      0.00      0.00    100.00
14時52分36秒       2      0.00      0.00      1.96      0.00      0.00     98.04
14時52分36秒       3      0.00      0.00      0.00      0.00      0.00    100.00

14時52分36秒     CPU     %user     %nice   %system   %iowait    %steal     %idle
14時52分37秒     all      0.00     25.97      1.04      0.52      0.00     72.47
14時52分37秒       0      0.00    100.00      0.00      0.00      0.00      0.00
14時52分37秒       1      0.00      1.10      5.49      0.00      0.00     93.41
14時52分37秒       2      0.00      0.00      1.00      1.00      0.00     98.00
14時52分37秒       3      0.00      0.00      0.00      0.00      0.00    100.00
自動で行う

後述のcgred (/etc/cgrules.conf) で。

/etc/cgconfig.conf でコントローラの作成

cgcreate で作ったものはOS再起動 (/etc/init.d/cgconfig restart) で消えてしまうので、永続的に設定するなら/etc/cgconfig.conf を作成。

mount {
        cpuset  = /cgroup/cpuset;
        cpu     = /cgroup/cpu;
        cpuacct = /cgroup/cpuacct;
        memory  = /cgroup/memory;
        devices = /cgroup/devices;
        freezer = /cgroup/freezer;
        net_cls = /cgroup/net_cls;
        blkio   = /cgroup/blkio;
}

group test {
    perm {
        task {
            uid = root;
            gid = root;
        } admin {
            uid = root;
            gid = root;
        }
    } cpuset {
        cpuset.cpus = 0;
        cpuset.mems = 0;
    }
}

設定したら/etc/init.d/cgconfig restart。

cgredデーモンで自動的にプロセスをコントローラに移動

いちいちcgclassify コマンドをプロセスごとに実行なんてやってられないので、実際に使う場合はこの方法かな。/etc/cgrules.conf に設定して、cgred を起動しておく。/etc/security/limits.conf likeな感じ。
ユーザ、グループ、実行するプロセスごとに割り当てるコントローラの種類、コントローラグループを指定できる。

#<user>                 <controllers>           <destination>
#<user>:<process name>  <controllers>           <destination>
#
#john          cpu              usergroup/faculty/john/
#john:cp       cpu              usergroup/faculty/john/cp
#@student      cpu,memory       usergroup/student/
#peter         cpu              test1/
#%             memory           test2/
#@root          *               admingroup/
#*              *               default/
さっきの例で作ったcpusetのコントローラグループtestにhoge ユーザの全プロセスを割り当てる例
hoge    cpuset   test/

これを書いておいて

# service cgred start

こうすると、hoge ユーザが実行する全プロセスはcpu0番しか使わなくなる。

cgclassify (or echo) , cgred がエラーになる場合

cpusetで必須のcpuset.cpus, cpuset,mems を指定しない状態で、cgclassify やcgredデーモンを動かしてもエラーになる。

# cgclassify -g cpuset:test 27742
Error changing group of pid 27742: No space left on device

cgredの場合は/var/log/messages にエラーが出る。

CGRE[27965]: Cgroup change for PID: 27969, UID: 503, GID: 503, PROCNAME: /usr/bin/perl FAILED! (Error Code: 50016)