Node.js 프로젝트에서 PM2로 무중단 배포 구성하기
문제 상황
운영 중인 Node.js API 서버를 배포할 때마다 pm2 restart 명령으로 재시작하고 있었다. 문제는 재시작 중 몇 초간 서비스가 중단되면서 클라이언트에서 502 에러가 발생한다는 것이었다.
PM2 Cluster Mode
PM2는 클러스터 모드로 여러 인스턴스를 실행할 수 있다. CPU 코어 수만큼 프로세스를 띄워 부하 분산도 가능하다.
// ecosystem.config.js
module.exports = {
apps: [{
name: 'api-server',
script: './app.js',
instances: 'max',
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 3000
}
}]
};
Reload vs Restart
핵심은 restart 대신 reload 명령을 사용하는 것이다.
# 기존 방식 - 모든 프로세스 동시 재시작
pm2 restart api-server
# 개선 방식 - 하나씩 순차적으로 재시작
pm2 reload api-server
reload는 클러스터 모드에서 프로세스를 하나씩 재시작한다. 한 인스턴스가 종료되고 새 버전이 시작될 때 다른 인스턴스들이 요청을 처리하므로 중단 시간이 없다.
Graceful Shutdown
애플리케이션 코드에서도 SIGINT 시그널을 처리해 진행 중인 요청을 완료한 후 종료되도록 했다.
const server = app.listen(3000);
process.on('SIGINT', () => {
console.log('Received SIGINT, shutting down gracefully');
server.close(() => {
console.log('Server closed');
process.exit(0);
});
});
배포 스크립트
최종적으로 배포 스크립트는 다음과 같이 구성했다.
#!/bin/bash
git pull origin master
npm install --production
pm2 reload ecosystem.config.js
결과
배포 중에도 API 응답이 끊기지 않게 되었다. 모니터링 결과 배포 시점에 에러율 증가도 관찰되지 않았다. 단순한 설정 변경만으로 큰 개선을 얻을 수 있었다.