Fair Group Scheduling とは
Fair Group Scheduling は Cgroup によるリソース管理の 1 つで、これによりプロセスグループごとに CPU 割り当て時間の制御を行うことが可能となる。
なお、Fair Group Scheduling は Linux カーネル 2.6.23 以降で導入された CFS (Completely Fair Scheduling) による機能を利用しているため、CFS が未実装のカーネルでは利用不可となる。
Fair Group Scheduling の使用方法
まず Fair Group Scheduling を利用するには cgroup ファイルシステムのマウントが必要となる。
$ sudo mount -t cgroup -o cpu cgroup /cgroup/
今回は、CPU リソースを制御するグループを 2 つ (GroupA 及び GroupB) 作ることにする。なお、簡単のため CPU コアは 1 つのものを使用する。
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 1
On-line CPU(s) list: 0
Thread(s) per core: 1
Core(s) per socket: 1
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 63
Model name: Intel(R) Xeon(R) CPU E5-2676 v3 @ 2.40GHz
Stepping: 2
CPU MHz: 2399.870
BogoMIPS: 4800.04
Hypervisor vendor: Xen
Virtualization type: full
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 30720K
NUMA node0 CPU(s): 0
$ sudo mkdir /cgroup/GroupA
$ sudo mkdir /cgroup/GroupB
上記 2 つのグループにプロセスを割り振ることにより、それぞれのグループ間で CPU 時間を公平にシェアする。
まずはシェルプロセスを GroupA に割り当て、そのシェルで CPU を 100% 使用するようにする。
$ sudo sh -c "echo $$ > /cgroup/GroupA/tasks"
$ yes > /dev/null
同様の操作を GroupB にも施す。
$ sudo sh -c "echo $$ > /cgroup/GroupB/tasks"
$ yes > /dev/null
ここで、top コマンドで確認すると、50% ずつ CPU 時間が割り当てられていることがわかる。
top - 09:35:24 up 1 min, 3 users, load average: 0.96, 0.27, 0.09
Tasks: 85 total, 3 running, 56 sleeping, 0 stopped, 0 zombie
Cpu(s): 48.5%us, 4.3%sy, 0.0%ni, 38.2%id, 2.1%wa, 0.0%hi, 0.2%si, 6.6%st
Mem: 1009432k total, 486820k used, 522612k free, 18004k buffers
Swap: 0k total, 0k used, 0k free, 377180k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3000 ec2-user 20 0 105m 1728 1632 R 49.8 0.2 0:33.57 yes
3005 ec2-user 20 0 105m 1744 1648 R 49.8 0.2 0:12.76 yes
次に、シェルを追加で 2 つ起動し、どちらも GroupB に所属させ、同様に CPU を 100% 使うようにする。つまり、GroupA には 1 プロセス、GroupB には 3 プロセス、という状況を作る (シェル自身を除く) 。
$ cat /cgroup/GroupA/tasks
2917
3000
$ cat /cgroup/GroupB/tasks
2943
2969
3005
3013
3017
3069
ここで top の出力を見てみると、GroupA に所属している PID 3000 のプロセスは 50% の CPU リソースを使用できているのに対して、GroupB に所属する他のプロセスは 50 % を約 3 等分する形でしか CPU リソースを使用できていないことがわかる。
top - 09:42:30 up 8 min, 5 users, load average: 3.87, 2.48, 1.16
Tasks: 91 total, 5 running, 62 sleeping, 0 stopped, 0 zombie
Cpu(s): 88.2%us, 1.5%sy, 0.0%ni, 8.2%id, 0.5%wa, 0.0%hi, 0.1%si, 1.5%st
Mem: 1009432k total, 492684k used, 516748k free, 18132k buffers
Swap: 0k total, 0k used, 0k free, 377248k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3000 ec2-user 20 0 105m 1728 1632 R 49.8 0.2 4:06.31 yes
3005 ec2-user 20 0 105m 1744 1648 R 17.9 0.2 2:39.55 yes
3013 ec2-user 20 0 105m 1656 1560 R 15.9 0.2 0:43.41 yes
3069 ec2-user 20 0 105m 1664 1568 R 15.9 0.2 0:22.54 yes
cpu.shares
cpu.shares 特殊ファイルは cpu サブシステムにより提供され、プロセススケジューラで扱うプロセス群に対して割り当てる CPU 時間の重みを設定することができる。
$ ls -l /cgroup/GroupA/ | grep cpu.shares
-rw-r--r-- 1 root root 0 Jan 14 09:48 cpu.shares
$ cat /cgroup/GroupA/cpu.shares
1024
ここで、GroupB の cpu.shares を GroupA の半分である 512 に設定する。
$ sudo bash -c "echo 512 > /cgroup/GroupB/cpu.shares"
これにより、GroupA の重みは 1024 、GroupB の重みは 512 となり、GroupA には GroupB の 2 倍の CPU 時間が割り当てられることになる。実際に top コマンドの出力を見てみるとこの設定が反映されていることがわかる。
top - 09:51:00 up 17 min, 5 users, load average: 4.00, 3.74, 2.38
Tasks: 91 total, 5 running, 62 sleeping, 0 stopped, 0 zombie
Cpu(s): 93.5%us, 1.2%sy, 0.0%ni, 4.2%id, 0.2%wa, 0.0%hi, 0.0%si, 0.8%st
Mem: 1009432k total, 492932k used, 516500k free, 18228k buffers
Swap: 0k total, 0k used, 0k free, 377252k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3000 ec2-user 20 0 105m 1728 1632 R 67.7 0.2 8:32.45 yes
3013 ec2-user 20 0 105m 1656 1560 R 11.9 0.2 2:04.72 yes
3069 ec2-user 20 0 105m 1664 1568 R 11.9 0.2 1:43.86 yes
3005 ec2-user 20 0 105m 1744 1648 R 10.0 0.2 4:00.86 yes