EC2 배포 환경을 이해하려고 정리한 PM2 클러스터 모드
입사 초기 프론트엔드 서비스 배포 환경이 EC2와 PM2로 구축되어 있었다.
PM2에 대해 공부하며 리서치한 내용이다.
PM2는 Process Manager의 약자로 NodeJS 프로세서를 관리하는, 원활한 서버 운영을 위한 패키지
- 서비스를 제공하고 있는 도중 갑자기 서버가 중지되어도 서버를 다시 실행
- Node.js는 싱글 스레드 기반이지만, 멀티 코어 혹은 하이퍼 스레딩을 사용할 수 있게 해줌
- 클라이언트로부터 요청이 올 때 알아서 요청을 여러 노드 프로세스에 고르게 분배 (로드 밸런싱)
작동 원리
- PM2의 Cluster mode는 Node.js의 Cluster module을 통해 작동
- Node.js Cluster module은 Node.js에서 멀티코어 시스템을 이용할 수 있도록 Port를 공유하는 Child process를 생성
- 요청을 Parent process가 받은 후 Child process들에 재분배
- 각 Child process는 각각의 V8에서 작동하므로, Node 인스턴스를 더 띄운 것과 같이 동작
- 인메모리에 의존하지 않는 프로그램을 만들면 위와 같은 확장에 더 용이
- Node.js 공식 홈페이지의 Cluster module에 대한 설명
A single instance of Node.js runs in a single thread. To take advantage of multi-core systems, the user will sometimes want to launch a cluster of Node.js processes to handle the load.
>
Node.js의 단일 인스턴스는 단일 스레드에서 실행되는데, 멀티코어 시스템을 이용하기 위해서 Node.js 프로세스들을 클러스터로 사용할 수 있다. 이를 통해 모든 서버 port를 공유하는 하위 프로세스를 생성한다.
The worker processes are spawned using the child_process.fork() method, so that they can communicate with the parent via IPC and pass server handles back and forth.
>
이 하위 프로세스들은 child_process.fork() 메서드를 사용해서 생성되는데, 부모 자식 간의 통신을 위한 IPC(Inter-process communication) 채널을 가지고 있으며 생성된 각 프로세스는 자체 V8인스턴스가 있다.
명령어
pm2 start <파일명>
# pm2를 이용해 앱을 실행한다면 fork 모드(자식 프로세스)로 설정되고,
# 서버 실행 즉시 Daemon화 되어, 종료하거나 에러가 발생하지 않는 이상 24시간 계속 유지된다.
$ pm2 start app.js --watch -i 2 # 프로세스를 watching하고 멀티 코어로 서버 실행
$ pm2 start app.js -i max # 최대 코어 갯수로 클러스터링
$ pm2 start app.js -i 0
$ pm2 scale app +2 # app 프로세스 갯수 +2
$ pm2 scale app 4 # app 프로세스 갯수 4개로 고정
$ pm2 status
$ pm2 ls # status와 ls를 이용해 현재 프로세스 리스트를 띄움
$ pm2 stop <app_name | namespace | id | 'all' | json_conf>
$ pm2 stop 2 # id 2번 프로세스를 멈춤
$ pm2 stop app # 이름을 줘도 됨. (전체 프로세스 멈춤)
$ pm2 restart <app_name | namespace | id | 'all' | json_conf>
$ pm2 restart 2 # 위에서 중지한 2번 프로세스를 재시작
$ pm2 reload <app_name | namespace | id | 'all' | json_conf>
$ pm2 reload app
$ pm2 reload all # 리로드
# - pm2 restart는 모든 프로세스를 죽인다음 다시 시작하는 방식. 그래서 아주 잠깐 동안 서비스를 이용하지 못하는 상황이 생긴다.
# - pm2 reload는 하나씩 프로세스를 죽여서, 최소한 1개 이상의 프로세스를 유지하며 하나씩 재시작 하는 방식이다.
# 그래서 잠깐 재시작 하는 동안 서비스를 이용못하는 상황을 미연에 방지할 수 있다.
# 단,이러한 방식 때문에 reload는 restart보다 재실행 속도가 느리다는 단점이 있다.
$ pm2 delete <app_name | namespace | id | 'all' | json_conf>
$ pm2 delete 2 # 특정 프로세스 삭제
$ pm2 delete app # 프로세스 name이 app인 거 모두 삭제
$ pm2 kill # 프로세스 전체 삭제
$ pm2 log # 전체 프로세스 로그 보기
$ pm2 log [process name | process id] # 특정 프로세스 로그 보기
$ pm2 log --lines 200 # 200줄 까지만 보기
$ pm2 log --err 200 # 에러 로그만 보기
설정 방법
- pm2 설정 파일 만들기 (ecosystem.config.js)
$ pm2 ecosystem # ecosystem.config.js 파일이 생성
# ecosystem.config.js
module.exports = {
/* apps 항목은 우리가 pm2에 사용할 옵션을 기재 */
apps: [
{
name: 'projectName', // app이름
script: './index.js', // 실행할 스크립트 파일
instances: 2, // cpu 코어수 만큼 프로세스 생성 (instance 항목값을 ‘0’으로 설정하면 CPU 코어 수 만큼 프로세스를 생성)
exec_mode: 'cluster', // 클러스터 모드
max_memory_restart: '300M', // 프로세스의 메모리가 300MB에 도달하면 reload 실행
watch: ['bin', 'routes'], //bin폴더, routes폴더를 감시해서 변경사항 실행
ignore_watch: ['node_modules'], // 반대로 해당폴더의 파일변경은 무시
env: {
// 환경변수 지정
Server_PORT: 4000,
NODE_ENV: 'development',
Redis_HOST: 'localhost',
Redis_PORT: 6379,
},
output: '~/logs/pm2/console.log', // 로그 출력 경로 재설정
error: '~/logs/pm2/onsoleError.log', // 에러 로그 출력 경로 재설정
},
],
/* deploy는 원격 서버와 git을 연동해서 배포하는 방식 */
deploy: {
production: {
user: 'SSH_USERNAME',
host: 'SSH_HOSTMACHINE',
ref: 'origin/master',
repo: 'GIT_REPOSITORY',
path: 'DESTINATION_PATH',
'pre-deploy-local': '',
'post-deploy': 'npm install && pm2 reload ecosystem.config.js --env production',
'pre-setup': '',
},
},
};
$ pm2 start ecosystem.config.js # 설정 파일을 start하면, 세팅대로 pm2 명령어가 실행
