cgroupsでcpuリソースを管理する


今回はcgroupsでcpuリソースを管理する方法についてお話しします.まず,プロセスを制御するcpuの使用について述べる.1つのマシンで大量のリソースを消費する可能性のある複数のプログラムを実行する場合、あるプログラムがすべてのリソースを占めていることを望んでいません.他のプログラムが正常に動作しないか、システムの仮死をもたらしてメンテナンスできません.このときcgroupsではプロセスのリソース占有をうまく制御できます.ここではcpuリソースだけを言います.
cgroupsではcpuが使えます.cfs_period_usとcpu.cfs_quota_usは、このグループ内のすべてのプロセスが単位時間で使用できるcpu時間を制限します.ここのcfsは完全公平スケジューラの略である.cpu.cfs_period_usは時間周期であり、デフォルトは100000、すなわち100ミリ秒である.cpu.cfs_quota_usは、その間に使用可能なcpu時間であり、デフォルト-1、すなわち無制限である.
cpuを消費するプログラムを走る
# echo 'while True: pass'|python &
[1] 1532

トップで見ると、このプロセスは100%のcpuを占めています.
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 77569 root      20   0  112m 3684 1708 R 99.6  0.7   0:30.42 python
...

そしてこのプロセスを制限します.まず/fooという制御グループの制限を修正し、プロセスを追加します.
echo 50000 >/sys/fs/cgroup/cpu/foo/cpu.cfs_quota_us
echo 77569 >/sys/fs/group/cpu/foo/tasks

設定を変更するには、対応するファイルに書き込むだけで、プロセスをcgroupに追加するにはpidをtasksファイルに書き込むだけでよいことがわかります.ここでcpu.cfs_quota_usは、cpuに対して50000とする.cfs_period_usの100000は50%です.効果をもう一度トップで見てみましょう.
PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 77569 root      20   0  112m 3684 1708 R 50.2  0.7   5:00.31 python
...

プロセスのcpu占有率は50%に制限されることに成功したことがわかる.ここで、テストされた仮想マシンにはコアが1つしかありません.マルチコアの場合、表示される値は異なります.また、cfs_quota_usもcfsより大きくてもよいperiod_usの、これは主に多核の状況に対してです.n個のコアがある場合、1つの制御グループのプロセスは自然に最大n倍のcpu時間を使用することができる.
もう1組のcpu.rt_period_us、cpu.rt_runtime_usはリアルタイムプロセスの制限に対応しており,普段は使用する機会がない可能性がある.
cpuサブシステムでは、cpu.statは前述の方法で作った資源制限の統計です.nr_periods、nr_throttledは、合計で経過した周期と、その中で制限された周期です.throttled_timeは、制御グループによって絞められたcpuの使用時間です.
cpuもあります.sharesは、cpuの使用を制限するためにも使用されています.でもcpuとcfs_quota_us、cpu.cfs_period_usには大きな違いがある.cpu.sharesは,プロセスが使用できる絶対的なcpu時間を制限するのではなく,各グループ間の割当を制御する.たとえば
/cpu/cpu.shares : 1024
/cpu/foo/cpu.shares : 2048

では、両方のグループのプロセスがフル負荷で実行されると、/fooのプロセスが占有できるcpuは/のプロセスの2倍になります.もし/foo/barのcpuをもう一つ建てたら.sharesも1024であり、フル負荷で実行されるプロセスもあり、その/、/foo、/foo/barのcpu占有比は1:2:1である.前に言ったのはそれぞれ満席の場合です.他の制御グループのプロセスが空いている場合、あるグループのプロセスはすべてのcpuを満たすことができます.通常、この方法は公平を保証する場合に資源をより十分に利用できることがわかる.
さらに、プロセスがどのcpuコアを使用できるかを限定することもできます.cpusetサブシステムは、処理プロセスで使用できるcpuコアとメモリノード、およびその他の関連構成です.この部分の多くの構成はNUMAに関連している.ここでcpuset.cpus、cpuset.memsは、プロセスが使用できるcpuコアとメモリノードを制限するために使用されます.この2つのパラメータのcpuコア、メモリノードはidで表され、間は「,」で区切られています.例えば0,1,2.0~3などの範囲を「-」で表すこともできます.両者を組み合わせて使うことができる.「0-2,6,7」のように.プロセスを追加する前にcpuset.cpus、cpuset.memsは同時に設定し、互換性がある必要があります.そうしないとエラーが発生します.たとえば
# echo 0 >/sys/fs/cgroup/cpuset/foo/cpuset.cpus
# echo 0 >/sys/fs/cgroup/cpuset/foo/cpuset.mems

これにより、/fooのプロセスではcpu 0とメモリノード0しか使用できません.使用する
# cat /proc//status|grep '_allowed_list'

効果を検証できます.
cgroupsは、リソースの使用を制限するほか、リソース統計の機能もあります.クラウドコンピューティングの課金に使えます.cpuacctサブシステムは、cpuリソース統計に特化しています.cpuacct.statは、この制御グループ内のプロセスユーザ状態とカーネル状態のcpu使用量を統計し、単位はUSER_HZ,すなわちjiffies,cpu滴答数である.1秒当たりの滴下数はgetconf CLK_TCKで取得でき、通常は100である.見た値をこの値で割ると秒に換算できます.
cpuacct.アメリカとcpuacct.usage_percpuは、この制御グループでプロセスが消費するcpu時間であり、単位はナノ秒である.後者はcpuに分けて統計されている.