핵심 인사이트 (3줄 요약)
- 본질: 이벤트 루프 (Event Loop) 기반 비동기 처리 (Node.js)은 프로세스와 스레드의 생성·실행·협력에서 핵심 흐름을 결정하는 개념으로, 시스템이 무엇을 먼저 관리하고 어떤 순서로 제어할지를 분명하게 만든다.
- 가치: 이 개념을 이해하면 자원 효율, 응답 시간, 안정성 사이의 균형을 더 정확하게 설명할 수 있고, 컨텍스트 스위칭 최소화를 위한 스레드 고정 (Thread Affinity/Pinning)로 이어지는 이유도 자연스럽게 파악된다.
- 판단 포인트: 코루틴 (Coroutine)과의 관계를 함께 봐야 이벤트 루프 (Event Loop) 기반 비동기 처리 (Node.js)을 단순 정의가 아니라 실제 설계·운영 판단 기준으로 사용할 수 있다.
Ⅰ. 개요 및 필요성
1. 정의 및 특징
이벤트 루프(Event Loop)는 단일 스레드에서 이벤트 큐를 순회하며 콜백 함수를 디스패치하는 비동기 처리 아키텍처다. 멀티스레딩 없이 동시성을 달성하는 핵심 메커니즘이다.
비유: 식당 주방장이 혼자서 주문서를 하나씩 확인하고, 조리가 오래 걸리는 음식은 오븐에 맡겨놓고 다음 주문을 처리하는 방식과 같다.
┌─────────────────────────────────────────────────┐
│ Event Loop │
│ │
│ ┌─────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Event │───>│ Dispatch │───>│ Callback │ │
│ │ Queue │ │ & Exec │ │ Complete │ │
│ └─────────┘ └──────────┘ └──────────┘ │
│ ^ │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────────────────┘
┌─────────────────── Single Thread Timeline ───────────────────┐
│ │
│ [A]──request──>[B]──request──>[A]──callback──>[C]──... │
│ non-blocking non-blocking result │
│ │
│ Legend: [A],[B],[C] = async operations │
└──────────────────────────────────────────────────────────────┘
- 📢 섹션 요약 비유: 복잡한 창고에서 필요한 물건을 찾기 위해 먼저 구역과 표지판을 세우는 것과 같다.
Ⅱ. 아키텍처 및 핵심 원리
1. 논블로킹 I/O (Non-blocking I/O)
I/O 연산이 완료될 때까지 스레드를 차단하지 않고 즉시 반환하며, 작업 완료 시 콜백을 큐에 등록한다.
2. 이벤트 루프의 5단계 (Node.js 기준)
| 단계 | 이름 | 설명 |
|---|---|---|
| 1 | Timers | setTimeout, setInterval 만료된 콜백 실행 |
| 2 | Pending Callbacks | 이전 루프에서 지연된 I/O 콜백 실행 |
| 3 | Poll | 새로운 I/O 이벤트 수집 및 실행 |
| 4 | Check | setImmediate 콜백 실행 |
| 5 | Close | close 이벤트 콜백 실행 |
┌──────────────────────────────────────────────────────────┐
│ Event Loop Phases │
│ │
│ ┌────────┐ ┌────────┐ ┌──────┐ ┌───────┐ ┌─────┐│
│ │ Timers │─>│Pending │─>│ Poll │─>│ Check │─>│Close││
│ └────────┘ │Callback│ └──────┘ └───────┘ └─────┘│
│ ^ └────────┘ │ │
│ └───────────────────────┘ (다시 반복) │
│ │
│ [Microtask Queue: Promise.then, process.nextTick] │
│ > 각 페이즈 사이마다 우선 실행 │
└──────────────────────────────────────────────────────────┘
3. 구현체별 특징
| 플랫폼 | 엔진 | 특징 |
|---|---|---|
| Node.js | libuv | C++ 기반, 파일 I/O + 네트워크 모두 비동기 |
| Browser JS | V8/SpiderMonkey | Web API 사용, UI 렌더링과 병행 |
| Python asyncio | async/await | 코루틴 기반, asyncio.run() 진입점 |
| Go | goroutine | M:N 스케줄링, runtime에 이벤트 루프 내장 |
비유: 이벤트 루프의 페이즈는 우체부가 아침에 배달(Timers), 미처 못한 편지(Pending), 새 편지 수거(Poll), 등기 확인(Check), 마감(Close) 순으로 돌리는 일과와 같다.
- 📢 섹션 요약 비유: 공장 컨베이어벨트가 어떤 순서로 부품을 받아 가공하고 내보내는지 설계도를 펼쳐 보는 것과 같다.
Ⅲ. 비교 및 연결
1. 콜백 기반 vs 프로미스 기반
┌────────────────── Callback Style ──────────────────┐
│ │
│ readFile("data.txt", function(err, data) { │
│ if (err) throw err; // 콜백 지옥 가능 │
│ console.log(data); │
│ }); │
│ │
└─────────────────────────────────────────────────────┘
┌────────────────── Promise Style ───────────────────┐
│ │
│ readFile("data.txt") │
│ .then(data => console.log(data)) │
│ .catch(err => console.error(err)); │
│ │
│ // async/await 변환 │
│ const data = await readFile("data.txt"); │
│ │
└─────────────────────────────────────────────────────┘
2. 마이크로태스크와 매크로태스크
| 구분 | 예시 | 실행 시점 |
|---|---|---|
| Microtask | Promise.then, queueMicrotask | 현재 페이즈 종료 직후, 다음 페이즈 이전 |
| Macrotask | setTimeout, setImmediate | 다음 이벤트 루프 틱(tick) |
- 📢 섹션 요약 비유: 비슷해 보이는 공구를 나란히 놓고 언제 망치를 쓰고 언제 드라이버를 써야 하는지 구분하는 것과 같다.
Ⅳ. 실무 적용 및 기술사 판단
1. 장점
- 스레드 생성/컨텍스트 스위칭 오버헤드 없음
- 메모리 사용량 적음 (단일 스레드)
- 수만 개의 동시 연결 처리 가능 (C10K 문제 해결)
- 동기 코드와 비슷한 제어 흐름으로 작성 가능
2. 한계: CPU 연산 집약적 작업
┌──────── CPU-Bound Blocking ────────┐
│ │
│ [Event Loop]──[Task A]────────────>│ BLOCKED!
│ │ │ (다른 이벤트 전부 지연)
│ │ CPU 100% │
│ │ 10초 소요 │
│ ▼ │
│ [완료] │
│ [Task B, C, D... 지연됨] │
│ │
└─────────────────────────────────────┘
해결책: Worker Thread 분리, 클러스터 모드 (멀티프로세스), C++ Addon 오프로딩
- 📢 섹션 요약 비유: 운전자가 도로 상황에 따라 기어와 브레이크를 다르게 선택하는 것처럼 조건별 판단이 중요하다.
Ⅴ. 기대효과 및 결론
이벤트 루프 기반 비동기 처리
├── 핵심 개념
│ ├── 단일 스레드 이벤트 구동 아키텍처
│ ├── 논블로킹 I/O
│ └── 콜백 큐 순회 및 디스패치
├── 이벤트 루프 페이즈
│ ├── Timers (setTimeout/setInterval)
│ ├── Pending Callbacks (지연된 I/O)
│ ├── Poll (새 이벤트 수집)
│ ├── Check (setImmediate)
│ └── Close (닫기 콜백)
├── 구현체
│ ├── libuv (Node.js)
│ ├── Browser Web API
│ ├── Python asyncio
│ └── Go runtime scheduler
├── 비동기 패턴
│ ├── Callback (콜백 지옥)
│ ├── Promise (then/catch/finally)
│ └── Async/Await (코루틴)
├── 장점
│ ├── 스레드 오버헤드 제거
│ ├── 적은 메모리 사용
│ └── C10K 문제 해결
└── 한계 및 해결책
├── CPU-bound 작업 시 블로킹
├── Worker Thread 분리
└── 클러스터 (멀티프로세스)
| 약어 | Full Name |
|---|---|
| libuv | Library for UV (Unified Virtualization) |
| I/O | Input/Output |
| API | Application Programming Interface |
| C10K | Client 10,000 Problem |
컴퓨터가 한 사람처럼 일할 때, 기다리지 않고 여러 일을 번갈아 하는 방법입니다. 주문이 들어오면 오븐에 넣고 다른 주문을 받는 식당 주방장과 같아요. 단, 계산이 아주 많이 필요한 일은 다른 도우미에게 맡겨야 합니다.
- 📢 섹션 요약 비유: 도구의 장점만 외우는 것이 아니라 어디까지 믿고 어디서 보완해야 하는지 기억하는 정리 노트와 같다.
📌 관련 개념 맵
| 개념 | 연결 포인트 |
|---|---|
| 고루틴 (Goroutine) | 현재 개념으로 들어오기 전에 함께 이해하면 경계가 선명해지는 기반 개념이다. |
| 코루틴 (Coroutine) | 현재 개념이 등장하게 만든 직접적인 선행 흐름이다. |
| 컨텍스트 스위칭 최소화를 위한 스레드 고정 (Thread Affinity/Pinning) | 현재 개념이 구현·세분화될 때 바로 연결되는 후속 개념이다. |
| CPU 친화성 (CPU Affinity) | 확장 학습이나 심화 비교로 이어지는 다음 단계의 키워드다. |
📈 관련 키워드 및 발전 흐름도
[코루틴 (Coroutine)]
│
▼
[이벤트 루프 (Event Loop) 기반 비동기 처리 (Node.js)]
│
├──▶ [컨텍스트 스위칭 최소화를 위한 스레드 고정 (Thread Affinity/Pinning)]
└──▶ [CPU 친화성 (CPU Affinity)]
이 흐름도는 선행 개념에서 현재 개념으로 넘어온 뒤, 구현 세분화와 후속 확장으로 이어지는 학습 순서를 압축해 보여준다.
👶 어린이를 위한 3줄 비유 설명
- 이벤트 루프 (Event Loop) 기반 비동기 처리 (Node.js)은 컴퓨터가 여러 일을 나눠서 처리하고 서로 기다리게 하는 약속이에요.
- 먼저 코루틴 (Coroutine)을 이해하면 이벤트 루프 (Event Loop) 기반 비동기 처리 (Node.js)이 왜 필요한지 더 쉽게 보여요.
- 그래서 이벤트 루프 (Event Loop) 기반 비동기 처리 (Node.js)을 잘 알면 나중에 컨텍스트 스위칭 최소화를 위한 스레드 고정 (Thread Affinity/Pinning)도 훨씬 쉽게 배울 수 있어요.