ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [linux] cgroup v1과 v2 및 cgroup 메모리에 대한 이해(+metric)
    SW개발/Linux 2025. 7. 27. 19:44

    리눅스 기반 시스템에서 리소스 관리와 격리는 매우 중요한 주제입니다. 특히 컨테이너 기술이 보편화된 지금, CPU, 메모리, I/O 등 다양한 리소스를 어떻게 효율적으로 제어할 것인가는 운영의 핵심이 되었습니다. 바로 이 지점에서 Cgroup(Control Groups)이 등장합니다.

    Cgroup은 리눅스 커널 기능 중 하나로, 프로세스 그룹에 대해 자원 사용량을 제한하거나 계측하고, 우선순위를 조정할 수 있도록 해줍니다. 그런데 이 Cgroup에는 두 가지 주요 버전이 존재합니다: v1과 v2. 두 버전은 구조와 동작 방식, 특히 메모리 관리 방식에서 상당한 차이를 보입니다.

    이 글에서는 Cgroup v1과 v2의 개념을 간단히 짚어보고, 특히 메모리 서브시스템의 차이점, OOM(Out of Memory) 상황에서의 처리 방식, 주요 파일과 메트릭 변화 등을 중심으로 정리해보겠습니다. 쿠버네티스와 컨테이너 환경을 운영 중이라면, 이 차이를 이해하는 것은 리소스 최적화와 장애 대응에 큰 도움이 될 것입니다.

    1. Cgroup v1의 한계

    Cgroup v1은 유연한 자원 제어를 목표로 시작되었지만, 실제로는 다음과 같은 문제들을 안고 있었습니다.


    분리된 컨트롤러: 각 컨트롤러(CPU, Memory, I/O 등)가 독립적인 hierarchy를 갖는 구조로 인해, 시스템 전체에서 여러 계층이 겹치고 충돌하면서 관리 복잡도가 증가했습니다.

    컨트롤러 간 작업의 어려움: 예를 들어, CPU와 메모리를 함께 제어하려 해도 각기 다른 계층에 설정되어 있어 일관된 자원 제어가 어려웠습니다.

    리소스 별로 각기 다른 API 설계: 각 컨트롤러마다 고유의 인터페이스와 attachment rule(프로세스 연결 규칙)을 갖고 있어 리소스 컨트롤러 별로 API 규칙이 다른 부분들이 많았습니다.

     

    2. Cgroup v2의 개선사항


    이러한 문제를 해결하기 위해 등장한 Cgroup v2는 다음과 같은 구조적 개선을 포함합니다

    단일 통합 계층 구조: 모든 컨트롤러를 하나의 unified hierarchy에서 관리하도록 하여, 구조를 단순화하고 컨트롤러 간 협조를 용이하게 만들었습니다.

    더 안전한 하위 트리 위임: 컨테이너 런타임이나 관리 도구가 하위 cgroup 트리만 위임받아도 안전하게 리소스를 나누고 관리할 수 있도록 설계되었습니다.

    향상된 리소스 격리 및 관리: 다양한 리소스(예: 네트워크 버퍼, 커널 메모리 등)를 보다 정밀하게 추적하고 제한할 수 있도록 했습니다.
    특히 다음과 같은 부분이 눈에 띕니다.
    • 다양한 메모리 유형에 대한 통합된 계정 관리
    • 페이지 캐시 쓰기 지연(writeback) 등 지연되는 리소스 변화에 대한 명확한 설명과 제어


    3. cgroup v1 -> v2로의 구조 변화

    구분 cgroup v1 cgroup v2
    아키텍쳐
    계층 구조 여러 개의 독립적인 계층 구조 (CPU, Memory 등 컨트롤러별로 계층 분리) 단일 통합 계층 구조
    프로세스 할당 프로세스를 여러 다른 Control 그룹 계층에 동시 할당 가능 프로세스는 단 하나의 Control 그룹에만 속할 수 있음
    컨트롤러 관리 꼐층별로 컨트롤러 활성화/비활성화 단일 계층 내에서 특정 서브트리에 컨트롤러를 활성화/비활성화
    리소스 분배 cpu.shares (CPU), clkio.weight (I/O) 등 컨트롤러별 독자적인 분배 방식 cpu.weight, io.weight 등 일관된 weight 기반의 통합된 분배 방식
    커널 메모리 사용량 추척 커널 메모리 사용량을 정확히 추적하기 어려움 커널 메모리 사용량을 정확하게 추적하고 그룹에 귀속시킬 수 있음 (memory.stat에 slab 포함)
    특징 - 유연하지만 구조가 복잡하고 일관성 부족
    - 오래되어 안정적이고 널리 사용됨
    - 구조가 단순하고 일관성 향상
    - 더 정확한 리소스 제어 및 통계 제공
    - kubernetes 최신 버전의 기본값
    cgroup 파일 위치 - /proc/${pid}/cgroup 파일을 열면 ${container_cgroup_path}가 출력됨
    - /sys/fs/cgroup/memory/${container_cgroup_path}로 접근
    - /proc/${pid}/cgroup 파일을 열면 ${container_cgroup_path}가 출력됨
    - /sys/fs/cgroup/${container_cgroup_path}로 접근
        ㄴ 중간에 memory 등 리소스 경로 생략됨

     

    4. 계산식 변화

    구분 cgroup v1 cgroup v2
    메모리 사용량 메트릭 파일 memory.usage_in_bytes memory.current
    메모리 측정에 사용되는 지표 RSS + Page Cache RSS + Page Cache + Kernel Memory
    계산 정확성 - 커널 메모리 누락으로 OOM Killer 오작동 가능성 있음
    - memory.usage_in_bytes는 커널 메모리(소켓 버퍼, inode 등) 사용량을 제대로 포함하지 않는다
    모든 메모리 사용량을 포함하여 더 정확한 메모리 값을 전달

     

    5. container_memory_usage_bytes vs container_memory_working_set_bytes

    구분 container_memory_usage_bytes container_memory_working_set_bytes 참고사항
    의미 - 컨테이너가 현재 사용하고 있는 총 메모리 양
    - 프로세스가 실질적으로 점유하고 있는 총 메모리
    - 컨테이너가 적극적으로 사용하고 있어 메모리에서 쉽게 제거하기 어려운 메모리의 크기
    - 전체 사용량(RSS + Page Cache)에서 시스템이 메모리가 부족할 때 쉽게 회수할 수 있는 inactive_file 캐시를 제외한 값
    RSS: 특정 프로세스가 실행되기 위해 독점적으로 사용하는 실제 메모리 양으로 전체 메모리 중 RAM에 실제로 올라와 있는 부분

    바라보는 cgroup 메트릭 cgroup v1: /sys/fs/cgroup/memory/memory.usage_in_bytes
    cgroup v2: /sys/fs/cgroup/memory/memory.current
    container_memory_usage_bytes - memory.stat inactive_file: 나중에 다시 쓸 수 있지만 당장 메모리가 부족하면 가장 먼저 비워도 되는 파일 데이터의 복사본 (캐시정도)
    구체적 메모리
    구조
    cgroup v1:
    RSS (Resident Set Size) + Page Cache
    cgroup v2: 
    RSS + Page Cache + Kernel Memory (socket buffer, inode 등의 영역 포함)
    cgroup 1:
    RSS + Page Cache - inactive_file
    cgroup v2:
    RSS + Page Cache - Kernel memory - inactive_file
     
    pod OOM Killer의 기준 X O 참고)
    https://github.com/kubernetes/kubernetes/issues/118916

     

    6. Pod OOM이 일어나는 구조

    순서 cgroup v1 cgroup v2
    1 Pod에 Memory Limit을 설정하면, memory.limit_in_bytes 파일에 값 셋팅 Pod에 Memory Limit을 설정하면, memory.max에 값 셋팅
    2 cgroup 내의 memory.usage_in_bytes >= memory_in_bytes 이면 커널은 메모리 할당 거부 cgroup 내의 memory.current >= memory.max 이면 커널은 메모리 할당 거부
    3 memory.usage_in_bytes가 pod limit에 도달한 순간 inactive_file을 삭제하면서 limit에 맞게 사용량 유지 (kswapd에 의해 정리) memory.current 가 pod limit에 도달한 순간 inactive_file을 삭제하면서 limit에 맞게 사용량 유지 (kswapd에 의해 정리)
    4 더 이상 inactive_file 삭제 불가능하면 OOM Killer 동작 더 이상 inactive_file 삭제 불가능하면 OOM Killer 동작
    5 memory.oom_control의 under_oom이 1로 표시 memory.events 파일의 OOM 카운터 증가
    6 프로세스가 SIGKILL 됨 프로세스 SIGKILL 

     

    7. container_memory_usage_bytes vs container_memory_working_set_bytes 테스트

    - 결론은 container_memory_working_set_bytes를 쓰자

    https://faun.pub/how-much-is-too-much-the-linux-oomkiller-and-used-memory-d32186f29c9d

     

    How much is too much? The Linux OOMKiller and “used” memory

    Not long after recently taking a job at Splunk, a co-worker (Hi Tameem!) hit me up over Slack and asked about one of my Kubernetes metrics…

    faun.pub

     

    'SW개발 > Linux' 카테고리의 다른 글

    [Linux] 명령어 정리  (0) 2020.09.28
Designed by Tistory.