Node.js 멀티코어 활용을 위한 Cluster 모듈 적용기

문제 상황

운영 중인 Express API 서버의 모니터링 결과, CPU 사용률이 최대 25%를 넘지 못했다. 4코어 EC2 인스턴스였는데 실제로는 1코어만 사용하고 있었다. Node.js는 단일 스레드 기반이라 멀티코어를 자동으로 활용하지 못한다.

트래픽이 증가하면서 응답 속도가 느려지기 시작했고, 스케일 아웃 전에 현재 서버 자원을 제대로 활용하는 방법을 찾아야 했다.

Cluster 모듈 적용

Node.js 내장 Cluster 모듈을 사용하면 마스터 프로세스가 워커 프로세스들을 생성하고 관리할 수 있다.

const cluster = require('cluster');
const os = require('os');

if (cluster.isMaster) {
  const numCPUs = os.cpus().length;
  console.log(`Master process ${process.pid} is running`);
  
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
  
  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died. Restarting...`);
    cluster.fork();
  });
} else {
  require('./app');
  console.log(`Worker ${process.pid} started`);
}

기존 app.js를 그대로 두고 server.js만 추가했다. 마스터는 워커를 생성하고, 워커가 죽으면 자동으로 재시작한다.

결과

적용 후 동일한 부하 테스트에서 CPU 사용률이 85%까지 올라갔고, 처리량은 약 3.5배 증가했다. 응답 시간도 평균 200ms에서 80ms로 개선됐다.

한 가지 주의할 점은 워커 간 메모리를 공유하지 않는다는 것이다. 세션 같은 상태 관리가 필요하면 Redis 같은 외부 저장소를 사용해야 한다. 우리는 이미 JWT를 쓰고 있어서 문제없었다.

PM2 같은 프로세스 매니저를 쓰는 방법도 있지만, 일단 내장 모듈로 해결했다. 나중에 무중단 배포가 필요해지면 PM2를 고려할 예정이다.