[Node.js] 런타임 개요
정의
Node.js 는 Ryan Dahl 이 2009년 발표한 JavaScript 서버 사이드 런타임 입니다. V8 엔진 (Chrome) + libuv (비동기 I/O) + 표준 라이브러리 조합으로 브라우저 밖에서 JS 실행.
한 줄 요약: “JavaScript 로 서버, CLI, 도구를 만드는 표준 런타임”.
구성 요소
flowchart TB App["JavaScript App"] --> API["Node.js API<br/>(fs, http, crypto)"] API --> B["Bindings<br/>(C++)"] B --> V8["V8 Engine"] B --> UV["libuv"] UV --> OS["OS (kernel)"] V8 --> OS
- V8: JS 파싱, 컴파일, 실행 (Ignition, TurboFan, Maglev)
- libuv: 이벤트 루프, 비동기 I/O, thread pool
- 표준 라이브러리: fs, http, crypto, net, dns, path, url, …
Event Loop
Node.js 의 심장. 단일 스레드 + 비동기 I/O.
flowchart LR T[Timers<br/>setTimeout] --> P[Pending<br/>Callbacks] P --> I[Idle/Prepare] I --> Poll[Poll<br/>I/O] Poll --> C[Check<br/>setImmediate] C --> Cl[Close<br/>Callbacks] Cl --> T
6 단계 (phases). 각 phase 에 callback queue. 사이사이 microtask queue (Promise, queueMicrotask) 처리.
핵심: I/O (파일, 네트워크) 는 non-blocking. libuv 가 OS 에 위임 후 완료 시 callback.
비동기 프로그래밍
Callback (초기)
fs.readFile('file.txt', (err, data) => {
if (err) throw err;
console.log(data);
});
Callback hell 문제.
Promise (ES6+)
fs.promises.readFile('file.txt')
.then(data => console.log(data))
.catch(err => console.error(err));
async/await (ES2017+)
try {
const data = await fs.promises.readFile('file.txt');
console.log(data);
} catch (err) {
console.error(err);
}
모던 관용. 자세한 것은 async/await 참조.
모듈 시스템
두 시스템 병존. 자세한 것은 CJS vs ESM 참조.
- CommonJS (레거시):
require/module.exports - ESM (표준):
import/export
Node 22.12+ 는 require(esm) 지원.
표준 모듈
파일 시스템
import { readFile, writeFile } from 'node:fs/promises';
const data = await readFile('/path/to/file', 'utf-8');
await writeFile('/path/out', 'content');
HTTP 서버
import { createServer } from 'node:http';
const server = createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello\n');
});
server.listen(3000);
Streams
import { createReadStream, createWriteStream } from 'node:fs';
import { pipeline } from 'node:stream/promises';
await pipeline(
createReadStream('input.txt'),
createWriteStream('output.txt'),
);
Streams 는 큰 파일 처리에 필수. Backpressure 자동.
Crypto
import { createHash, randomBytes } from 'node:crypto';
const hash = createHash('sha256').update('data').digest('hex');
const token = randomBytes(32).toString('hex');
Path / URL
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const configPath = join(__dirname, 'config.json');
Worker Threads
CPU-bound 작업용. Event loop 를 막지 않기 위해:
import { Worker } from 'node:worker_threads';
const worker = new Worker('./cpu-heavy.js');
worker.postMessage({ data: [...] });
worker.on('message', result => console.log(result));
주의: Node 는 기본 단일 스레드. Worker 는 진짜 thread, 무거운 계산 격리.
Cluster
멀티 프로세스로 CPU 활용 (worker_threads 대안):
import cluster from 'node:cluster';
import os from 'node:os';
if (cluster.isPrimary) {
for (let i = 0; i < os.cpus().length; i++) cluster.fork();
} else {
// server code
}
PM2 가 이 관리를 대신. Kubernetes 는 프로세스 대신 pod.
npm / package.json
의존성 관리:
{
"name": "my-app",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "node src/index.js",
"dev": "node --watch src/index.js",
"test": "node --test"
},
"dependencies": {
"express": "^4.19.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"typescript": "^5.3.0"
}
}
패키지 매니저: npm (기본), pnpm (효율적), yarn, bun.
LTS 정책
Node 는 짝수 버전이 LTS (Long Term Support). 30개월 유지.
- Node 20 (2023-04): LTS
- Node 22 (2024-04): LTS
- Node 24 (2025-04): LTS (예정)
홀수 버전 (21, 23): 짧은 실험. 프로덕션 지양.
최근 개선 (Node 20-22)
- Test runner 내장 (
node --test) - Watch mode (
node --watch) - Permission model (
--permission) fetchglobal (undici 통합)require(esm)stable (22.12+)import.meta.dirname,.filename--env-file(.env 자동 로드)- WebSocket client
Node 가 Deno/Bun 기능을 흡수 중.
대안 런타임
- Bun: Zig, 초고속
- Deno: TS 네이티브, secure by default
- WinterJS, Netlify Edge: Edge 특화
Node 는 여전히 지배적, 하지만 압박 받음.
실전 최적화
Native module
크리티컬 성능은 C++/Rust addon (.node 파일). N-API.
Cluster / Worker
CPU 코어 활용.
Streams
큰 파일/네트워크는 buffer 대신 stream.
Profile
--prof, --inspect (Chrome DevTools).
Memory Leak
Heap snapshot + Chrome DevTools.
함정
WARNING
Blocking sync API 금지 (서버). fs.readFileSync 는 event loop 정지. 항상 async.
CAUTION
CPU-bound 는 worker_threads. Event loop 안 heavy computation 은 다른 요청 지연.
WARNING
Unhandled Promise rejection. Node 는 warning → process.exit (v15+). 반드시 catch.
IMPORTANT
LTS 만 프로덕션. 홀수 버전은 몇 개월 후 EOL.
CAUTION
__dirname in ESM. 없음. import.meta.dirname (Node 20.11+).
관련 위키
- CJS vs ESM
- ES Modules
- Event Loop
- async/await
- Promise
- 번들링
- Bun - 대안
- TypeScript
- NestJS
- Koa.js
- FastAPI - Python 대비
이 글의 용어 (11개)
- [Framework] Koa.jsframeworks
- 정의 Koa.js 는 Express 창시자 TJ Holowaychuk 이 2013년 발표한 Node.js 웹 프레임워크 입니다. Express 의 후계자 성격이며, 미들웨어를 a…
- [Framework] NestJSframeworks
- 정의 NestJS 는 Kamil Myśliwiec 이 2017년 발표한 Node.js 서버측 프레임워크 입니다. TypeScript first, Angular 에서 영감받은 모듈…
- [Javascript] 이벤트 루프javascript
- 정의 이벤트 루프 (Event Loop) 는 싱글 스레드 JavaScript 엔진이 비동기 작업을 처리하기 위해 돌리는 무한 루프다. 콜 스택이 비어있을 때마다 마이크로태스크 큐…
- [Javascript] async/awaitjavascript
- 정의 / 는 기반 비동기 코드를 마치 동기 코드처럼 쓸 수 있게 해주는 ES2017 의 문법 설탕. 본질은 Promise 그 자체, 문법만 다르다. 전체 동작 메커니즘은 글 참조…
- [JavaScript] Bun (Runtime + Bundler)javascript
- 정의 Bun 은 Jarred Sumner 가 2022년 발표한 JavaScript/TypeScript 런타임 + 번들러 + 패키지 매니저 + 테스트 러너 통합 도구입니다. Zig…
- [JavaScript] Bundling (번들링 개요)javascript
- 정의 JavaScript 번들링 (Bundling) 은 여러 소스 파일 (JS, CSS, 이미지, JSON 등) 을 브라우저나 런타임이 효율적으로 실행할 수 있는 최소한의 결과물…
- [JavaScript] CommonJS vs ESM (package.json 설정 완전 정복)javascript
- 정의 JavaScript 는 두 개의 서로 다른 모듈 시스템 을 가집니다. - CommonJS (CJS): Node.js 초기 (2009) 부터 사용. / . 동기 로딩. - E…
- [Javascript] ES Modules (import / export)javascript
- 정의 ES Modules (ESM) 은 표준 JS 모듈 시스템 (ES6). / 키워드. 브라우저와 Node.js 16+ 모두 지원. export named export defau…
- [Javascript] Promisejavascript
- 정의 Promise 는 미래의 어떤 시점에 결정될 값을 나타내는 객체다. ECMAScript 2015 (ES6) 에 도입되어 기반 비동기의 가독성과 에러 처리 문제를 해결했다. …
- [Python] FastAPIfastapi
- 정의 FastAPI 는 Python 3.8+ 을 위한 ASGI 기반 현대 웹/API 프레임워크 입니다. Sebastián Ramírez (tiangolo) 가 2018년 발표했고…
- TypeScripttypescript
- 정의 TypeScript 는 Microsoft 가 2012년 발표한 JavaScript 의 상위 집합 프로그래밍 언어입니다. 정적 타입 시스템, 인터페이스, 제네릭, enum, …
💬 댓글