Carpe Diem

備忘録

cgroupsでリソース制限

概要

cgroups (control groups)は、プロセスグループのリソース(CPU、メモリ、ディスクI/O、ネットワークなど)を制限、考慮、分離するLinuxカーネル機能です。

これを使ってプロセスのリソース制限を行ってみます。

環境

cgroupsの構成

cgroupsの構成は以下のようになっています。

f:id:quoll00:20200224175519p:plain

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_us1CPU辺り最大cfs_period_usまで与えられます。つまりマルチコアの場合はそのn倍になります。

例)2コアならcfs_period_us=100,000の場合、cfs_quota_usは200,000まで与えられる

スケジューラの動き

CPU時間を与える、という間隔が掴みにくい場合は以下の図を見ると分かりやすいです。

f:id:quoll00:20200224163841p:plain

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

f:id:quoll00:20200224165319p:plain

2コアなのでcfs_period_us=100,000の場合cfs_quota_usは200,000まで与えられますが、今回は設定で20,000までしか与えていないのでCPU使用率が10%になっていますね。

systemd-cgtop

$ systemd-cgtop

ではcgroup毎のtopが表示できます。

f:id:quoll00:20200224165733p:plain

先ほどの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の各パラメータがどう作用するのかが理解できるようになりますね。

ソース