04. Proxmox VE Compute — CPU, Memory, VM & LXC
가상화의 핵심 리소스 — CPU와 메모리가 VM/LXC에 어떻게 할당되고 관리되는가
📌 이 글의 목적
CPU와 메모리는 가상화의 가장 핵심적인 리소스임. “vCPU 4개, 메모리 8GB”로 VM을 만들었을 때, 물리 자원이 어떻게 매핑되고 스케줄링되는지를 이해하면 성능 설계, 오버커밋 전략, 리소스 경합 분석의 기반이 됨.
이 글을 읽고 나면:
- vCPU가 물리 CPU에 어떻게 매핑/스케줄링되는지 이해할 수 있음
- NUMA 토폴로지가 VM 성능에 미치는 영향을 설명할 수 있음
- 메모리 오버커밋과 Ballooning의 동작 원리를 이해할 수 있음
- KVM VM과 LXC의 리소스 관리 차이를 비교할 수 있음
- VMware의 CPU/Memory 관리 모델과 구조적 차이를 비교할 수 있음
1. CPU 가상화와 스케줄링
1.1 vCPU와 물리 CPU의 관계
Proxmox에서 VM에 할당하는 vCPU는 물리 CPU 코어와 1:1 고정이 아님. 각 vCPU는 QEMU 프로세스 내의 스레드로 표현되며, Linux CFS(Completely Fair Scheduler)가 이를 물리 코어에 스케줄링함.
flowchart TB subgraph Physical["물리 CPU (8코어)"] Core0["코어 0"] Core1["코어 1"] Core2["코어 2"] Core3["코어 3"] Core4["코어 4"] Core5["코어 5"] Core6["코어 6"] Core7["코어 7"] end subgraph CFS["Linux CFS 스케줄러"] Sched["시분할 스케줄링"] end subgraph VM_Threads["VM 스레드들"] VM1_T0["VM1 vCPU0"] VM1_T1["VM1 vCPU1"] VM2_T0["VM2 vCPU0"] VM2_T1["VM2 vCPU1"] VM2_T2["VM2 vCPU2"] VM2_T3["VM2 vCPU3"] Host_P["호스트 프로세스들"] end VM_Threads --> CFS CFS --> Physical
핵심 포인트:
- vCPU는 특정 물리 코어에 고정(pin)되지 않는 한, CFS가 자유롭게 스케줄링함
- 물리 코어 수보다 더 많은 vCPU를 할당할 수 있음 (CPU 오버커밋)
- 오버커밋 시 CFS의 시분할에 의해 각 vCPU의 실행 시간이 줄어듦
1.2 CPU 토폴로지 설정
Proxmox에서 VM의 CPU 토폴로지를 설정할 때 3가지 요소가 있음.
| 항목 | 설명 | 예시 |
|---|---|---|
| Sockets | 가상 CPU 소켓 수 | 1 |
| Cores | 소켓당 코어 수 | 4 |
| vCPUs (총합) | Sockets × Cores | 4 |
# 예시: 2소켓 × 4코어 = 8 vCPU
qm set 100 --sockets 2 --cores 4
소켓 vs 코어 — 어떻게 설정하나?
| 설정 | 게스트 OS가 보는 것 | 용도 |
|---|---|---|
| 1소켓 × 8코어 | 8코어 1소켓 CPU | ✅ 일반적 (NUMA 1노드) |
| 2소켓 × 4코어 | 4코어 2소켓 CPU | NUMA 매핑, Windows 라이선스 고려 시 |
| 8소켓 × 1코어 | 1코어 8소켓 CPU | ❌ 비추천 (NUMA 비효율) |
💡 Windows 라이선스: Windows Server의 일부 에디션은 소켓 수에 따라 라이선스가 달라짐. VM에서 소켓 수를 최소화하면 라이선스 비용을 절약할 수 있음.
1.3 CPU 타입
| 설정 | 의미 | 성능 | 마이그레이션 |
|---|---|---|---|
| host | 호스트 CPU 기능을 그대로 노출 | ✅ 최고 | ❌ 동일 CPU만 |
| kvm64 / qemu64 | 최소 가상 CPU | 낮음 | ✅ 어디서든 |
| x86-64-v2-AES | x86-64 마이크로아키텍처 레벨 v2 + AES | 좋음 | ✅ v2 이상 |
| x86-64-v3 | AVX2 등 포함 | 더 좋음 | v3 이상 |
| x86-64-v4 | AVX-512 포함 | 높음 | v4 이상 |
추천 전략:
- 단일 노드 / 동일 CPU 클러스터 →
host(최고 성능) - 이기종 CPU 클러스터 →
x86-64-v2-AES또는x86-64-v3(마이그레이션 호환성 확보)
💡 VMware의 EVC(Enhanced vMotion Compatibility)와 유사한 개념. EVC가 클러스터 수준에서 CPU 기능을 통일하는 것처럼, Proxmox에서는 CPU 타입을 적절히 선택하여 마이그레이션 호환성을 확보함.
1.4 CPU Pinning (affinity)
특정 vCPU를 특정 물리 코어에 고정하는 설정.
# VM 100의 vCPU 0을 물리 코어 2에, vCPU 1을 물리 코어 3에 고정
qm set 100 --affinity 2-3
# taskset으로 직접 확인
taskset -cp $(pgrep -f 'kvm.*-id 100')| Pinning | 장점 | 단점 |
|---|---|---|
| 사용 안 함 (기본) | CFS가 유연하게 스케줄링 | 캐시 미스 가능성 |
| 사용 | 캐시 지역성 향상, 예측 가능한 성능 | 유연성 감소, 코어 고정으로 다른 VM 사용 불가 |
💡 NUMA 환경에서 CPU Pinning은 성능에 큰 영향을 미침. VM의 vCPU를 같은 NUMA 노드의 코어에 고정하면 메모리 접근 지연이 줄어듦.
1.5 CPU 오버커밋
물리 코어 수보다 더 많은 vCPU를 할당하는 것.
| 비율 | 의미 | 적합한 워크로드 |
|---|---|---|
| 1:1 | 오버커밋 없음 | 지연 민감한 DB, 실시간 처리 |
| 2:1 | 물리 1코어당 vCPU 2개 | 일반 웹 서버, 개발 환경 |
| 4:1 | 물리 1코어당 vCPU 4개 | 유휴 시간이 많은 경량 서비스 |
| 8:1+ | 고밀도 | 테스트 환경, VDI(idle 상태 많음) |
⚠️ CPU 오버커밋은 “각 VM이 항상 100% CPU를 사용하지 않는다”는 가정에 기반함. 모든 VM이 동시에 CPU를 100% 사용하면 경합이 발생하여 모든 VM의 성능이 저하됨.
2. NUMA — Non-Uniform Memory Access
2.1 NUMA란
현대 멀티소켓 서버에서 각 CPU 소켓은 자체 메모리 컨트롤러와 로컬 메모리를 가짐. 자기 소켓에 연결된 메모리(로컬)에 접근하는 것이 다른 소켓의 메모리(리모트)에 접근하는 것보다 빠름.
flowchart LR subgraph Socket0["소켓 0 (NUMA Node 0)"] CPU0["CPU 코어 0-7"] MEM0["로컬 메모리<br/>64GB"] end subgraph Socket1["소켓 1 (NUMA Node 1)"] CPU1["CPU 코어 8-15"] MEM1["로컬 메모리<br/>64GB"] end CPU0 -->|"빠름<br/>(로컬)"| MEM0 CPU1 -->|"빠름<br/>(로컬)"| MEM1 CPU0 -->|"느림<br/>(리모트, QPI/UPI)"| MEM1 CPU1 -->|"느림<br/>(리모트, QPI/UPI)"| MEM0
| 접근 유형 | 지연 시간 | 대역폭 |
|---|---|---|
| 로컬 메모리 | ~80ns | 최대 |
| 리모트 메모리 | 인터커넥트에 의해 제한 |
2.2 Proxmox의 NUMA 지원
# VM에 NUMA 활성화
qm set 100 --numa 1
# NUMA 노드 수동 정의
qm set 100 --numa0 cpus=0-3,memory=4096
qm set 100 --numa1 cpus=4-7,memory=4096NUMA를 활성화하면:
- 게스트 OS가 NUMA 토폴로지를 인식함
- 게스트 OS 자체의 NUMA 최적화가 동작함 (스케줄러, 메모리 할당)
- CPU Pinning과 결합하면 최적의 성능을 얻을 수 있음
NUMA 모범 사례:
| 원칙 | 설명 |
|---|---|
| VM을 NUMA 노드 안에 맞추기 | VM의 vCPU와 메모리가 하나의 NUMA 노드에 들어가면 리모트 접근이 발생하지 않음 |
| 소켓 경계 넘기지 않기 | 8코어/소켓 서버에서 VM에 12 vCPU를 주면 반드시 NUMA 경계를 넘음 |
| 대형 VM은 NUMA를 활성화 | 다중 소켓 서버에서 대형 VM은 NUMA를 켜야 게스트 OS가 최적화 가능 |
💡 VMware의 NUMA 처리: ESXi는 NUMA 스케줄러가 자동으로 VM을 NUMA 노드에 배치하고 최적화함. Proxmox/KVM은 Linux CFS + 수동 Pinning/NUMA 설정으로 유사한 효과를 얻음. ESXi의 자동화 수준이 더 높은 편.
3. 메모리 관리
3.1 메모리 할당 모델
Proxmox에서 VM 메모리를 관리하는 주요 메커니즘:
flowchart TD subgraph Normal["정상 상태"] Static["정적 할당<br/>(고정 메모리)"] Balloon["Ballooning<br/>(동적 조절)"] end subgraph Pressure["메모리 부족 시"] KSM["KSM<br/>(Kernel Same-page Merging)"] Swap["스왑<br/>(최후의 수단)"] end Static --> Balloon -->|"부족"| KSM -->|"더 부족"| Swap
3.2 Memory Ballooning
Ballooning은 VM의 메모리를 동적으로 조절하는 기술임. Balloon Driver가 VM 내부에서 “빈 메모리를 점유”하여 호스트에 반환하거나, 반대로 메모리를 해제하여 VM에 돌려줌.
sequenceDiagram participant Host as 호스트 (Proxmox) participant Balloon as Balloon Driver (VM 내부) participant GuestOS as Guest OS Note over Host: 호스트 메모리 부족 감지 Host ->> Balloon: "메모리 1GB 반환해줘" (inflate) Balloon ->> GuestOS: 1GB 메모리 점유 (사용 불가로 만듦) GuestOS ->> GuestOS: 사용 가능 메모리 감소 Balloon ->> Host: 1GB 메모리 반환 Note over Host: 호스트 메모리 여유 생김 Host ->> Balloon: "메모리 돌려줄게" (deflate) Balloon ->> GuestOS: 점유한 메모리 해제 GuestOS ->> GuestOS: 사용 가능 메모리 증가
Proxmox Ballooning 설정:
# 최소 2GB, 최대 8GB (Ballooning 활성화)
qm set 100 --memory 8192 --balloon 2048
# Ballooning 비활성화 (항상 고정 메모리)
qm set 100 --memory 8192 --balloon 0| 설정 | 의미 |
|---|---|
memory | VM에 할당되는 최대 메모리 |
balloon | 최소 보장 메모리. 이 아래로는 줄이지 않음 |
balloon=0 | Ballooning 비활성화 (메모리 고정) |
⚠️ Ballooning이 동작하려면 VM 내부에 VirtIO Balloon Driver가 설치되어 있어야 함. Linux는 기본 내장, Windows는 VirtIO 드라이버 설치 필요.
3.3 KSM — Kernel Same-page Merging
KSM은 동일한 내용의 메모리 페이지를 여러 VM이 공유하도록 하는 Linux 커널 기능임.
flowchart LR subgraph Before["KSM 전"] VM1_Page["VM1: 페이지 A<br/>(0xABCD...)"] VM2_Page["VM2: 페이지 A<br/>(0xABCD... 동일)"] VM3_Page["VM3: 페이지 A<br/>(0xABCD... 동일)"] end subgraph After["KSM 후"] Shared["공유 페이지 A<br/>(0xABCD...)"] VM1_Ref["VM1 → 참조"] VM2_Ref["VM2 → 참조"] VM3_Ref["VM3 → 참조"] VM1_Ref --> Shared VM2_Ref --> Shared VM3_Ref --> Shared end Before -->|"KSM 스캔"| After
- 동일한 OS를 실행하는 VM이 많을수록 효과가 큼 (커널 코드, 공유 라이브러리 등)
- Copy-on-Write로 동작하므로 VM이 해당 페이지를 수정하면 자동으로 분리됨
- CPU 오버헤드가 있음 (백그라운드 스캔)
💡 VMware의 TPS(Transparent Page Sharing)와 동일한 개념. 다만 VMware는 보안상의 이유로 기본적으로 같은 VM 내에서만 TPS를 적용하고, VM 간 공유는 비활성화함 (CVE-2014-0182).
3.4 Huge Pages
기본 페이지 크기(4KB) 대신 대형 페이지(2MB 또는 1GB) 를 사용하여 TLB 미스를 줄이고 메모리 접근 성능을 향상시키는 기술.
| 페이지 크기 | TLB 커버리지 (1024 엔트리 기준) | 용도 |
|---|---|---|
| 4KB | 4MB | 기본 |
| 2MB | 2GB | 대형 VM, 데이터베이스 |
| 1GB | 1TB | 매우 대형 VM, 고성능 워크로드 |
# Proxmox에서 Huge Pages 활성화
qm set 100 --hugepages 2 # 2MB 페이지
qm set 100 --hugepages 1024 # 1GB 페이지
# 호스트에서 Huge Pages 예약
echo 4096 > /proc/sys/vm/nr_hugepages # 2MB × 4096 = 8GB 예약⚠️ Huge Pages를 사용하면 해당 메모리는 호스트에서 예약되어 다른 용도로 사용 불가능함. Ballooning과 KSM도 동작하지 않음. 성능이 필요한 특정 VM에만 선택적으로 적용하는 것이 권장됨.
3.5 메모리 오버커밋
물리 메모리보다 더 많은 메모리를 VM에 할당하는 것.
| 전략 | 방법 | 위험도 |
|---|---|---|
| Ballooning | VM이 사용하지 않는 메모리를 호스트에 반환 | 낮음 |
| KSM | 동일 페이지 공유로 실질적 사용량 감소 | 낮음 |
| Swap | 호스트 메모리 부족 시 디스크로 페이징 | ⚠️ 높음 |
| OOM Killer | 메모리 완전 부족 시 프로세스(VM) 강제 종료 | ❌ 매우 높음 |
💡 VMware는 메모리 관리를 TPS → Ballooning → Compression → Swap 4단계로 수행함. Proxmox/KVM은 KSM → Ballooning → Swap → OOM Killer 순서. VMware의 Memory Compression(압축 후 메모리에 유지)에 해당하는 기능은 KVM에 없음.
4. 리소스 제어 — cgroups
4.1 cgroups v2
Proxmox는 cgroups v2를 사용하여 VM(QEMU 프로세스)과 LXC 컨테이너의 리소스를 제어함.
| 리소스 | 제어 방식 | 설명 |
|---|---|---|
| CPU | cpu.weight (shares) | 상대적 CPU 시간 비율 |
| CPU | cpu.max (quota/period) | 절대적 CPU 시간 제한 |
| 메모리 | memory.max | 최대 메모리 제한 |
| 메모리 | memory.high | 메모리 사용 감속 임계값 |
| I/O | io.weight | 상대적 I/O 비율 |
| I/O | io.max | 절대적 I/O 제한 (IOPS, BPS) |
4.2 Proxmox의 리소스 제한 옵션
CPU 제한:
| 옵션 | 설명 | 예시 |
|---|---|---|
cores | vCPU 수 | 4 |
cpulimit | CPU 사용량 상한 (코어 단위) | 2.0 = 2코어분까지 |
cpuunits | 상대적 CPU 가중치 (기본 1024) | 2048 = 기본의 2배 |
# VM 100: 4 vCPU지만 최대 2코어분만 사용 가능
qm set 100 --cores 4 --cpulimit 2
# VM 100: 다른 VM 대비 CPU 우선순위 2배
qm set 100 --cpuunits 2048메모리 제한:
| 옵션 | 설명 |
|---|---|
memory | 최대 할당 메모리 (MB) |
balloon | 최소 보장 메모리 (MB) |
shares | Ballooning 시 상대적 우선순위 (기본 1000) |
💡 VMware의 Reservation, Limit, Shares 모델과 대응:
- Reservation ≈
balloon(최소 보장)- Limit ≈
memory(최대 허용)- Shares ≈
cpuunits/shares(상대적 우선순위)
5. KVM VM vs LXC — 워크로드 비교
5.1 아키텍처 차이
flowchart TB subgraph KVM_Side["KVM (하드웨어 가상화)"] VM_KVM["VM"] GuestKernel["Guest Kernel<br/>(독립 커널)"] QEMU_Proc["QEMU 프로세스"] KVM_Mod["KVM 모듈"] VM_KVM --> GuestKernel --> QEMU_Proc --> KVM_Mod end subgraph LXC_Side["LXC (OS 가상화)"] CT_LXC["Container"] NS["Namespaces<br/>(PID, NET, MNT, UTS, IPC, USER)"] CG["cgroups v2<br/>(리소스 제한)"] HostKernel["호스트 커널 공유"] CT_LXC --> NS --> CG --> HostKernel end
5.2 상세 비교
| 항목 | KVM VM | LXC Container |
|---|---|---|
| 가상화 수준 | 하드웨어 (전체 머신 에뮬레이션) | OS (커널 공유, 프로세스 격리) |
| 커널 | 독립 커널 (아무 OS 가능) | 호스트 커널 공유 (Linux만) |
| 오버헤드 | 중간 (VirtIO 시 낮음) | 매우 낮음 (네이티브에 가까움) |
| 부팅 시간 | 수십 초 | 수 초 |
| 메모리 오버헤드 | 100~300MB+ (게스트 커널, QEMU) | 수 MB (프로세스 자체만) |
| CPU 오버헤드 | 낮음 (VT-x 가속) | 거의 없음 |
| 격리 수준 | 높음 (하드웨어 분리) | 중간 (커널 공유 — 커널 취약점 시 위험) |
| 지원 OS | 모든 OS (Windows, BSD 등) | Linux만 |
| 디스크 I/O | VirtIO 경유 | 직접 파일시스템 접근 |
| 네트워크 | 가상 NIC (tap + bridge) | veth pair + bridge |
| 스냅샷 | ✅ (QEMU 수준) | ✅ (스토리지 수준) |
| 라이브 마이그레이션 | ✅ | 제한적 (CRIU 기반, 실험적) |
| GPU Passthrough | ✅ (PCI Passthrough) | 제한적 |
| Docker 실행 | ✅ | ✅ (nesting 활성화 필요) |
5.3 LXC의 격리 메커니즘
LXC는 Linux 커널의 Namespace와 cgroups로 격리를 구현함.
| Namespace | 격리 대상 | 설명 |
|---|---|---|
| PID | 프로세스 ID | 컨테이너 내부에서 PID 1부터 시작 |
| NET | 네트워크 | 독립 네트워크 스택, 인터페이스, IP |
| MNT | 마운트 포인트 | 독립 파일시스템 뷰 |
| UTS | 호스트명 | 독립 호스트명, 도메인명 |
| IPC | IPC 리소스 | 독립 세마포어, 메시지 큐 |
| USER | 사용자 ID | UID/GID 매핑 (Unprivileged CT) |
| cgroup | cgroup 뷰 | 자체 cgroup 트리 |
5.4 Privileged vs Unprivileged LXC
| 유형 | UID 매핑 | 보안 | 성능 | 권장 |
|---|---|---|---|---|
| Unprivileged | 컨테이너 root = 호스트 UID 100000+ | ✅ 안전 | 약간의 오버헤드 | ✅ 기본 |
| Privileged | 컨테이너 root = 호스트 root (UID 0) | ⚠️ 위험 | 약간 더 빠름 | NFS, 특수 장치 |
💡 Unprivileged 컨테이너가 강력히 권장됨. 컨테이너 내부에서 root 탈출(escape)이 발생해도 호스트에서는 비권한 사용자이므로 피해가 제한됨.
5.5 워크로드별 선택 기준
| 워크로드 | 추천 | 이유 |
|---|---|---|
| Windows 서버 | KVM | LXC는 Linux만 지원 |
| 데이터베이스 (MySQL, PostgreSQL) | KVM | 커널 수준 튜닝, 격리 필요 |
| 웹 서버 (Nginx, Apache) | LXC | 경량, 빠른 프로비저닝 |
| DNS/NTP/Syslog | LXC | 인프라 서비스, 리소스 최소 |
| 모니터링 (Prometheus, Grafana) | LXC | 경량 서비스 |
| CI/CD Runner | LXC 또는 KVM | Docker 필요 시 nesting 활성화 |
| Kubernetes 워커 | KVM | 커널 모듈 필요, 격리 중요 |
| 개발/테스트 환경 | LXC | 빠른 생성/삭제, 리소스 절약 |
| 보안 민감 워크로드 | KVM | 하드웨어 수준 격리 |
6. VMware와의 Compute 비교
| 항목 | Proxmox (KVM) | VMware (ESXi) |
|---|---|---|
| CPU 스케줄러 | Linux CFS | VMkernel CPU Scheduler |
| NUMA 자동 최적화 | 수동 (Pinning + NUMA 옵션) | 자동 (NUMA Scheduler) |
| CPU 오버커밋 | 지원 (CFS 시분할) | 지원 (Ready, Co-Stop 메트릭) |
| 메모리 관리 | Ballooning, KSM, Swap | TPS, Ballooning, Compression, Swap |
| Memory Compression | ❌ 없음 | ✅ (Swap 전 단계) |
| 리소스 예약 | balloon(최소), cpuunits(가중치) | Reservation, Limit, Shares |
| DRS (자동 밸런싱) | ❌ 없음 | ✅ (vMotion 기반 자동 재배치) |
| Resource Pool | Pool (기본) | Resource Pool (계층 구조) |
| 컨테이너 | ✅ LXC 내장 | ❌ (Tanzu는 별도) |
| Hot Add CPU | ✅ | ✅ |
| Hot Add Memory | ✅ | ✅ |
💡 VMware의 가장 큰 차별점은 DRS(자동 부하 분산) 과 NUMA 자동 최적화임. Proxmox에서는 이를 수동 설정이나 외부 스크립트로 보완해야 함. 반면 LXC라는 경량 컨테이너 옵션은 Proxmox만의 강점임.
정리
Proxmox의 컴퓨트 리소스 관리는 Linux 커널의 기능을 그대로 활용하는 구조임.
- CPU: Linux CFS가 vCPU 스레드를 스케줄링. CPU 타입, Pinning, NUMA 설정으로 최적화
- 메모리: Ballooning으로 동적 조절, KSM으로 페이지 공유, Huge Pages로 TLB 최적화
- KVM VM: 하드웨어 가상화로 모든 OS 지원, 강한 격리, 약간의 오버헤드
- LXC: OS 가상화로 Linux만 지원, 매우 낮은 오버헤드, 경량 서비스에 적합
- 리소스 제어: cgroups v2 기반으로 CPU, 메모리, I/O를 세밀하게 제한
다음 글
→ #5 Network Configuration — Linux Bridge, VLAN, Bonding, SDN 아키텍처
🔗 관련 문서
- KVM & QEMU Architecture — #2, KVM/QEMU 내부 동작
- Proxmox Management Architecture — #3, API/권한/클러스터
- VMware Compute — VMware CPU/Memory 비교
- Proxmox VE Series Index — 시리즈 목차