Quick Reference
import cluster from "node:cluster";
import http from "node:http";
import { availableParallelism } from "node:os";
if (cluster.isPrimary) {
const restartTimes = [];
const canRestart = () => {
const now = Date.now();
while (restartTimes[0] < now - 60_000) restartTimes.shift();
if (restartTimes.length >= 5) return false;
restartTimes.push(now);
return true;
};
for (let i = 0; i < availableParallelism(); i++) {
cluster.fork();
}
cluster.on("exit", (worker, code, signal) => {
console.error(`worker ${worker.process.pid} exited`, { code, signal });
if (!worker.exitedAfterDisconnect && canRestart()) cluster.fork();
});
} else {
http.createServer((req, res) => {
res.end(`worker ${process.pid}`);
}).listen(3000);
}여러 Node 프로세스를 격리한 채 같은 서버 포트를 공유해야 할 때만 cluster를 씁니다. 한 프로세스 안에서 CPU 계산을 분리할 목적이면 worker_threads가 맞습니다. worker 메모리는 공유되지 않으므로 세션과 캐시는 외부 저장소에 두고, 재시작은 crash loop 제한과 종료 절차까지 운영 코드로 관리합니다.
프로세스 분산
먼저 머릿속에 넣어둘 기본형은 아래입니다.
- primary에서
cluster.fork() - worker 종료 감시:
cluster.on("exit", ...) - 의도적 종료 구분:
worker.exitedAfterDisconnect - HTTP 서버 멀티코어 확장:
cluster - CPU 계산 병렬화:
worker_threads
목적이 "HTTP 서버 수평 확장"이면 cluster
동일한 서버 프로세스를 코어 수만큼 띄워 요청을 나눠 처리하려는 목적이라면 cluster가 맞습니다. 프로세스가 분리되므로 한 worker 문제가 다른 worker로 덜 번집니다.
목적이 "한 프로세스 안 CPU 계산 병렬화"면 worker_threads
같은 앱 안에서 계산만 분리하고 싶고, 메모리 공유나 더 낮은 생성 비용이 중요하다면 worker_threads가 더 맞습니다.
운영에서는 재시작과 종료가 핵심이다
cluster 카드는 포크 문법보다 worker가 죽었을 때 어떻게 복구할지, 배포 중 어떻게 교체할지가 더 중요합니다. 위 예제처럼 무조건 다시 fork하면 장애 코드가 무한히 재시작될 수 있으므로, 운영 환경에서는 시간 창당 재시작 횟수와 종료 상태를 따로 관리해야 합니다.
상태 공유는 자동이 아니라 외부화가 기본이다
프로세스가 나뉘면 메모리도 나뉩니다. Node는 worker 수를 자동으로 유지하거나 애플리케이션 상태를 동기화하지 않습니다. 세션, 캐시, rate limit 같은 상태를 프로세스 메모리에만 두면 worker마다 따로 놀 수 있으니, 실제 운영에서는 Redis나 외부 저장소를 같이 떠올리는 편이 맞습니다.
언제 cluster를 쓸까
체크포인트
- HTTP 서버 멀티코어 확장:
cluster - CPU 계산 병렬화:
worker_threads - 메모리 공유 필요:
worker_threads - 프로세스 격리 우선:
cluster - 비정상 종료 복구:
cluster.on("exit") - 의도적 종료 구분:
worker.exitedAfterDisconnect - 프로세스 간 상태는 외부 저장소 기준으로 설계
주의할 점
cluster.fork()는 현재 엔트리 파일을 다시 실행한다. cluster.isPrimary 분기 없이 쓰면 worker까지 계속 fork해서 프로세스가 폭증한다.
참고 링크
1 sources