๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

DevOps

PM2 Research

์ž…์‚ฌ ์ดˆ๊ธฐ ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋น„์Šค ๋ฐฐํฌ ํ™˜๊ฒฝ์ด EC2์™€ PM2๋กœ ๊ตฌ์ถ•๋˜์–ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

PM2์— ๋Œ€ํ•ด ๊ณต๋ถ€ํ•˜๋ฉฐ ๋ฆฌ์„œ์น˜ํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

PM2๋Š” Process Manager์˜ ์•ฝ์ž๋กœ NodeJS ํ”„๋กœ์„ธ์„œ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š”, ์›ํ™œํ•œ ์„œ๋ฒ„ ์šด์˜์„ ์œ„ํ•œ ํŒจํ‚ค์ง€
  • ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋Š” ๋„์ค‘ ๊ฐ‘์ž๊ธฐ ์„œ๋ฒ„๊ฐ€ ์ค‘์ง€๋˜์–ด๋„ ์„œ๋ฒ„๋ฅผ ๋‹ค์‹œ ์‹คํ–‰
  • Node.js๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ๊ธฐ๋ฐ˜์ด์ง€๋งŒ, ๋ฉ€ํ‹ฐ ์ฝ”์–ด ํ˜น์€ ํ•˜์ดํผ ์Šค๋ ˆ๋”ฉ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ
  • ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ์š”์ฒญ์ด ์˜ฌ ๋•Œ ์•Œ์•„์„œ ์š”์ฒญ์„ ์—ฌ๋Ÿฌ ๋…ธ๋“œ ํ”„๋กœ์„ธ์Šค์— ๊ณ ๋ฅด๊ฒŒ ๋ถ„๋ฐฐ (๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ)

์ž‘๋™ ์›๋ฆฌ

  1. PM2์˜ Cluster mode๋Š” Node.js์˜ Cluster module์„ ํ†ตํ•ด ์ž‘๋™
  2. Node.js Cluster module์€ Node.js์—์„œ ๋ฉ€ํ‹ฐ์ฝ”์–ด ์‹œ์Šคํ…œ์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก Port๋ฅผ ๊ณต์œ ํ•˜๋Š” Child process๋ฅผ ์ƒ์„ฑ
  3. ์š”์ฒญ์„ Parent process๊ฐ€ ๋ฐ›์€ ํ›„ Child process๋“ค์— ์žฌ๋ถ„๋ฐฐ
  4. ๊ฐ Child process๋Š” ๊ฐ๊ฐ์˜ V8์—์„œ ์ž‘๋™ํ•˜๋ฏ€๋กœ, Node ์ธ์Šคํ„ด์Šค๋ฅผ ๋” ๋„์šด ๊ฒƒ๊ณผ ๊ฐ™์ด ๋™์ž‘
  5. ์ธ๋ฉ”๋ชจ๋ฆฌ์— ์˜์กดํ•˜์ง€ ์•Š๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค๋ฉด ์œ„์™€ ๊ฐ™์€ ํ™•์žฅ์— ๋” ์šฉ์ด
  • 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 ๋ช…๋ น์–ด๊ฐ€ ์‹คํ–‰

 

 

  • references:
 

PM2์˜ Cluster mode๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ• ๊นŒ์š”?

์•ˆ๋…•ํ•˜์„ธ์š”. ์˜ค๋Š˜์€ PM2์˜ Cluster mode์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋จผ์ € PM2๊ฐ€ ๋ฌด์—‡์ผ๊นŒ์š”? PM2๋Š” Node.js ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ”„๋กœ์„ธ์Šค ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋ฉฐ, ์•„๋ž˜์™€ ๊ฐ™์€ ์ด์ ์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ๊ทธ

short-term.tistory.com

 

 

[NODE] ๐Ÿ“š PM2 ๋ชจ๋“ˆ ์‚ฌ์šฉ๋ฒ• - ํด๋Ÿฌ์Šคํ„ฐ / ๋ฌด์ค‘๋‹จ ์„œ๋น„์Šค

Node.js ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ Node.js๋Š” Chrome์˜ V8 ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์œผ๋กœ ๋นŒ๋“œ๋œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋Ÿฐํƒ€์ž„(runtime)์œผ๋กœ ‘Event Driven’, ‘Non-Blocking I/O’ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•ด ๊ฐ€๋ณ๊ณ  ์„ฑ๋Šฅ์ด ๋›ฐ์–ด๋‚˜ ๋†’์€ ํ‰๊ฐ€๋ฅผ ๋ฐ›๊ณ  ์žˆ

inpa.tistory.com

 

'DevOps' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

CDN (Content Delivery Network)  (2) 2025.01.05
๋ฌด์ค‘๋‹จ ๋ฐฐํฌ (Zero Downtime Deployment)  (3) 2025.01.05