핵심 인사이트 (3줄 요약)
- 본질: CPU 친화성 (CPU Affinity)은 프로세스와 스레드의 생성·실행·협력에서 핵심 흐름을 결정하는 개념으로, 시스템이 무엇을 먼저 관리하고 어떤 순서로 제어할지를 분명하게 만든다.
- 가치: 이 개념을 이해하면 자원 효율, 응답 시간, 안정성 사이의 균형을 더 정확하게 설명할 수 있고, NUMA-인식 스레드 스케줄링로 이어지는 이유도 자연스럽게 파악된다.
- 판단 포인트: 컨텍스트 스위칭 최소화를 위한 스레드 고정 (Thread Affinity/Pinning)과의 관계를 함께 봐야 CPU 친화성 (CPU Affinity)을 단순 정의가 아니라 실제 설계·운영 판단 기준으로 사용할 수 있다.
Ⅰ. 개요 및 필요성
1. 정의
CPU 어피니티(CPU Affinity)는 프로세스나 스레드가 실행될 CPU 코어의 집합을 지정 또는 선호하는 속성이다. 운영체제 스케줄러의 스레드 배치 정책에 직접적인 영향을 미친다.
비유: 아이가 항상 앉던 자리를 선호하는 것(Soft)과, 담임 선생님이 특정 자리를 지정하는 것(Hard)의 차이와 같다.
┌─────────── CPU Affinity Overview ────────────┐
│ │
│ 프로세스 A ──── CPU Mask: 0,1,2,3 │
│ 프로세스 B ──── CPU Mask: 0,1 │
│ 프로세스 C ──── CPU Mask: 2,3 │
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │Core 0│ │Core 1│ │Core 2│ │Core 3│ │
│ │ A,B │ │ A,B │ │ A,C │ │ A,C │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
└────────────────────────────────────────────────┘
2. 소프트 어피니티 (Soft Affinity)
운영체제가 이전에 실행했던 코어를 선호하도록 하는 정책이다. 강제성이 없으며, 부하 분산이 필요한 경우 다른 코어로 마이그레이션할 수 있다.
- 구현 방식: 스케줄러의 마이그레이션 저항도(migration resistance) 설정
- 목표: 캐시 지역성 유지와 부하 분산의 균형
┌────────── Soft Affinity 동작 ──────────┐
│ │
│ 시간 T1: Thread X ──> Core 0 실행 │
│ 시간 T2: Thread X ──> Core 0 선호 │
│ (OS가 Core 0에 머무르게 함) │
│ 시간 T3: Core 0 과부하 시 │
│ Thread X ──> Core 2 이동 (허용)│
│ │
│ 특징: 선호하지만 강제하지 않음 │
│ │
└──────────────────────────────────────────┘
3. 하드 어피니티 (Hard Affinity)
프로세스가 지정된 CPU 코어 집합 외에서는 절대 실행되지 않도록 강제하는 설정이다.
- 구현 방식:
sched_setaffinity()시스템 콜 - 목표: 결정적 실행, 실시간 성능 보장
┌────────── Hard Affinity 동작 ───────────┐
│ │
│ 설정: sched_setaffinity(pid, mask=0x03) │
│ -> Core 0, 1만 허용 │
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │Core 0│ │Core 1│ │Core 2│ │Core 3│ │
│ │ OK │ │ OK │ │ X │ │ X │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
│ 스케줤러가 Core 2,3으로 이동 불가 │
│ │
└───────────────────────────────────────────┘
- 📢 섹션 요약 비유: 복잡한 창고에서 필요한 물건을 찾기 위해 먼저 구역과 표지판을 세우는 것과 같다.
Ⅱ. 아키텍처 및 핵심 원리
1. 비트마스크 구조
CPU 어피니티 마스크는 각 비트가 코어를 나타내는 정수 값이다.
┌────────────── CPU Mask Bit Layout ──────────────┐
│ │
│ Bit Position: 7 6 5 4 3 2 1 0 │
│ Core Number: 7 6 5 4 3 2 1 0 │
│ │
│ Mask = 0xFF (11111111): Core 0~7 모두 허용 │
│ Mask = 0x03 (00000011): Core 0, 1만 허용 │
│ Mask = 0x0A (00001010): Core 1, 3만 허용 │
│ Mask = 0x55 (01010101): Core 0,2,4,6만 허용 │
│ │
└───────────────────────────────────────────────────┘
┌─────────── 실제 적용 예 ─────────────┐
│ │
│ 8코어 시스템, 4개 워커 스레드: │
│ │
│ Worker-0: mask=0x01 -> Core 0 전용 │
│ Worker-1: mask=0x02 -> Core 1 전용 │
│ Worker-2: mask=0x04 -> Core 2 전용 │
│ Worker-3: mask=0x08 -> Core 3 전용 │
│ │
│ Core 4~7: OS/시스템 예약 │
│ │
└───────────────────────────────────────┘
2. 리눅스에서의 확인과 설정
# 프로세스의 CPU 어피니티 확인
taskset -p <PID>
# 프로세스를 특정 코어에 고정하여 실행
taskset -c 0,1 ./my_app
# cgroups를 통한 그룹 설정
echo "0-1" > /sys/fs/cgroup/cpuset/mygroup/cpuset.cpus
- 📢 섹션 요약 비유: 공장 컨베이어벨트가 어떤 순서로 부품을 받아 가공하고 내보내는지 설계도를 펼쳐 보는 것과 같다.
Ⅲ. 비교 및 연결
1. 과도한 고정의 문제
┌────── 하드 어피니티 로드 불균형 ──────┐
│ │
│ BEFORE (정균분산): │
│ Core 0: ████░░░░░░ 40% │
│ Core 1: ████░░░░░░ 40% │
│ Core 2: ████░░░░░░ 40% │
│ Core 3: ████░░░░░░ 40% │
│ │
│ AFTER (하드 어피니티 과도한 적용): │
│ Core 0: ██████████ 100% (과부하!) │
│ Core 1: ██░░░░░░░░ 20% │
│ Core 2: ░░░░░░░░░░ 0% (유휴) │
│ Core 3: ░░░░░░░░░░ 0% (유휴) │
│ │
│ 총 처리량 저하 발생 │
│ │
└────────────────────────────────────────┘
2. 위험 요소
| 위험 | 설명 | 대응 |
|---|---|---|
| 로드 불균형 | 특정 코어만 과부하 | 실시간 모니터링 |
| 오버커밋 | 코어 수보다 많은 스레드 고정 | 코어 수에 맞게 조정 |
| 유연성 상실 | 부하 변화에 대응 불가 | 소프트 어피니티 검토 |
| 핫스팟 | 특정 코어 온도 상승 | 균형 배치 |
비유: 4개의 계산대가 있는 마트에서 모든 손님을 1번 계산대로만 보내면 혼잡해지는 것과 같다.
1. NUMA 시스템에서의 어피니티
┌──────────── NUMA Node + CPU Affinity ────────────┐
│ │
│ NUMA Node 0 NUMA Node 1 │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Local Mem 0 │ │ Local Mem 1 │ │
│ │ (빠름) │ │ (빠름) │ │
│ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ ┌──────┴──────┐ ┌──────┴──────┐ │
│ │C0 C1 C2 C3│ │C4 C5 C6 C7│ │
│ └─────────────┘ └─────────────┘ │
│ │ │ │
│ └──── QPI/Interconnect ───┘ │
│ (원격 메모리 접근: 느림) │
│ │
│ 최적: 스레드와 메모리를 같은 노드에 고정 │
│ │
└─────────────────────────────────────────────────────┘
2. NUMA 인식 어피니티 설정
| 설정 | 명령어 | 효과 |
|---|---|---|
| CPU 노드 바인딩 | numactl --cpunodebind=0 | Node 0의 코어만 사용 |
| 메모리 노드 바인딩 | numactl --membind=0 | Node 0의 메모리만 할당 |
| 선호도 설정 | numactl --preferred=0 | Node 0 선호, 부족 시 다른 노드 |
- 📢 섹션 요약 비유: 비슷해 보이는 공구를 나란히 놓고 언제 망치를 쓰고 언제 드라이버를 써야 하는지 구분하는 것과 같다.
Ⅳ. 실무 적용 및 기술사 판단
| 약어 | Full Name |
|---|---|
| CPU | Central Processing Unit |
| NUMA | Non-Uniform Memory Access |
| QPI | QuickPath Interconnect |
| TLB | Translation Lookaside Buffer |
| PID | Process Identifier |
- 📢 섹션 요약 비유: 운전자가 도로 상황에 따라 기어와 브레이크를 다르게 선택하는 것처럼 조건별 판단이 중요하다.
Ⅴ. 기대효과 및 결론
CPU 친화성 Soft/Hard Affinity
├── 핵심 개념
│ ├── CPU 어피니티 (코어 집합 지정)
│ ├── 소프트 어피니티 (OS 선호 정책)
│ └── 하드 어피니티 (강제 바인딩)
├── CPU 마스크 비트맵
│ ├── 각 비트가 코어를 표현
│ ├── sched_setaffinity()로 설정
│ └── taskset으로 명령행 제어
├── 소프트 어피니티 특징
│ ├── 이전 코어 선호 (캐시 지역성)
│ ├── 마이그레이션 허용 (유연성)
│ └── 부하 분산 자동 조정
├── 하드 어피니티 특징
│ ├── 지정 코어 외 실행 불가
│ ├── 결정적 실행 보장
│ └── 실시간 시스템에 적합
├── 위험 및 주의사항
│ ├── 로드 불균형 (특정 코어 과부하)
│ ├── 오버커밋 (코어 수 초과 스레드)
│ └── 유연성 상실 (부하 변화 미대응)
└── NUMA 관계
├── 같은 노드에 스레드+메모리 배치
├── numactl로 노드 단위 제어
└── 원격 메모리 접근 지연 최소화
컴퓨터의 일꾼이 어느 작업대에서 일할지 정하는 규칙입니다. 소프트는 "가능하면 이 자리를 써요", 하드는 "무조건 이 자리만 써요"입니다. 자리를 너무 꽉 잡으면 다른 자리가 놀기 때문에 균형이 중요해요.
- 📢 섹션 요약 비유: 도구의 장점만 외우는 것이 아니라 어디까지 믿고 어디서 보완해야 하는지 기억하는 정리 노트와 같다.
📌 관련 개념 맵
| 개념 | 연결 포인트 |
|---|---|
| 이벤트 루프 (Event Loop) 기반 비동기 처리 (Node.js) | 현재 개념으로 들어오기 전에 함께 이해하면 경계가 선명해지는 기반 개념이다. |
| 컨텍스트 스위칭 최소화를 위한 스레드 고정 (Thread Affinity/Pinning) | 현재 개념이 등장하게 만든 직접적인 선행 흐름이다. |
| NUMA-인식 스레드 스케줄링 | 현재 개념이 구현·세분화될 때 바로 연결되는 후속 개념이다. |
| 실시간 프로세스 (Real-time Process) | 확장 학습이나 심화 비교로 이어지는 다음 단계의 키워드다. |
📈 관련 키워드 및 발전 흐름도
[컨텍스트 스위칭 최소화를 위한 스레드 고정 (Thread Affinity/Pinning)]
│
▼
[CPU 친화성 (CPU Affinity)]
│
├──▶ [NUMA-인식 스레드 스케줄링]
└──▶ [실시간 프로세스 (Real-time Process)]
이 흐름도는 선행 개념에서 현재 개념으로 넘어온 뒤, 구현 세분화와 후속 확장으로 이어지는 학습 순서를 압축해 보여준다.
👶 어린이를 위한 3줄 비유 설명
- CPU 친화성 (CPU Affinity)은 컴퓨터가 여러 일을 나눠서 처리하고 서로 기다리게 하는 약속이에요.
- 먼저 컨텍스트 스위칭 최소화를 위한 스레드 고정 (Thread Affinity/Pinning)을 이해하면 CPU 친화성 (CPU Affinity)이 왜 필요한지 더 쉽게 보여요.
- 그래서 CPU 친화성 (CPU Affinity)을 잘 알면 나중에 NUMA-인식 스레드 스케줄링도 훨씬 쉽게 배울 수 있어요.