Node.js 멀티코어 활용: Worker Threads vs Cluster 모듈
문제 상황
대용량 CSV 파싱 및 데이터 변환 API를 개발하던 중 단일 스레드로는 처리 속도가 너무 느렸다. 서버는 8코어였지만 Node.js 프로세스 하나만 100%를 찍으며 나머지 코어는 놀고 있었다.
Cluster 모듈 시도
먼저 익숙한 Cluster 모듈로 접근했다.
const cluster = require('cluster');
const os = require('os');
if (cluster.isMaster) {
const numCPUs = os.cpus().length;
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
require('./server');
}
여러 워커 프로세스가 포트를 공유하며 요청을 분산 처리했다. 동시 요청이 많을 때는 효과적이었지만, 단일 요청 내 무거운 작업은 여전히 느렸다.
Worker Threads로 전환
Node 12부터 안정화된 Worker Threads를 적용했다. 하나의 요청 내에서 작업을 여러 청크로 나눠 병렬 처리했다.
const { Worker } = require('worker_threads');
function processChunk(data) {
return new Promise((resolve, reject) => {
const worker = new Worker('./worker.js', { workerData: data });
worker.on('message', resolve);
worker.on('error', reject);
});
}
const chunks = splitData(largeData, 8);
const results = await Promise.all(chunks.map(processChunk));
단일 요청 처리 시간이 약 60% 단축되었다.
결론
- Cluster: 다중 요청 분산, PM2 같은 프로세스 매니저와 유사
- Worker Threads: 단일 요청 내 CPU 작업 병렬화, 메모리 공유 가능
우리 케이스는 Worker Threads가 적합했다. 다만 워커 생성 비용이 있으니 워커 풀을 만들어 재사용하는 방식으로 개선할 예정이다.