668. cgroups와 하드웨어 자원 할당 (Control Groups HW Resource Allocation)
핵심 인사이트 (3줄 요약)
- 본질: cgroups(Control Groups)는 리눅스 커널에서 프로세스들을 그룹화하여 CPU, 메모리, 입출력(I/O), 네트워크와 같은 물리적 하드웨어 자원의 사용량을 제한하고 우선순위를 제어하는 핵심 프레임워크다.
- 가치: 특정 프로세스가 시스템 전체의 자원을 독점하는 '시끄러운 이웃(Noisy Neighbor)' 문제를 방지하며, 가상화 및 컨테이너 환경에서 서비스 수준 협약(SLA)을 보장하는 기초 토대가 된다.
- 융합: CFS(Completely Fair Scheduler)와 같은 CPU 스케줄링 알고리즘, 페이지 캐시 관리, 블록 계층의 I/O 스로틀링 기술과 밀접하게 결합되어 하드웨어 추상화 및 자원 분배의 정수를 보여준다.
Ⅰ. 개요 및 필요성
1. 자원 공유의 무질서: "만인에 대한 만인의 투쟁"
- 현상: 운영체제 위에서는 수많은 프로세스가 돌아간다. 만약 어떤 프로세스에 무한 루프 버그가 있거나 과도하게 파일을 읽어댄다면, 다른 중요한 서비스들은 자원을 할당받지 못해 멈추게 된다.
- 문제점: 전통적인 유닉스 시스템은 사용자별 제한(ulimit)은 있었으나, 연관된 프로세스 그룹 전체를 묶어서 하드웨어 자원을 세밀하게 통제하는 기능이 부족했다.
2. cgroups의 탄생: "질서 있는 분배"
- 도입: 구글의 엔지니어들이 'Process Containers'라는 이름으로 처음 개발하여 리눅스 커널에 기증했다.
- 목표: CPU 시간, 메모리 용량, 디스크 대역폭 등을 '계층적'으로 관리하여, 서버 한 대를 마치 여러 대의 가상 서버처럼 자원을 나누어 쓸 수 있게 하는 것이다.
3. 비유적 설명
- 💡 비유: '수돗물 배분 시스템'과 같습니다.
- 프로세스: 물을 쓰는 각 가정의 수도꼭지입니다.
- cgroups: 마을 전체의 물탱크에서 각 구역(그룹)으로 가는 파이프의 굵기를 조절하는 밸브입니다.
- 자원 할당: 옆집(다른 그룹)에서 물을 아무리 많이 틀어도, 우리 집 파이프에 설정된 최소 물의 양(Weight/Limit)은 보장되며, 최대치를 넘겨서 다른 동네 물을 뺏어갈 수도 없습니다.
4. cgroups 계층 구조와 컨트롤러 (ASCII)
[ Root Cgroup (/) ]
│
┌──────┴────────────────────────┐
│ [ Production Group ] │ [ Development Group ]
│ - cpu.shares = 1024 │ - cpu.shares = 512
│ - memory.limit = 10G │ - memory.limit = 2G
└──────┬───────────────────────┘ └─────────────────────┘
│
┌──────┴────────────────┐
│ [ Web Server Pod ] │ [ DB Server Pod ]
│ - pids: 101, 102 │ - pids: 205
└───────────────────────┘ └─────────────────────┘
* 특징: 부모 그룹의 자원 한도 내에서 자식 그룹이 자원을 나눠 가짐.
- 📢 섹션 요약 비유: cgroups는 '가계부'입니다. 전체 수입(하드웨어 총자원)을 식비, 교육비, 저축(각 그룹)으로 미리 떼어놓고, 그 안에서만 돈을 쓰게 하여 한쪽의 과소비가 가계 전체를 망치지 않게 관리합니다.
Ⅱ. 아키텍처 및 핵심 원리
1. 주요 서브시스템 (Controllers)
- cpu: CFS(Completely Fair Scheduler)를 사용하여 프로세스 그룹에 할당되는 CPU 시간 비율을 제어한다.
- cpuset: 특정 프로세스 그룹이 오직 지정된 CPU 코어와 메모리 노드(NUMA)에서만 실행되도록 물리적으로 고정한다.
- memory: 프로세스 그룹의 총 메모리 사용량을 제한한다. 한도를 넘으면 OOM(Out of Memory) 킬러가 작동하거나 스와핑이 발생한다.
- blkio: 블록 장치(SSD/HDD)에 대한 읽기/쓰기 속도(bps)나 초당 작업 수(iops)를 제한한다.
- pids: 그룹 내에서 생성할 수 있는 총 프로세스/쓰레드 수를 제한하여 '포크 폭탄(Fork Bomb)' 공격을 막는다.
2. CPU 스케줄링과의 상호작용
- Shares (가중치): 시스템이 바쁠 때 자원을 어떤 비율로 나눌지 결정한다. (예: 1024 vs 512면 2:1로 CPU를 씀)
- Quota / Period (강제 한도): CPU가 널널하더라도 절대 넘을 수 없는 상한선을 정한다. (예: 100ms 중 20ms만 써라 -> 0.2 CPU 제한)
3. 메모리 제어와 페이지 캐시
- cgroups는 익명 메모리(Anonymous Memory)뿐만 아니라 파일 캐시(Page Cache)까지 추적한다.
- 특정 그룹이 파일을 너무 많이 읽어 호스트의 메모리를 캐시로 다 채워버리는 것을 막기 위해 '메모리 소프트 리미트'와 '하드 리미트'를 사용한다.
4. cgroups v1 vs v2
-
v1 (Legacy): 각 컨트롤러(cpu, mem 등)가 별개의 계층 구조를 가져 관리가 복잡하고 컨트롤러 간 협업이 어려웠다.
-
v2 (Unified Hierarchy): 모든 컨트롤러가 하나의 단일 계층 구조를 따르며, 자원 관리가 더 직관적이고 효율적으로 변했다. 특히 I/O와 메모리 제어의 시너지가 좋아졌다.
-
📢 섹션 요약 비유: v1이 '부서마다 따로 관리하는 장부'였다면, v2는 '전사 통합 전산 시스템'입니다. 모든 자원 흐름이 한눈에 보이고 조율하기가 훨씬 쉬워졌습니다.
Ⅲ. 비교 및 연결
cgroups vs 가상화(Hypervisor) vs ulimit
| 비교 항목 | ulimit (User Limit) | cgroups | 가상화 (VM) |
|---|---|---|---|
| 제어 단위 | 사용자(UID) 기준 | 프로세스 그룹 기준 | 가상 하드웨어 기준 |
| 자원 제한 범위 | 단순 파일/프로세스 수 | CPU, Mem, I/O 등 전방위 | 하드웨어 수준의 물리 분리 |
| 격리 수준 | 매우 낮음 | 중간 (커널 공유) | 높음 (독립 커널) |
| 오버헤드 | 없음 | 매우 낮음 (커널 내 로직) | 높음 (Guest OS 실행) |
| 동적 변경 | 가능 | 실시간 즉시 반영 가능 | 일부 가능 (Hot-plug 필요) |
시스템 호출(System Call)과 cgroups 인터페이스
-
cgroups는 별도의 시스템 호출 대신 Virtual File System (VFS) 인터페이스를 사용한다.
-
/sys/fs/cgroup/경로 아래에 디렉토리를 만들면 그룹이 생성되고, 파일에 값을 쓰면 즉시 하드웨어 자원 제한이 적용되는 직관적인 방식을 택했다. -
📢 섹션 요약 비유: ulimit이 '개인용 용돈 제한'이고 VM이 '독립해서 따로 사는 것'이라면, cgroups는 '한 지붕 아래 살면서 생활비를 공동 관리하는 것'입니다. 효율적이면서도 서로 선은 넘지 않습니다.
Ⅳ. 실무 적용 및 기술사 판단
실무 시나리오
-
쿠버네티스(Kubernetes) 자원 할당 전략 (Requests vs Limits)
- 상황: 서비스가 갑자기 폭주할 때 다른 서비스에 영향을 주지 않아야 함.
- 적용:
Requests는 cgroups의cpu.shares로,Limits는cpu.cfs_quota_us로 변환되어 적용됨을 이해하고 설정. - 결과: 우선순위가 높은 Pod는 자원을 보장받고, 낮은 Pod는 한도를 초과하지 못하게 관리.
-
빌드 서버(CI/CD) 성능 최적화
- 상황: 컴파일 작업이 CPU를 100% 사용하여 모니터링 시스템이 멈춤.
- 적용: 빌드 프로세스들을 별도 cgroup으로 묶고
cpuset을 통해 특정 코어(예: 0~14번)만 쓰게 하고 15번 코어는 시스템 관리용으로 남겨둠. - 결과: 빌드 중에도 관리자의 원격 접속 및 모니터링이 원활하게 유지됨.
안티패턴 (Anti-pattern)
-
메모리 제한을 너무 타이트하게 설정: 애플리케이션의 Peak 사용량을 고려하지 않고 Limits를 설정하면, 멀쩡한 프로세스가 OOM Killer에 의해 수시로 죽어 서비스 가용성이 떨어진다.
-
I/O 제한 없는 로그 기록: CPU와 메모리는 제한했지만 디스크 I/O를 제한하지 않으면, 로그 폭주 시 시스템 전체의 디스크 대기 시간(I/O Wait)이 증가하여 모든 서비스가 느려진다.
-
📢 섹션 요약 비유: 엔진 출력(CPU)만 제한하고 브레이크 성능(I/O)은 신경 쓰지 않는 자동차와 같습니다. 전체적인 주행 밸런스(시스템 안정성)를 위해서는 모든 서브시스템의 제한 수치를 조화롭게 설정해야 합니다.
Ⅴ. 기대효과 및 결론
정량적 기대효과
- 서버 밀집도(Density): 자원 제한을 통해 한 대의 서버에 수용 가능한 컨테이너 수 2~3배 증가.
- 서비스 안정성: 특정 프로세스 폭주시 타 서비스 영향도 90% 이상 차단.
- 운영 비용: 유휴 자원을 효율적으로 재배분하여 전체 클라우드 비용 절감.
결론
cgroups는 리눅스가 단순한 개인용 OS에서 거대한 클라우드 인프라의 심장으로 거듭나게 한 **'자원 관리의 혁명'**이다. 하드웨어라는 한정된 영토를 어떻게 하면 공정하고 효율적으로 나누어 줄 것인가에 대한 소프트웨어적 해답이 바로 cgroups다. 기술사는 단순히 명령어를 치는 수준을 넘어, 커널 내부에서 CFS나 페이지 캐시 매커니즘이 cgroups 설정값에 따라 어떻게 춤추는지 이해하고 설계해야 한다.
- 📢 섹션 요약 비유: cgroups는 '현명한 정원사'입니다. 한 나무가 모든 양분을 빨아먹어 옆 나무를 죽이지 않도록, 뿌리 깊은 곳(커널 내부)에서부터 영양분(자원)의 흐름을 조절하여 정원 전체(시스템)가 건강하게 자라게 합니다.
📌 관련 개념 맵
| 개념 명칭 | 관계 및 시너지 설명 |
|---|---|
| Namespace | cgroups가 자원의 '양'을 제한한다면, 네임스페이스는 자원의 '이름(가시성)'을 격리함. |
| CFS Scheduler | cgroups cpu 컨트롤러가 실제로 사용하는 커널 스케줄링 알고리즘. |
| OOM Killer | cgroups memory 제한을 어긴 프로세스를 사살하는 커널의 마지막 수단. |
| systemd | 현대 리눅스에서 cgroups 계층 구조를 자동으로 관리하는 서비스 매니저. |
| Pressure Stall Information (PSI) | cgroups 내에서 CPU/Mem/IO 부족으로 얼마나 대기했는지 보여주는 지표. |
👶 어린이를 위한 3줄 비유 설명
- cgroups는 컴퓨터 속에 있는 **'자원 나누기 대장'**이에요.
- 여러 개의 게임을 동시에 켤 때, 한 게임이 컴퓨터 힘을 다 써버리지 못하게 골고루 나누어 준답니다.
- 덕분에 동생이 무거운 게임을 해도 내 공부 프로그램이 버벅거리지 않고 잘 돌아갈 수 있어요!