Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

프론트엔드 next.js 환경에서 메모리를 최적화 하기 위한 방법 #8

Open
yuiseo opened this issue Oct 31, 2024 · 0 comments
Assignees
Labels
프론트엔드 질문 리스트의 직무 구분을 위한 라벨 💡 질문 리스트 직무 관련 궁금증과 해결이 필요한 질문들

Comments

@yuiseo
Copy link
Member

yuiseo commented Oct 31, 2024

📝 프론트엔드 next.js 환경에서 메모리를 최적화 하기 위한 방법

📚 주제:
node 환경의 메모리 최적화를 위한 방법을 탐구한다.

📚 탐구 내용:
현재 메모리 사용량을 확인하기 위해서는 server를 커스텀 하여 확인할 수 있다.
메모리 사용량을 알아내는 방법은 GPT의 도움을 받아 process.memoryUsage()를 통해 알 수 있다는 것을 확인했다.


1. process.memoryUsage의 중요 요소

image
image
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 메모리 로그

image
이전에 dev모드로 서버 start할 때와 다르게 heap 메모리 사용량이 1/15 이상 감소한 것도 확인할 수 있었다.


5. --optimize-for-size 설정 차이

설정전

image

설정후

image

--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

@yuiseo yuiseo added 💡 질문 리스트 직무 관련 궁금증과 해결이 필요한 질문들 프론트엔드 질문 리스트의 직무 구분을 위한 라벨 labels Oct 31, 2024
@suna-ji suna-ji added this to the 11월 2주차 (11/12 화) milestone Nov 4, 2024
@yuiseo yuiseo removed this from the 11월 2주차 (11/12 화) milestone Nov 10, 2024
@yuiseo yuiseo self-assigned this Dec 15, 2024
@yuiseo yuiseo added this to the 7주차(12/16 월) milestone Dec 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
프론트엔드 질문 리스트의 직무 구분을 위한 라벨 💡 질문 리스트 직무 관련 궁금증과 해결이 필요한 질문들
Projects
None yet
Development

No branches or pull requests

2 participants