概要
cgroups (control groups)は、プロセスグループのリソース(CPU、メモリ、ディスクI/O、ネットワークなど)を制限、考慮、分離するLinuxカーネル機能です。
これを使ってプロセスのリソース制限を行ってみます。
環境
- Ubuntu 18.04.3
cgroupsの構成
cgroupsの構成は以下のようになっています。
ref: 1.2. サブシステム、階層、コントロールグループ、タスクの関係 Red Hat Enterprise Linux 6 | Red Hat Customer Portal
特徴は以下です。
- 階層(hierarchy)には、単一または複数のサブシステム(cpu, memory, net_cls)を接続できる
- ただし単一のサブシステム (例: cpu) を複数の階層に接続することはできない
- 階層は複数のコントロールグループを持つことができる
- コントロールグループはタスクを実行できる
- タスクはプロセスに紐づく
- 同一階層内の複数のタスクが同一のプロセスには紐付かない
- 別階層のタスクを同一プロセスに紐付けることは可能
サブシステム
サブシステムとは、CPU 時間やメモリーなどの単一のリソースを指します。
Linuxでは以下のサブシステムがあります。
サブシステム | 説明 |
---|---|
blkio | 物理ドライブ (例: ディスク、ソリッドステート、USB) などのブロックデバイスの入出力アクセスの制限を設定 |
cpu | スケジューラーを使用して cgroup タスクに CPU へのアクセスを提供 |
cpuacct | cgroup 内のタスクで使用される CPU リソースについての自動レポートを生成 |
cpuset | 個別の CPU (マルチコアシステム上) およびメモリーノードを cgroup 内のタスクに割り当てる |
devices | cgroup 内のタスクによるデバイスへのアクセスを許可または拒否する |
freezer | cgroup 内のタスクを一時停止または再開する |
memory | cgroup 内のタスクによって使用されるメモリーに対する制限を設定する。 それらのタスクによって使用されるメモリーリソースについての自動レポートを生成する |
net_cls | ネットワークパケットへのタグ付けを行う |
net_prio | ネットワークトラフィックの優先度を動的に設定 |
ns | namespace |
cgroupを使ってみる
では実際にcgroupを使ってリソース制限をしてみます。
インストール
Ubuntuではcgroup-tools
をインストールします。
$ sudo apt install cgroup-tools
設定
cgcreate
を使って設定する方法もありますが、今回はcgconfig.conf
を使います。
/etc/cgconfig.conf
に以下の設定を書きます。
group group1 { cpu { cpu.cfs_quota_us = 20000; cpu.cfs_period_us = 100000; } memory { memory.limit_in_bytes = 1G; } }
ここではCPUのリソース制限に
を指定しています。
パラメータ | 説明 |
---|---|
cfs_quota_us | cgroup内のタスクに与えられるCPU時間(µs)。 使い切るとスロットリングされ、次の期間まで実行を許可されなくなる。 |
cfs_period_us | cgroup による CPU リソースへのアクセスを再割り当てする一定間隔(µs) |
cfs_quota_us
は1CPU辺り最大cfs_period_us
まで与えられます。つまりマルチコアの場合はそのn倍になります。
例)2コアならcfs_period_us
=100,000の場合、cfs_quota_us
は200,000まで与えられる
スケジューラの動き
CPU時間を与える、という間隔が掴みにくい場合は以下の図を見ると分かりやすいです。
ref: うさぎでもわかる計算機システム(基本情報対応) Part18 プロセスの3状態・スケジューリングアルゴリズム - 工業大学生ももやまのうさぎ塾
CFS(Completely Fair Scheduler)は赤黒木を使ったもっと複雑なアルゴリズムですが、このようにタスクに対して一定時間CPUを利用させます。
時間内に完了すればそれで終わりますし、そうでなければプリエンプションが発生します。
設定の反映
$ sudo cgconfigparser -l /etc/cgconfig.conf
動作検証(cgexec)
2コアのVM上で検証します。
cgexec
を使うことでcgroupを指定してプロセスを実行できます。
$ sudo cgexec -g cpu:group1 stress -c 2
dstat
2コアなのでcfs_period_us
=100,000の場合cfs_quota_us
は200,000まで与えられますが、今回は設定で20,000までしか与えていないのでCPU使用率が10%になっていますね。
systemd-cgtop
$ systemd-cgtop
ではcgroup毎のtopが表示できます。
先ほどのdstatはCPU数でノーマライズされていましたが、こちらはCPU数x100%が最大となります。
システムの利用状況
スロットリング時間など、cAdvisorなどで見れる値は/sys/fs/cgroup/
を見ると確認できます。
$ ls /sys/fs/cgroup/ blkio cpu,cpuacct cpuset freezer memory net_cls,net_prio perf_event rdma unified cpu cpuacct devices hugetlb net_cls net_prio pids systemd
例えばnr_throttled
などはcpu.stat
で確認できます。
$ cat /sys/fs/cgroup/cpu/cpu.stat nr_periods 0 nr_throttled 0 throttled_time 0
まとめ
cgroupsを使ってリソース制限をしてみました。
DockerはnamespaceやcgroupsといったLinuxカーネルの機能を使いやすくしたものなので、元となる機能を理解することでDockerの各パラメータがどう作用するのかが理解できるようになりますね。