Process group별 Management를 제공하는 I/F이다.
Cgroup자체는 Process Grouping만을 수행하며,
Resource에 대한 관리는 Subsystem을 통해 이뤄진다.
Cgroup으로 만들어진 Process Group은 hierachy하게 만들어질 수 있다.
결과적으로 Cgroup을 통해 다음과 같은 기능을 제공한다.
sysfs나 procfs와 같이 low-level filesystem interface로 구현되며,
모든 cgroups 관련 action은 filesystem을 통해서 이뤄진다.
create/remove directory, read/write file, mount/umount
subsystem | version |
---|---|
cgroups | 2.6.24 |
net_prio | 3.3 |
net_cls | 3.3 |
blkio async I/O | 3.10 |
일반적으로 /sys/fs/cgroups에 cgroupfs가 mount된다. 여기서 생성되는 모든 entry는 reboot될때 지워진다. → persistent 하지 않다.
$ ls -l /sys/fs/cgroups
total 0
dr-xr-xr-x 2 root root 0 Jan 1 1970 bfqio
dr-xr-xr-x 4 root root 0 Jan 1 1970 blkio
lrwxrwxrwx 1 root root 11 Jan 1 1970 cpu -> cpu,cpuacct
dr-xr-xr-x 4 root root 0 Jan 1 1970 cpu,cpuacct
lrwxrwxrwx 1 root root 11 Jan 1 1970 cpuacct -> cpu,cpuacct
dr-xr-xr-x 3 root root 0 Jan 1 1970 cpuset
dr-xr-xr-x 4 root root 0 Jan 1 1970 devices
dr-xr-xr-x 3 root root 0 Jan 1 1970 freezer
lrwxrwxrwx 1 root root 16 Jan 1 1970 net_cls -> net_cls,net_prio
dr-xr-xr-x 2 root root 0 Jan 1 1970 net_cls,net_prio
lrwxrwxrwx 1 root root 16 Jan 1 1970 net_prio -> net_cls,net_prio
dr-xr-xr-x 2 root root 0 Jan 1 1970 perf_event
dr-xr-xr-x 4 root root 0 Jan 1 1970 systemd`
전체 cgroup에 대한 요약정보를 /proc에서 얻을 수 있다.
$ cat /proc/cgruops
#subsys_name hierarchy num_cgroups enabled
cpuset 7 3 1
cpu 4 41 1
cpuacct 4 41 1
blkio 5 41 1
memory 0 1 0
devices 3 41 1
freezer 9 3 1
net_cls 2 1 1
bfqio 8 1 1
perf_event 6 1 1
net_prio 2 1 1
현재 process와 관련, mount된 cgroup을 다음과 같이 알 수 있다.
$ cat /proc/self/cgroup
9:devices:/user.slice/user-0.slice/session-c3.scope
8:net_cls,net_prio:/
7:perf_event:/
6:cpuset:/
5:freezer:/
4:bfqio:/
3:blkio:/user.slice/user-0.slice/session-c3.scope
2:cpu,cpuacct:/user.slice/user-0.slice/session-c3.scope
1:name=systemd:/user.slice/user-0.slice/session-c3.scope
[root@pi boot]# cat /proc/$$/cgroup
9:devices:/user.slice/user-0.slice/session-c3.scope
8:net_cls,net_prio:/
7:perf_event:/
6:cpuset:/
5:freezer:/
4:bfqio:/
3:blkio:/user.slice/user-0.slice/session-c3.scope
2:cpu,cpuacct:/user.slice/user-0.slice/session-c3.scope
1:name=systemd:/user.slice/user-0.slice/session-c3.scope
cgroup tree에 관해선 아래와 같은 rule이 적용된다.
kernel 내 아래 path에 cgroup 관련 hook이 들어가 있다.
task_struct내에서 관련 filed를 찾을 수 있다.
struct task_struct : http://lxr.free-electrons.com/source/include/linux/sched.h?v=4.0#L1278
struct css_set __rcu *cgroups : http://lxr.free-electrons.com/source/include/linux/sched.h?v=4.0#L1570
struct css_set : http://lxr.free-electrons.com/source/include/linux/cgroup.h?v=4.0#L325
아래에서 list가 link된다.
struct list_head task : http://lxr.free-electrons.com/source/include/linux/cgroup.h?v=4.0#L343
지원하는 subsystem에 대해 기술되어 있다.
cgroup_subsys.h : http://lxr.free-electrons.com/source/include/linux/cgroup_subsys.h?v=4.0
Group별로 Subsystem을 통해 Group을 제어 할 수 있다.
상위 Group의 Subsystem 정책은 하위로 상속된다.
4.1 기준으로 현재 11개의 subsystem을 지원해주고 있다.
위는 다시 아래와 같이 구분해볼 수 있다.
subsystem은 각기 따로 사용할수도 있고 한번에 사용할 수도 있다.
$ mount -t cgroup -o cpu none /cpu
$ mount -t cgroup -o cpuset none /cpuset
$ mount -t cgroup none /cgroups
systemd를 사용하는 system에선 systemd 도구로 cgroup을 제어할 수 있다. 다음 명령은 system 상에 존재하는 cgroup과 subsystem 구조를 보여준다.
$ systemd-cgls
cgroup별 resource 사용 현황도 살필 수 있다.
$ systemd-cgtop
현재 process에 적용된 정책을 살펴보자
$ cat /sys/fs/cgroup/cpu/system.slice/smbd.service/cpu.shares
1024
$ systemctl set-property smbd.service CPUShares=200
$ systemctl show -p CPUShares smbd.service
CPUShares=200
$ cat /sys/fs/cgroup/cpu/system.slice/smbd.service/cpu.shares
200
$ ls /sys/fs/cgroup/cpu
cgroup.clone_children cpu.cfs_period_us cpu.rt_runtime_us cpuacct.stat notify_on_release tasks
cgroup.procs cpu.cfs_quota_us cpu.shares cpuacct.usage release_agent user.slice
cgroup.sane_behavior cpu.rt_period_us cpu.stat cpuacct.usage_percpu system.slice
주요 I/F는 아래와 같다.
I/F | Description |
---|---|
cpu.shares | CPU core의 점유율을 2~262114의 수치로 지정한다(default 1024). |
cpu.cfs_period_us | CPU 사용 시간 비율의 상한을 지정(default는 무제한) |
cpu.cfs_quota_us |
cpuset을 이용해 process별 core 사용에 대한 제한을 가한다.
$ ls /sys/fs/cgroup/cpuset
cgroup.clone_children cpuset.effective_cpus cpuset.memory_pressure cpuset.sched_load_balance
cgroup.procs cpuset.effective_mems cpuset.memory_pressure_enabled cpuset.sched_relax_domain_level
cgroup.sane_behavior cpuset.mem_exclusive cpuset.memory_spread_page notify_on_release
cpuset.cpu_exclusive cpuset.mem_hardwall cpuset.memory_spread_slab release_agent
cpuset.cpus cpuset.memory_migrate cpuset.mems tasks
주요 I/F는 아래와 같다.
I/F | Description |
---|---|
cpuset.cpus | process를 실행하는 CPU core 지정. |
cpuset.cpu_exclusive | 1로 set되면 이 group이 지정한 cpu cores는 다른 group에서 지정하지 못한다. |
cpuset.mems | NUMA architecture의 process가 이용하는 memory node를 지정. |
stress tool을 사용해서 비교 해본다.
$ unshare /bin/sh
$ pstree -p
systemd(1)-+-agetty(194)
|-agetty(195)
|-avahi-daemon(262)---avahi-daemon(263)
|-dbus-daemon(190)
|-docker(198)-+-{docker}(200)
| |-{docker}(201)
| |-{docker}(202)
| |-{docker}(204)
| `-{docker}(206)
|-haveged(193)
|-nmbd(207)
|-smbd(256)---smbd(260)
|-sshd(199)-+-sshd(266)---bash(273)
| `-sshd(285)---bash(287)---sh(332)---pstree(344)
|-systemd(269)---(sd-pam)(270)
|-systemd-journal(115)
|-systemd-logind(189)
|-systemd-resolve(197)
|-systemd-timesyn(182)---{sd-resolve}(184)
`-systemd-udevd(141)
$ stress -m 3 --vm-bytes 128m -t 60s
$ top
4개 core를 모두 100% 사용함을 확인할 수 있다. 이제 cgroup으로 제약을 가한다.
$ cd /sys/fs/cgroup/cpuset/
$ mkdir test/
$ cd test/
$ echo 0 > cpuset.cpus
$ echo 0 > cpuset.mems
$ echo 332 > tasks
같은 test를 반복한다.
$ stress -m 3 --vmbytes 128m -t 60s
$ top
0번 core만 사용됨을 알 수 있다.
process 별 memory 사용에 대한 제약을 가한다.
memory가 부족할 경우 적용할 사항을 oom_control을 통해 조정해 줄 수 있다.
$ ls /sys/fs/cgroup/memory
cgroup.clone_children memory.kmem.tcp.max_usage_in_bytes memory.pressure_level
cgroup.event_control memory.kmem.tcp.usage_in_bytes memory.soft_limit_in_bytes
cgroup.procs memory.kmem.usage_in_bytes memory.stat
cgroup.sane_behavior memory.limit_in_bytes memory.swappiness
memory.failcnt memory.max_usage_in_bytes memory.usage_in_bytes
memory.force_empty memory.memsw.failcnt memory.use_hierarchy
memory.kmem.failcnt memory.memsw.limit_in_bytes notify_on_release
memory.kmem.limit_in_bytes memory.memsw.max_usage_in_bytes release_agent
memory.kmem.max_usage_in_bytes memory.memsw.usage_in_bytes system.slice
memory.kmem.slabinfo memory.move_charge_at_immigrate tasks
memory.kmem.tcp.failcnt memory.numa_stat user.slice
memory.kmem.tcp.limit_in_bytes memory.oom_control
주요 I/F는 아래와 같다.
I/F | Description |
---|---|
memory.limit_in_bytes | 해당 group을 이용할 수 있는 물리 memory의 상한(byte)을 지정 |
memory.memsw.limit_in_bytes | 해당 group을 이용할 수 있는 ‘물리 memory + swap영역’의 상한(byte)을 지정 |
memory.use_hierachy | 1이 set되면 해당 group의 memory 사용량에 sub group의 process memory 사용량도 추가된다(default는 0). |
$ cd /sys/fs/cgroup/memory $ mkdir group1 $ echo 128M > group1/memory.limit_in_bytes $ echo $$ > group1/tasks $ stress --vm 1 --vm-bytes 127M --timeout 60s $ stress --vm 1 --vm-bytes 128M --timeout 60s $ echo 1 > group1/memory.oom_control $ echo 2G > group1/memory.limit_in_bytes $ stress --vm 1 --vm-bytes 512M --timeout 60s $ stress --vm 1 --vm-bytes 1G --timeout 60s $ echo 0 > group1/memory.oom_control $ stress --vm 1 --vm-bytes 512M --timeout 60s $ stress --vm 1 --vm-bytes 1G --timeout 60s
device file의 사용에 대한 제한을 가한다. 3가지 file이 있다. * devices.allow : whitelist * devices.deny : blacklist * devices.list : 사용가능한 device
각각에 대해서 4가지 filed가 있다.
/dev/null 의 경우 major는 1 minor는 3이다.
$ mkdir /sys/fs/cgroup/devices/0
$ cat /sys/fs/cgroup/devices/0/devices.list
a ":" rwm
$ echo "a *:* rmw" > /sys/fs/cgroup/devices/0/devices.deny
$ echo $$ > /sys/fs/cgroup/devices/0/tasks
$ echo "test > /dev/null
bash: /dev/null: Operation not permitted
$ echo "a *.* rwm" > /sys/fs/cgroup/devices/0/devices.allow
$ echo "test" > /dev/null
blkio
$ ls /sys/fs/cgroup
blkio.io_merged blkio.io_service_bytes_recursive blkio.io_wait_time blkio.sectors blkio.throttle.read_iops_device blkio.weight notify_on_release
blkio.io_merged_recursive blkio.io_service_time blkio.io_wait_time_recursive blkio.sectors_recursive blkio.throttle.write_bps_device blkio.weight_device release_agent
blkio.io_queued blkio.io_service_time_recursive blkio.leaf_weight blkio.throttle.io_service_bytes blkio.throttle.write_iops_device cgroup.clone_children system.slice
blkio.io_queued_recursive blkio.io_serviced blkio.leaf_weight_device blkio.throttle.io_serviced blkio.time cgroup.procs tasks
blkio.io_service_bytes blkio.io_serviced_recursive blkio.reset_stats blkio.throttle.read_bps_device blkio.time_recursive cgroup.sane_behavior user.slice
주요 I/F는 아래와 같다.
I/F | Description |
---|---|
blkio.weight | 모든 block device에 공통적인 우선순위를 100~1000의 값으로 지정(default는 500). |
blkio.weight_device | 특정 device에 대한 우선순위를 지정. |
blkio.throttle.read_bps_device | 특정 device에 대한 접근 속도의 상한을 Bytes/Sec 단위로 지정. |
blkio.throttle.write_bps_device | |
blkio.throttle.read_iops_device | 특정 dsevice에 대한 접근 속도의 상한을 IOPS 단위로 지정. |
blkio.throttle.write_iops_device |
https://www.linuxfoundation.jp/jp_uploads/seminar20081119/CgroupMemcgMaster.pdf
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Resource_Management_Guide/sec-memory.html