다중 처리기 스케줄링 (Multiple-Processor Scheduling)
핵심 인사이트 (3줄 요약)
- 본질: 다중 처리기 스케줄링은 CPU가 1개인 환경(단일 코어)을 넘어, 여러 개의 물리적 CPU 코어에 프로세스들을 어떻게 분배하고 할당할 것인가를 다루는 거시적 자원 관리 아키텍처다.
- 가치: 단순히 코어 수가 늘어났다고 속도가 배가 되는 것이 아니라, 메모리 캐시 적중률 유지(Cache Affinity)와 여러 코어 간의 처리량 균형(Load Balancing)이라는 고도의 동기화(Synchronization) 난제를 풀어야만 진정한 병렬 처리(Parallelism) 성능을 획득할 수 있다.
- 융합: 초기 마스터-슬레이브(비대칭) 구조에서 벗어나 모든 코어가 평등하게 동작하는 **SMP (대칭형 다중 처리)**가 현대의 표준이 되었으며, 나아가 CPU와 메모리의 물리적 거리를 따지는 NUMA (Non-Uniform Memory Access) 아키텍처와 결합하여 극한의 스케줄링 최적화로 진화하고 있다.
Ⅰ. 개요 및 필요성 (Context & Necessity)
- 개념: 시스템 내에 2개 이상의 독립된 프로세서(Processor, Core)가 존재할 때, Ready 큐에 있는 프로세스들을 이 다수의 코어들에게 적절히 배분(Mapping)하는 스케줄링 기법 및 정책이다.
- 필요성: 단일 프로세서 스케줄링이 1차선 도로의 신호등 제어였다면, 다중 처리기 스케줄링은 8차선 고속도로의 톨게이트 배분과 같다. 만약 8개의 코어 중 1번 코어에만 작업이 몰리고 나머지 7개가 놀고 있다면(Load Imbalance), 아무리 비싼 CPU를 사도 시스템 성능은 1코어 때와 다를 바 없는 참담한 자원 낭비가 발생한다.
- 💡 비유: 대형 은행에 10개의 창구(다중 코어)가 있을 때, 대기하는 수백 명의 손님(프로세스)을 **'하나의 공통 대기줄'**로 세울지, 아니면 **'창구마다 10개의 독립된 줄'**로 세울지, 그리고 옆 창구가 비면 손님을 넘겨줄지(Load Balancing) 결정하는 지점장의 '창구 분배 전략'과 완벽히 일치한다.
- 등장 배경: 무어의 법칙(Moore's Law)에 한계가 오면서 CPU 클럭 속도를 높이는 대신 코어(Core)의 개수를 늘리는 멀티코어(Multi-core) 패러다임으로 하드웨어 시장이 전환되었다. 이에 발맞춰 운영체제 역시 싱글 코어 시절의 낡은 스케줄러(단일 큐 전역 락)를 뜯어고쳐, 코어 간의 충돌(Contention)을 최소화하는 분산 아키텍처로 진화해야만 했다.
[다중 처리기 스케줄링의 진화 흐름도]
[1세대: 비대칭 (ASMP)] [2세대: 대칭형 (SMP) - 현대 표준]
(Master 코어만 OS 통제권 가짐) (모든 코어가 동등한 권한으로 OS 구동)
[ 마스터 코어 0 ] (보스) [코어 0] [코어 1] [코어 2] [코어 3]
│ 하달 │ │ │ │ (각자 꺼내감)
┌────────┼────────┐ └──────┼──────┼──────┘
▼ ▼ ▼ ▼
[슬레이브1] [슬레이브2] [슬레이브3] [ 공통 Ready Queue ]
(얘네는 시키는 유저 코드만 실행) (문제점: 큐를 꺼낼 때마다 엄청난 락(Lock) 경합 발생!)
[다이어그램 해설] 초기 비대칭(Asymmetric) 방식은 만들기 쉬웠다. 마스터 코어 1개가 스케줄러 역할을 독점하고 나머지 코어에 노가다만 시켰다. 하지만 마스터가 병목(Bottleneck)이 되면 시스템 전체가 뻗는 치명적 단점이 있었다. 그래서 모든 코어가 평등하게 Ready 큐에 접근하는 대칭형(Symmetric, SMP)으로 진화했다. 그러나 SMP 환경에서는 여러 코어가 동시에 하나의 큐에 접근하려다 보니 거대한 병목(Lock Contention)이 새롭게 터져버렸다.
- 📢 섹션 요약 비유: 옛날엔 사장(마스터 코어) 혼자 결재 서류를 쥐고 직원(슬레이브 코어)들에게 일을 하나씩 던져주는 수직적 회사였다면, 현대는 직원 모두가 알아서 일감 보관함(Ready 큐)에서 일을 꺼내가는 수평적 자율 회사(SMP)로 바뀌었습니다. 하지만 보관함이 1개뿐이라 서로 꺼내가려다 몸싸움(Lock)이 나는 게 새로운 숙제입니다.
Ⅱ. 아키텍처 및 핵심 원리 (Deep Dive)
큐의 구조적 선택: SQA vs MQA
다중 처리기 스케줄러 설계의 가장 중대한 갈림길은 대기줄(Queue)을 어떻게 만들 것이냐다.
1. 단일 큐 다중 처리기 (SQA: Single Queue Multiprocessor)
- 방식: 시스템 전체에 거대한 Ready Queue를 딱 1개만 둔다.
- 장점: 부하 균등화(Load Balancing)가 저절로 완벽하게 이루어진다. 노는 코어는 무조건 중앙 큐에서 일을 빼가므로 코어가 쉴 틈이 없다.
- 치명적 단점 (확장성 붕괴): 64코어 CPU 환경이라면, 64개의 코어가 동시에 1개의 큐에서 프로세스를 뺏어가려 덤빈다. 데이터 오염을 막기 위해 큐 전체에 **뮤텍스 락(Global Lock)**을 걸어야 하는데, 코어 1개가 락을 쥔 동안 나머지 63개 코어는 큐에 접근조차 못 하고 놀아야(Spinning) 하는 극악의 지연이 발생한다.
2. 다중 큐 다중 처리기 (MQA: Multiple Queue Multiprocessor)
- 방식: 각 CPU 코어마다 전용(Private) Ready Queue를 하나씩 따로 둔다. (현대 Windows, Linux O(1) 및 CFS 스케줄러의 채택 방식)
- 장점: 내 코어는 내 전용 큐에서만 프로세스를 꺼내므로 다른 코어와 락(Lock) 경합이 거의 0에 수렴한다. CPU 캐시 친화성(Affinity)이 극대화된다.
- 치명적 단점 (불균형): 코어 0번의 큐에는 100개의 프로세스가 쌓여 터지려 하는데, 코어 1번의 큐는 텅텅 비어 코어 1번이 백수로 노는 '로드 임밸런스(Load Imbalance)' 현상이 필연적으로 발생한다.
┌────────────────────────────────────────────────────────────────────────┐
│ 현대 SMP 아키텍처의 다중 큐(MQA) 구조와 캐시 친화성 보호 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ [ 코어 0 ] [ 코어 1 ] [ 코어 2 ] [ 코어 3 ] │
│ │ └ L1캐시 │ └ L1캐시 │ └ L1캐시 │ └ L1캐시 │
│ ▼ ▼ ▼ ▼ │
│ [ 큐 0 ] [ 큐 1 ] [ 큐 2 ] [ 큐 3 ] │
│ P1, P2 P3, P4 P5 (텅 빔) │
│ │
│ ▶ 장점: P1은 영원히 코어 0번에서만 실행되므로, 코어 0의 L1/L2 캐시에 │
│ 남아있는 자신의 데이터를 계속 재활용(Cache Hit)할 수 있어 초고속! │
│ │
│ 🚨 문제 발생: 코어 3번은 자기 큐가 비어서 빈둥빈둥 놀고 있음. │
│ ✅ 해결책 (Push/Pull Migration): OS가 주기적으로 코어 0의 큐를 │
│ 검사하여, 넘치는 프로세스 P2를 코어 3의 큐로 강제 이사(Migration) │
│ 시켜버림으로써 전체 균형을 다시 맞춘다. (Load Balancing) │
└────────────────────────────────────────────────────────────────────────┘
[다이어그램 해설] 컴퓨터 과학은 항상 "일단 쪼개서(MQA) 락을 없애고 빠르게 만든 다음, 쪼개서 생긴 불균형의 부작용은 백그라운드 관리 데몬(Load Balancer)이 몰래 고쳐준다"는 방식으로 발전해 왔다. 현대 OS는 철저하게 MQA 구조를 취하며, 프로세스가 처음 태어날 때 해시(Hash) 연산을 통해 특정 코어의 큐에 영구 배정해 버린다.
- 📢 섹션 요약 비유: 마트에서 "1줄 서기(SQA)"를 하면 손님 분배는 완벽하지만 맨 앞줄에서 엉키고 싸움(Lock)이 납니다. 반대로 "계산대별로 각자 서기(MQA)"를 하면 쾌적하지만 어떤 계산대만 손님이 몰립니다. 결국 계산대별로 각자 서게 하되, 줄이 긴 곳의 손님을 눈치껏 빈 계산대로 끌고 가는 매니저(Load Balancer)를 두는 것이 현대의 정답입니다.
Ⅲ. 융합 비교 및 다각도 분석 (Comparison & Synergy)
프로세서 친화도 (Processor Affinity)의 두 가지 얼굴
다중 코어 스케줄링에서 가장 중요한 단어는 **'캐시 친화도(Cache Affinity)'**다. 프로세스가 어제 돌았던 그 코어에서 오늘 또 돌아야, 그 코어 내부의 L1/L2 캐시에 남아있는 뜨거운 데이터(Warm Cache)를 그대로 주워 먹어 성능이 3배 빨라지기 때문이다.
| 종류 | 설명 및 특징 | 커널의 취급 방식 |
|---|---|---|
| 연성 친화도 (Soft Affinity) | OS가 "웬만하면 네가 쓰던 코어에 계속 배정해 줄게, 근데 너무 한쪽에만 몰리면 딴 코어로 보낼 수도 있어"라고 최선을 다하지만 절대 보장은 안 함. | 일반적인 범용 OS (리눅스 디폴트)의 기본 정책. 균형(Load Balance)이 캐시보다 중요할 땐 이사를 감행함. |
| 강성 친화도 (Hard Affinity) | 사용자가 "내 이 데이터베이스 프로세스는 무조건 0번, 1번 코어에서만 돌아야 해! 죽어도 딴 코어로 보내지 마!"라고 강제로 대못을 박는 행위. | sched_setaffinity() 시스템 콜이나 taskset 명령어로 관리자가 직접 코어를 격리(Isolation)함. |
친화도(Affinity) vs 부하 균등화(Load Balancing)의 트레이드오프
다중 처리기 스케줄링의 영원한 딜레마다.
-
친화도 극대화: 프로세스를 절대 다른 코어로 이사(Migration)시키지 않는다. 캐시 적중률은 100%가 되지만, 어떤 코어는 100% 풀로드이고 어떤 코어는 0%로 노는 양극화가 터진다.
-
부하 균등화 극대화: 노는 꼴을 못 보고 계속 프로세스를 다른 코어의 큐로 빼앗아(Work Stealing) 이사시킨다. 균형은 완벽하지만 이사 갈 때마다 새로운 코어의 L1 캐시가 비어있어(Cold Cache) 메모리에서 데이터를 퍼 오느라 끔찍한 렉(디스패치 지연)이 유발된다.
-
📢 섹션 요약 비유: 연성 친화도는 "이사 가면 짐 정리(캐시 로드)하느라 일주일 날리니까 웬만하면 지금 집에 평생 살아, 근데 집값이 너무 오르면 어쩔 수 없이 딴 동네로 이사시켜 줄게"라는 현실적인 정책입니다. 강성 친화도는 "이 집(특정 코어)은 나만 쓸 수 있는 성역이야"라고 알박기를 하는 것입니다.
Ⅳ. 실무 적용 및 기술사적 판단 (Strategy & Decision)
실무 시나리오
- Redis 및 Nginx의 강성 친화도(CPU Pinning) 튜닝: 싱글 스레드 기반으로 초당 10만 건을 처리하는 Redis 서버나 Nginx 워커 프로세스를 운영할 때, OS 스케줄러가 부하 분산을 한답시고 코어 0번에 있던 Redis를 코어 1번으로 이주(Migration)시키는 순간 엄청난 캐시 미스(Cache Miss) 스파이크가 튀며 지연이 발생한다.
- 아키텍처 결단: 실무 아키텍트는 OS의 개입을 원천 차단하기 위해 리눅스
taskset명령어 연동을 통해 Nginx 워커 프로세스 4개를 코어 0, 1, 2, 3에 각각 **강성 친화도(Hard Affinity, CPU Pinning)**로 대못을 박아버린다. 이를 통해 코어 이동 오버헤드를 제로화하고 L3 캐시 오염을 완벽히 방어한다.
- 아키텍처 결단: 실무 아키텍트는 OS의 개입을 원천 차단하기 위해 리눅스
- NUMA (Non-Uniform Memory Access) 아키텍처 스케줄링: 최신 듀얼 소켓 제온(Xeon) 서버는 메모리가 두 덩어리로 나뉘어 있다. CPU 0번은 0번 메모리와 가깝고(빠름), 1번 메모리와는 멀다(느림). 만약 스케줄러가 CPU 0번에서 도는 프로세스를 CPU 1번으로 아무 생각 없이 이사(Load Balancing)시켜버리면, 이 프로세스는 자기가 쓰던 0번 메모리에 접근하기 위해 멀고 먼 메인보드 횡단 버스(QPI)를 타야 하므로 성능이 30% 이상 박살 난다.
- 실무 조치: 현대 리눅스 스케줄러(NUMA-aware Scheduler)는 이사를 시킬 때 "이 코어와 저 메모리가 물리적으로 가까운가?"를 계산하여, 절대 남의 동네 메모리를 끌어다 쓰지 않도록 같은 NUMA 노드 안에서만 스케줄링을 강제하는 정밀 제어를 수행한다. (DB 서버 튜닝의 핵심)
┌─────────────────────────────────────────────────────────────────┐
│ 멀티코어 시스템 성능 최적화를 위한 스케줄링 아키텍처 트리 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ [ 64 코어 대형 시스템 부하 분산 및 튜닝 전략 ] │
│ │ │
│ ▼ [분석 1] L1/L2 캐시 미스율이 비정상적인가? │
│ ├─ [예 (잦은 Migration 발생 의심)] │
│ │ │ │
│ │ ▼ 튜닝 조치 │
│ │ - 커널 파라미터(migration_cost_ns) 상승 │
│ │ - 웬만하면 프로세스를 딴 코어로 옮기지 못하게 방어 │
│ │ - Cgroups를 통한 특정 코어군(cpuset) 완전 격리 │
│ │ │
│ └─ [아니오] │
│ │ │
│ ▼ [분석 2] 코어별 사용률 불균형이 심한가? │
│ (예: 코어 0은 100%, 코어 63은 0%) │
│ │ │
│ ▼ 튜닝 조치 │
│ - Work Stealing(작업 훔치기) 폴링 빈도 증가 │
│ - 인터럽트(IRQ) 어피니티 분산 (irqbalance) │
└─────────────────────────────────────────────────────────────────┘
[다이어그램 해설] 다중 코어 시대의 스케줄링은 알고리즘의 우수성보다 **'물리적 아키텍처와의 궁합'**이 100배 중요하다. 아무리 완벽한 O(1) 스케줄러라도 하드웨어의 NUMA 노드 경계를 무시하고 이사를 시키면 지옥이 펼쳐진다. 클라우드 엔지니어가 cpuset과 numactl을 이용해 OS 스케줄러의 팔다리를 묶고 "너는 이 동네에서만 놀아!"라고 수동 격리(Isolation)를 쳐주는 것이 대규모 인프라 튜닝의 꽃이다.
- 📢 섹션 요약 비유: 전학생(프로세스)을 자꾸 이 반, 저 반으로 옮겨 다니게 하면 교실 인원수(Load Balancing)는 칼같이 맞겠지만, 그 전학생은 친구를 사귈 시간(캐시 웜업)이 없어서 성적이 바닥을 칩니다. 웬만하면 1학년 3반(특정 코어)에 끝까지 뼈를 묻게 해주는 것이 최고의 성적을 내는 교육 스케줄링입니다.
Ⅴ. 기대효과 및 결론 (Future & Standard)
기대효과
다중 큐(MQA)와 NUMA 인지 스케줄링을 성공적으로 결합하면, 수십~수백 개의 거대 코어 시스템에서도 스케줄러 자체의 락(Lock) 병목 없이 선형적인 성능 확장(Linear Scalability)을 이끌어내며, 99% 이상의 물리적 CPU 이용률과 극한의 메모리 접근 속도(Zero Remote Node Access)를 획득할 수 있다.
결론 및 미래 전망
멀티코어 스케줄링은 **'대칭형 다중 처리(SMP) + 각 코어별 독립 큐(MQA) + 연성 프로세서 친화도(Soft Affinity) + 작업 훔치기(Work Stealing)'**라는 4가지 철학의 완벽한 융합체로 굳어졌다. (현대 리눅스 CFS가 정확히 이 모델이다). 미래의 스케줄러는 ARM의 big.LITTLE이나 인텔의 P-Core/E-Core처럼 속도가 각기 다른 이기종 코어(Heterogeneous Multicore) 환경에서, 배터리 잔량과 발열 온도(Thermal Throttling)까지 고려하여 "이 작업은 뜨거워진 고성능 코어 대신 차가운 저전력 코어로 이사시킨다"는 3차원 에너지 인지 스케줄링(Energy-Aware Scheduling, EAS)으로 진화하고 있다.
- 📢 섹션 요약 비유: 예전에는 일꾼 8명이 똑같은 삽(동일 코어)을 들고 파면 그만이었지만, 이제는 굴삭기 2대(P코어)와 모종삽 6개(E코어)가 섞여 있고 심지어 기름값(배터리)과 엔진 온도까지 계산해서 실시간으로 어떤 놈에게 흙을 퍼게 할지 지시하는 무시무시한 AI 현장소장(미래 OS 스케줄러)의 시대로 진입했습니다.
📌 관련 개념 맵 (Knowledge Graph)
| 개념 명칭 | 관계 및 시너지 설명 |
|---|---|
| 프로세서 친화도 (Processor Affinity) | 프로세스가 과거의 향수(L1/L2 캐시)를 잊지 못해 원래 돌던 코어에 계속 머물고 싶어 하는 다중 스케줄링의 핵심 중력이다. |
| 부하 균등화 (Load Balancing) | 특정 코어만 과로사하는 것을 막기 위해, 친화도를 부수고 억지로 프로세스를 이사시키는 또 다른 스케줄링 축이다. |
| NUMA (Non-Uniform Memory Access) | 코어와 메모리 간의 물리적 '거리'를 다루는 아키텍처로, 스케줄러가 함부로 프로세스를 남의 동네 코어로 넘기지 못하게 막는 하드웨어적 벽이다. |
| 다단계 큐 (Multilevel Queue) | 스케줄러가 코어 1개에 대해 큐를 분리했다면, MQA(Multi Queue Architecture)는 아예 코어별로 큐를 통째로 찢어서 락(Lock)을 없앤 공간적 분할이다. |
| 작업 훔치기 (Work Stealing) | 부하 균등화를 위해 한가한 코어가 바쁜 옆 동네 코어의 큐를 몰래 열어 프로세스를 훔쳐 오는 현대 스케줄러의 기민한 뒷골목 기술이다. |
👶 어린이를 위한 3줄 비유 설명
- 계산원이 1명일 때는 줄을 1개만 서면 되지만, 대형 마트처럼 계산원(코어)이 8명으로 늘어나면 줄을 어떻게 세울지 엄청난 작전이 필요해요!
- 만약 하나의 긴 줄로 서서 비는 곳으로 가면 공평하지만, 맨 앞에서 8명이 서로 자기가 가겠다고 엉켜서 멱살을 잡고 싸우게 돼요(스케줄러 병목).
- 그래서 계산대마다 각자 줄을 따로 서게 만들고, 어떤 줄이 너무 길면 매니저 아저씨(OS)가 눈치껏 긴 줄의 손님을 텅 빈 계산대로 슥~ 빼주는 방식이 현대 컴퓨터의 8코어 스케줄링 비법이랍니다!