๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
  • What would life be If we had no courage to attemp anything?
Development/Next.js

[Next.js] node.js ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ํ™•์ธ๊ณผ heap ๋ฉ”๋ชจ๋ฆฌ ์ œํ•œ ์ ์šฉํ•˜๊ธฐ

by DevIseo 2024. 12. 23.

node.js ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ํ™•์ธ๊ณผ heap ๋ฉ”๋ชจ๋ฆฌ ์ œํ•œ ์ ์šฉํ•˜๊ธฐ

ํ˜„์žฌ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” next.js์—์„œ server๋ฅผ ์ปค์Šคํ…€ ํ•˜์—ฌ ๋กœ๊ทธ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ์•Œ์•„๋‚ด๋Š” ๋ฐฉ๋ฒ•์€ GPT์˜ ๋„์›€์„ ๋ฐ›์•„ process.memoryUsage()๋ฅผ ํ†ตํ•ด ์•Œ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค.

 

1. process.memoryUsage์˜ ์ค‘์š” ์š”์†Œ

Node.js(Next.js) ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ชจ๋‹ˆํ„ฐ๋ง์„ ์œ„ํ•œ ๋ฉ”๋ชจ๋ฆฌ ์ธ์‚ฌ์ดํŠธ / if(kakaoAI)2024
ํ•ด๋‹น ์ปจํผ๋Ÿฐ์Šค ๋‚ด์šฉ์ด ๋‚ด๊ฐ€ ๊ณ ๋ฏผํ•˜๊ณ  ์žˆ๋Š” ๊ฐœ๋…์ ์ธ ๋ถ€๋ถ„์„ ๋‹ค๋ค„์ฃผ๊ณ  ์žˆ์—ˆ๋‹ค.

 

1-1. ์ฝ”๋“œ ์ ์šฉ

// server.js
const { createServer } = require('http');
const { parse } = require('url');
const next = require('next');

const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();

app.prepare().then(() => {
  const server = createServer((req, res) => {
    const parsedUrl = parse(req.url, true);
    handle(req, res, parsedUrl);
  });

  // ๋ฉ”๋ชจ๋ฆฌ ๋กœ๊น…
  function logMemoryUsage() {
    const memoryUsage = process.memoryUsage();
    console.log(`RSS: ${memoryUsage.rss / 1024 / 1024} MB`);
    console.log(`Heap Total: ${memoryUsage.heapTotal / 1024 / 1024} MB`);
    console.log(`Heap Used: ${memoryUsage.heapUsed / 1024 / 1024} MB`);
    console.log(`External: ${memoryUsage.external / 1024 / 1024} MB`);
  }

  setInterval(logMemoryUsage, 5000);
});
 

์ปค์Šคํ…€ํ•œ server๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„๋ฅผ ์‹œ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” package.json์˜ script๋ฅผ node๋ฅผ ํ†ตํ•ด ์‹คํ–‰์‹œ์ผœ์•ผ ํ•œ๋‹ค.

{
  "scripts": {
    "start": "node server.js",
  },

 

2. heap ๋ฉ”๋ชจ๋ฆฌ ์ œํ•œ

package.json์˜ script์‹คํ–‰ ์‹œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด heap ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ œํ•œํ•˜์—ฌ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

{
  "scripts": {
    "start": "node --max-old-space-size=4096 server.js"
  }
}
 

ํ•ด๋‹น ๋ช…๋ น์–ด๋กœ ์„œ๋ฒ„ start์‹œ server.js์—์„œ ์ž‘์„ฑํ•œ console.log๋ฅผ ํ†ตํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋กœ๊ทธ๊ฐ€ ์ฐํžˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

RSS: 6878.95703125 MB
Heap Total: 3646.2421875 MB
Heap Used: 3577.541633605957 MB
External: 2535.8189821243286 MB
RSS: 6878.97265625 MB
Heap Total: 3646.2421875 MB
Heap Used: 3577.559700012207 MB
External: 2535.819083213806 MB
RSS: 7877.37109375 MB
Heap Total: 3597.78515625 MB
Heap Used: 3515.6298904418945 MB
External: 3877.6123657226562 MB
 

๊ทธ๋Ÿฌ๋‚˜ --max-old-space-size ๋Š” ํž™ ๋ฉ”๋ชจ๋ฆฌ ์— ๋Œ€ํ•œ ์ตœ๋Œ€ ํฌ๊ธฐ๋ฅผ ์„ค์ •ํ•  ๋ฟ, ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์—๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•œ๋‹ค.

ํ•ด๋‹น ๋กœ๊ทธ์—์„œ RSS ๋Š” Resident Set Size ์•ฝ์ž๋กœ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ์ด๋‹ค. ์—ฌ๊ธฐ์—๋Š” ํž™ ๋ฉ”๋ชจ๋ฆฌ ์™ธ์—๋„ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ๋“ค์ด ํฌํ•จ๋œ๋‹ค.

  • External Memory: V8 ์—”์ง„ ์™ธ๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ (e.g., ๋ฒ„ํผ, C++ ํ™•์žฅ ๋“ฑ)
  • Code Segment: ์ฝ”๋“œ ์‹คํ–‰์„ ์œ„ํ•œ ๋ฉ”๋ชจ๋ฆฌ
  • Stack Memory: ํ•จ์ˆ˜ ํ˜ธ์ถœ ์Šคํƒ ๋ฉ”๋ชจ๋ฆฌ

๋”ฐ๋ผ์„œ, --max-old-space-size๋กœ ์ œํ•œ๋œ ๊ฒƒ์€ ํž™ ๋ฉ”๋ชจ๋ฆฌ๋งŒ์ด๋ฏ€๋กœ, ํž™ ์™ธ๋ถ€ ๋ฉ”๋ชจ๋ฆฌ(External, Code, Stack)๋Š” ์ œํ•œ๋˜์ง€ ์•Š๋Š”๋‹ค.

์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ œํ•œํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Node.js ์ž์ฒด๊ฐ€ ์•„๋‹Œ, ์‹คํ–‰ ํ™˜๊ฒฝ์ด๋‚˜ ์šด์˜ ์ฒด์ œ์—์„œ ๋ฉ”๋ชจ๋ฆฌ ์ œํ•œ์„ ์„ค์ • ํ•ด์•ผ ํ•œ๋‹ค.

 

3. node server ํ™˜๊ฒฝ ์„ค์ •

๐Ÿ”ฅ Trouble Shooting
๋˜ํ•œ, ์œ„์˜ script๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด build ํ›„ start ์‹คํ–‰ ์‹œ dev๋ชจ๋“œ๋กœ ์„œ๋ฒ„๊ฐ€ ์ผœ์ง€๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค. (์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋กœ๊ทธ๋“ค๋„ dev๋ชจ๋“œ์˜ ๋กœ๊ทธ์ž„์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.)

์ด์ „์— start ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰ ์‹œ node server.js๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„๋ฅผ ์ผœ๋„๋ก ์„ค์ • ํ›„ ์ธํ”„๋ผ ํ™˜๊ฒฝ์— ์…‹ํŒ…ํ–ˆ์„ ๋•Œ OOM์ด ๋‚œ ์ด์œ ๋Š” ๊ธฐ๋ณธ heap ํฌ๊ธฐ ์„ค์ •์ด 2GB์—ฌ์„œ ์˜€๋‹ค. dev ๋ชจ๋“œ๋กœ ์„œ๋ฒ„๊ฐ€ ์ผœ์ง€๊ฒŒ ๋˜๋ฉด ์ตœ์ ํ™”๊ฐ€ ๋˜์ง€ ์•Š์€ ์ƒํƒœ๋ผ ํž™ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๊ทธ ์ด์ƒ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด ๋ฐœ์ƒํ•œ ๋ฌธ์ œ๋กœ ๋ณด์ธ๋‹ค.

 

๐Ÿง‘‍๐Ÿš’ Problem Solving
์šฐ๋ฆฌ๋Š” build ํ›„ production ํ™˜๊ฒฝ์œผ๋กœ ์ปค์Šคํ…€ ํ•œ ์„œ๋ฒ„ ์‹คํ–‰ํ•ด์•ผ ํ•œ๋‹ค.
๋”ฐ๋ผ์„œ, script์—์„œ production ๋ชจ๋“œ๋กœ ์„œ๋ฒ„๊ฐ€ ์ผœ์งˆ ์ˆ˜ ์žˆ๊ฒŒ ์„ค์ •ํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.
production ๋ชจ๋“œ๋กœ ์‹คํ–‰์‹œํ‚ค๊ณ ์ž ํ•œ๋‹ค๋ฉด script์—์„œ NODE_ENV๋ฅผ ๋ช…์‹œํ•ด์ค˜์•ผ ํ•œ๋‹ค.

 

// package.json
"scripts": {
  "build": "yarn next build",
  "start": "NODE_ENV=production node --max-old-space-size=3072 --max-semi-space-size=64 --optimize-for-size --trace-gc server.js"
}
## ERROR LOG
$ yarn run start
yarn run v1.22.19
$ NODE_ENV=production node --max-old-space-size=3072  --max-semi-space-size=64 --optimize-for-size --trace-gc server.js
'NODE_ENV' is not recognized as an internal or external command,
operable program or batch file.
 

NODE_ENV๋ฅผ ์ธ์‹ํ•  ์ˆ˜ ์—†์Œ์„ ๋‚˜ํƒ€๋‚ด๋Š” ๋กœ๊ทธ๊ฐ€ ๋‚˜์™”๋‹ค. (๋‚˜์˜ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์€ ์œˆ๋„์šฐ์˜€๋‹ค!)

 


 

๐Ÿ”ฅ Trouble Shooting
๊ทธ๋Ÿฌ๋‚˜ ํ•ด๋‹น script๋กœ ์‹คํ–‰ ์‹œ Windows ํ™˜๊ฒฝ์—์„œ๋Š” NODE_ENV๋ฅผ ์ธ์‹ํ•  ์ˆ˜ ์—†์—ˆ๋‹ค.

๐Ÿง‘‍๐Ÿš’ Problem Solving
๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ๋Š” Windows์™€ Linux ํ™˜๊ฒฝ์— ๋Œ€ํ•œ Cross-env ์„ค์ •์ด ํ•„์š”ํ•˜๋‹ค.

## cross-env ์˜์กด์„ฑ ์ถ”๊ฐ€
yarn add cross-env
 
## cross-env๋ฅผ ํ†ตํ•œ node ํ™˜๊ฒฝ ์„ค์ •
"scripts": {
  "build": "yarn next build",
  "start": "cross-env NODE_ENV=production node --optimize-for-size --trace-gc server.js"
}

 

 

4. production๋ชจ๋“œ๋กœ ์‹คํ–‰ ์‹œ heap ๋ฉ”๋ชจ๋ฆฌ ๋กœ๊ทธ

์ด์ „์— dev๋ชจ๋“œ๋กœ ์„œ๋ฒ„ startํ•  ๋•Œ์™€ ๋‹ค๋ฅด๊ฒŒ heap ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด 1/15 ์ด์ƒ ๊ฐ์†Œํ•œ ๊ฒƒ๋„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

5. --optimize-for-size ์„ค์ • ์ฐจ์ด

์„ค์ • ์ „ ์„ค์ • ํ›„

--optimize-for-size ์„ค์ •์„ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋˜๋ฉด ์„ค์ • ์ „๋ณด๋‹ค heap ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๊ฐ์†Œํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค.

 

โ“ ๊ถ๊ธˆํ•ด์„œ ๋” ์ฐพ์•„๋ณธ ๊ฒƒ

๊ธฐ์กด “next start”์™€ ํ•ด๋‹น ์Šคํฌ๋ฆฝํŠธ๋Š” ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ์„๊นŒ?

  • next start vs node server.js ์ฐจ์ด์ 
ํŠน์ง• next start node server.js(์ปค์Šคํ…€ ์„œ๋ฒ„)
์„ค์ • ๊ฐ„์†Œํ™” Next.js ๊ธฐ๋ณธ ์ œ๊ณต ๊ธฐ๋Šฅ์œผ๋กœ ๊ฐ„๋‹จํžˆ ์‹คํ–‰ ๊ฐ€๋Šฅ ์„œ๋ฒ„ ๋กœ์ง ์ถ”๊ฐ€๋กœ ์„ค์ • ๋ณต์žก๋„ ์ฆ๊ฐ€
์œ ์—ฐ์„ฑ ๊ธฐ๋ณธ ์„œ๋ฒ„๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ HTTP ์š”์ฒญ ์ฒ˜๋ฆฌ, API ํ”„๋ก์‹œ ๋“ฑ ์œ ์—ฐ
์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ธฐ๋ณธ ์„ค์ •์œผ๋กœ ์ตœ์ ํ™” ์ง์ ‘ ์ตœ์ ํ™” ๊ฐ€๋Šฅ (e.g., ์บ์‹ฑ ๋กœ์ง)
๋ฉ”๋ชจ๋ฆฌ ์„ค์ • ์ œ์–ด NODE_OPTIONS๋กœ ๊ฐ„์ ‘ ์„ค์ • node ํ”Œ๋ž˜๊ทธ๋กœ ์ง์ ‘ ์„ค์ • ๊ฐ€๋Šฅ

next start

  • ๋‚ด์žฅ๋œ Next.js ์„œ๋ฒ„ ์‚ฌ์šฉ:
    • Next.js๊ฐ€ ๊ธฐ๋ณธ ์ œ๊ณตํ•˜๋Š” ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.
    • ์ปค์Šคํ…€ ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ง์ ‘ ์„œ๋ฒ„๋ฅผ ์ œ์–ดํ•  ์ˆ˜๋Š” ์—†๋‹ค.
  • ๊ฐ„๋‹จํ•œ ๋ฐฐํฌ:
    • Next.js๋กœ ์ƒ์„ฑ๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๋Š” ๊ฐ€์žฅ ํ‘œ์ค€์ ์ธ ๋ฐฉ๋ฒ•์ด๋‹ค.
  • ๋ฉ”๋ชจ๋ฆฌ ์„ค์ •:
    • next start ์ž์ฒด๋กœ๋Š” Node.js ์‹คํ–‰ ํ™˜๊ฒฝ์„ ์ง์ ‘ ์„ค์ •ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—, ๋ฉ”๋ชจ๋ฆฌ ์ œํ•œ ๋“ฑ Node.js ์˜ต์…˜์„ ์ œ์–ดํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช…๋ น์–ด๋กœ ์‹คํ–‰ํ•ด์•ผ ํ•œ๋‹ค.
    NODE_OPTIONS="--max-old-space-size=4096" next start
    
     

node server.js

  • ์ปค์Šคํ…€ ์„œ๋ฒ„:
    • Next.js์˜ next() ์ธ์Šคํ„ด์Šค๋ฅผ ํ™œ์šฉํ•ด HTTP ์„œ๋ฒ„๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•˜๊ณ , ์ถ”๊ฐ€ ๋กœ์ง์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ํŠน์ • API ํ”„๋ก์‹œ ์ฒ˜๋ฆฌ, ์ปค์Šคํ…€ ํ—ค๋” ์„ค์ • ๋“ฑ Next.js ๊ธฐ๋ณธ ์„œ๋ฒ„์—์„œ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์œ ์—ฐ์„ฑ:
    • HTTP ์š”์ฒญ์„ ์ง์ ‘ ์ œ์–ดํ•˜๊ฑฐ๋‚˜ ๋‹ค์–‘ํ•œ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค.
  • ๋ฉ”๋ชจ๋ฆฌ ์„ค์ •:
    • ์ปค์Šคํ…€ ์„œ๋ฒ„๋Š” Node.js ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰๋˜๋ฏ€๋กœ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ์„ค์ •์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.
    node --max-old-space-size=4096 server.js
    
     

 


๐Ÿ’ก ์ฐธ๊ณ  ์ž๋ฃŒ:

https://www.youtube.com/watch?v=p2YFSJaoWWU

https://blog.eunsukim.me/posts/debugging-javascript-memory-leak-with-chrome-devtools

https://yozm.wishket.com/magazine/detail/2504/

https://medium.com/@623easyoon/study-experience-front-performance-%EC%B8%A1%EC%A0%95-%EB%B0%8F-%EA%B0%9C%EC%84%A0-90c6974c8b27

๋Œ“๊ธ€