cgroup v2는 리눅스 커널에서 프로세스를 그룹화 하고, 각 그룹에 대해 리소스 할당/제한을 설정하는 기능을 제공한다. cgroup v1보다 간편하고 세밀한 제어를 지원한다. 계층적 구조를 지원하여 복잡한 리소스 관리를 더욱 효율적으로 수행할 수 있다.
Enable Cgroup v2
부트 커맨드로 cgroup_no_v1= 옵션을 전달해야 한다. 만약 memory 서브시스템을 사용한다고 하면, “cgroup_no_v1=memory“를 전달하면 된다. 그렇지 않고 모든 서브시스템을 사용하려면 “cgroup_no_v1=all” 을 전달하도록 설정한다.
cgroup 마운트/언마운트
cgroup v2를 사용하기 위해서는 cgroup2 마운트를 해야 한다. 마운트할 위치는 일반적으로 /sys/fs/cgroup 이다.
# mkdir /sys/fs/cgroup
# mount -t cgroup2 none /sys/fs/cgroup
cgroup v2 을 그만 사용할 경우 언마운트(umount) 해 준다.
# umount /sys/fs/cgroup
계층 생성 및 제어
계층 생성에 앞서 부트 커맨드라인에 cgroup_no_v1=으로 전달한 옵션으로 사용가능한 컨트롤러를 cgroup root의 cgroup.controllers를 읽어 확인한다.
# cat /sys/fs/cgroup/cgroup.controllers
cpuset cpu io memory hugetlb pids rdma
계층을 생성하기 위해서는 cgroup을 마운트한 root 디렉토리에서 새로운 디렉토리를 생성하면 된다.
# sudo mkdir /sys/fs/cgroup/my_cgroup
새로 생성한 그룹 안에서 cpu.max, memory.max 같은 컨트롤러 인터페이스 파일을 쓰려면, 그 컨트롤러를 상위(부모) cgroup의 cgroup.subtree_control 파일에 활성화해서 하위로 위임해야 한다. my_cgroup은 root의 자식이므로, root의 cgroup.subtree_control에 기록한다.
# echo "+cpu +memory" > /sys/fs/cgroup/cgroup.subtree_control
제어 하려는 PID를 cgroup.procs 에 입력하여 생성한 그룹에서 제어 받도록 설정한다.
# echo $YOUR_PID > /sys/fs/cgroup/my_cgroup/cgroup.procs
컨트롤러(Controllers)
각 컨트롤러는 cgroup 디렉토리 안에 인터페이스 파일(예: cpu.max, memory.max)을 만들며, 이 파일을 읽고 쓰는 것으로 리소스를 조회하고 제한한다. cgroup.controllers로 확인한 것처럼 cpuset, cpu, io, memory, hugetlb, pids, rdma 컨트롤러가 있으며, 아래에서는 가장 많이 쓰는 cpu, memory, io 컨트롤러를 다룬다.
CPU
사용되는 시간은 마이크로초(microseconds) 단위이다.
| Interface | Description |
| cpu.stat | cpu 사용 통계를 report |
| cpu.weight cpu.weight.nice | cpu.weight [1, 10000] 범위의 가중치 값을 갖고, 기본값은 “100” cpu.weight.nice [-20, 19] 범위의 nice값을 갖고 기본값은 “0” |
| cpu.max cpu.max.burst | cpu.max “$MAX $PERIOD” 형식으로 최대 대역폭을 지정, 기본값은 “max 100000″(제한 없음, 100ms 주기) cpu.max.burst [0, $MAX] 범위의 버스트 값이며, 기본값은 “0” |
| cpu.pressure | PSI (Pressure Stall Information) 지표 제공 (참고: https://docs.kernel.org/accounting/psi.html) |
| cpu.uclamp.max cpu.uclamp.min | cpu.uclamp.max 사용률 max 값을 설정하며, 기본값은 “max” cpu.uclamp.min 사용율 min 값을 설정하며, 기본값은 “0” |
Memory
| Interface | Description |
| memory.current | cgroup의 현재 메모리 사용량 |
| memory.high memory.max | memory.high 메모리 사용량의 soft limit, cgroup의 메모리 사용량이 soft limit을 초과하면 memory reclaim을 빈번히 수행 memory.max 메모리 사용량의 hard limit, cgroup의 메모리 사용량이 hard limit을 초과하면 oom killer를 호출하여 종료시킴 |
| memory.low memory.min | memory.low 메모리 사용량의 하한선, 시스템이 회수하지 않는 량 memory.min 유지해야 하는 메모리 최소량, 즉 시스템에서 회수할 수 없는 메모리량 지정 |
| memory.pressure | PSI (Pressure Stall Information) 지표 제공 (참고: https://docs.kernel.org/accounting/psi.html) |
| memory.events | low, high, max, oom에 대한 event 수 |
| memory.stat | cgroup의 메모리 사용량 통계 |
IO
블록 장치에 대한 읽기/쓰기 대역폭과 IOPS를 제어한다.
| Interface | Description |
| io.stat | 장치별 rbytes, wbytes, rios, wios 등 IO 사용 통계를 report |
| io.weight | [1, 10000] 범위의 가중치 값을 갖고, 기본값은 “100”. 여러 cgroup이 IO 대역폭을 경쟁할 때 상대적 우선순위를 결정 |
| io.max | 장치별 최대 대역폭(rbps, wbps)과 최대 IOPS(riops, wiops)를 제한. 예: 8:0 rbps=2097152 wbps=2097152 |
| io.pressure | PSI (Pressure Stall Information) 지표 제공 (참고: https://docs.kernel.org/accounting/psi.html) |
io.max는 아래와 같이 major:minor 장치 번호를 지정해서 설정한다.
# echo "8:0 rbps=2097152 wbps=2097152" > /sys/fs/cgroup/my_cgroup/io.max
프로세스 관리
프로세스 추가/제거
cgroup에 속한 프로세스 목록은 cgroup.procs를 읽어 확인한다.
# cat /sys/fs/cgroup/my_cgroup/cgroup.procs
반대로 특정 프로세스가 어느 cgroup에 속해 있는지는 /proc/$PID/cgroup으로 확인할 수 있다.
# cat /proc/$YOUR_PID/cgroup
0::/my_cgroup
프로세스를 다른 cgroup으로 옮기려면 옮길 cgroup의 cgroup.procs에 PID를 다시 쓰면 된다. 루트 cgroup으로 되돌리려면 root의 cgroup.procs에 쓴다.
# echo $YOUR_PID > /sys/fs/cgroup/cgroup.procs
cgroup 자체를 삭제할 때는 rmdir을 사용한다. cgroup.procs가 비어 있어야 삭제할 수 있고, 프로세스가 남아있으면 “Device or resource busy” 에러가 발생한다.
# rmdir /sys/fs/cgroup/my_cgroup
스레드 단위로 세밀하게 제어하려는 경우, 해당 cgroup을 threaded 모드로 전환한 뒤 cgroup.threads에 TID를 입력하면 프로세스 전체가 아닌 개별 스레드만 옮길 수 있다.
cgroup v2 예제
지금까지 다룬 내용을 묶어서, 특정 프로세스의 CPU 사용량을 코어 1개의 50%로, 메모리 사용량을 200MB로 제한하는 예제다.
# mkdir /sys/fs/cgroup/webapp
# echo "+cpu +memory" > /sys/fs/cgroup/cgroup.subtree_control
# echo "50000 100000" > /sys/fs/cgroup/webapp/cpu.max
# echo "200M" > /sys/fs/cgroup/webapp/memory.max
# echo $YOUR_PID > /sys/fs/cgroup/webapp/cgroup.procs
cpu.max의 “50000 100000″은 100000μs(period)마다 최대 50000μs(quota)만 CPU를 사용할 수 있다는 뜻으로, 코어 1개 기준 50%에 해당한다. 설정이 제대로 반영됐는지는 아래처럼 확인한다.
# cat /sys/fs/cgroup/webapp/cpu.max
50000 100000
# cat /sys/fs/cgroup/webapp/memory.current
# cat /sys/fs/cgroup/webapp/memory.events
low 0
high 0
max 0
oom 0
oom_kill 0
memory.max를 초과하면 memory.events의 max 카운트가 올라가고, 계속 회수에 실패하면 oom_kill이 발생해 프로세스가 종료된다.
참고
cgroups: 프로세스 그룹의 자원 관리
cgroup: cpu 서브시스템
cgroup: memory 서브시스템
cgroups: Memory Threshold Notifier 구현
cgroups v1 사용법