본문 바로가기
Backend2026년 1월 12일7분 읽기

Node.js 클러스터 모드와 PM2 프로덕션 최적화

YS
김영삼
조회 526

Node.js 클러스터 모드

Node.js는 기본적으로 단일 스레드로 동작합니다. 멀티코어 CPU를 활용하려면 클러스터 모듈을 사용하여 여러 워커 프로세스를 생성해야 합니다.

네이티브 클러스터 모듈

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isPrimary) {
  console.log(`Primary ${process.pid} is running`);
  console.log(`CPU cores: ${numCPUs}`);

  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died (${signal || code})`);
    console.log('Starting a new worker...');
    cluster.fork();
  });

  for (const id in cluster.workers) {
    cluster.workers[id].on('message', (msg) => {
      console.log(`Message from worker ${id}: ${msg}`);
    });
  }
} else {
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Worker ${process.pid} handled this request
`);
  }).listen(3000);

  console.log(`Worker ${process.pid} started`);
}

PM2 기본 사용법

# PM2 설치
npm install -g pm2

# 클러스터 모드로 실행
pm2 start app.js -i max --name my-app

# 주요 명령어
pm2 list              # 프로세스 목록
pm2 monit             # 실시간 모니터링
pm2 logs my-app       # 로그 확인
pm2 restart my-app    # 재시작
pm2 reload my-app     # 무중단 리로드
pm2 stop my-app       # 중지
pm2 delete my-app     # 삭제

PM2 Ecosystem 설정 파일

// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'my-app',
    script: './dist/server.js',
    instances: 'max',
    exec_mode: 'cluster',
    max_memory_restart: '1G',

    env: {
      NODE_ENV: 'development',
      PORT: 3000
    },
    env_production: {
      NODE_ENV: 'production',
      PORT: 8080
    },

    log_file: '/var/log/pm2/combined.log',
    error_file: '/var/log/pm2/error.log',
    out_file: '/var/log/pm2/out.log',
    log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
    merge_logs: true,

    listen_timeout: 8000,
    kill_timeout: 5000,
    wait_ready: true,

    watch: false,
    max_restarts: 10,
    restart_delay: 4000,
    autorestart: true,

    shutdown_with_message: true
  }]
};

Graceful Shutdown 구현

const server = require('http').createServer(app);

server.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
  if (process.send) {
    process.send('ready');
  }
});

process.on('SIGINT', gracefulShutdown);
process.on('SIGTERM', gracefulShutdown);

async function gracefulShutdown(signal) {
  console.log(`${signal} received. Graceful shutdown...`);

  server.close(async () => {
    await database.disconnect();
    await redis.quit();
    console.log('Process terminated gracefully');
    process.exit(0);
  });

  setTimeout(() => {
    console.error('Forced shutdown after timeout');
    process.exit(1);
  }, 10000);
}

PM2 모니터링 및 배포

기능명령어설명
모니터링pm2 monitCPU/메모리 실시간 모니터링
스타트업pm2 startup시스템 부팅 시 자동 실행
저장pm2 save현재 프로세스 목록 저장
배포pm2 deploy원격 서버 배포 자동화
키메트릭pm2 plus웹 기반 모니터링 대시보드
  • pm2 reload는 새 워커를 먼저 시작하고 이전 워커를 종료하므로 무중단 배포 가능
  • max_memory_restart로 메모리 누수 시 자동 재시작
  • pm2 startup으로 서버 재부팅 시에도 자동 복구
  • 프로덕션에서는 반드시 Graceful Shutdown을 구현하여 요청 손실 방지

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록