cgroup v2 사용법

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) 단위이다.

InterfaceDescription
cpu.statcpu 사용 통계를 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.pressurePSI (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

InterfaceDescription
memory.currentcgroup의 현재 메모리 사용량
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.pressurePSI (Pressure Stall Information) 지표 제공 (참고: https://docs.kernel.org/accounting/psi.html)
memory.eventslow, high, max, oom에 대한 event 수
memory.statcgroup의 메모리 사용량 통계

IO

블록 장치에 대한 읽기/쓰기 대역폭과 IOPS를 제어한다.

InterfaceDescription
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.pressurePSI (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 사용법

답글 남기기