본문 바로가기

Project/Node.js

Node.js의 GC(Garbage Collection)

Node.js에서의 GC와 메모리 전략: 대용량 처리를 위한 구조적 접근

Node.js는 JavaScript 기반의 런타임으로, V8 엔진의 Garbage Collection(GC) 시스템을 사용하여 메모리를 자동으로 관리합니다. 이 GC는 개발자가 직접 메모리를 해제하지 않아도 되게 해주는 강력한 도구지만, 그 내부 구조와 한계를 이해하지 못한 채로 코드를 작성하면 성능 병목, 응답 지연, 더 심각하게는 OOM(Out of Memory) 이슈로 이어질 수 있습니다.

1. GC 구조의 이해: Young & Old Generation

V8의 힙 메모리는 크게 Young Generation과 Old Generation으로 나뉘며, GC는 이 두 영역을 다르게 관리합니다.

  • Young Generation: 짧은 생명주기를 가진 객체가 위치. 빠르고 자주 GC됨
  • Old Generation: Young 영역에서 살아남은 객체가 승격됨. 상대적으로 느리고 무거운 GC가 수행됨 (Mark-Sweep / Mark-Compact).

문제는 메모리 용량이 클수록 GC가 느려진다는 것입니다.
GC는 살아있는 객체를 판단하기 위해 모든 객체 그래프를 스캔하고, 이 과정에서 애플리케이션의 실행을 일시 중단(Stop-the-World)시키기 때문입니다.

메모리를 크게 설정하면 안정적일 것 같지만, 실제로는 GC 비용이 증가해 응답 지연(latency)이 증가하거나 GC pause로 인해 가용성이 떨어질 수 있습니다.

2. 대용량 처리에서의 GC 병목: 구조적 해결이 필요하다

대규모 데이터를 다룰 때 가장 흔한 실수는 데이터를 한 번에 메모리에 올리는 것입니다.

  • CSV 엑셀 다운로드
  • 이미지 또는 대용량 파일 전송
  • 수십만 건의 DB export

이러한 요청을 100명이 동시에 보내면?
단순한 버퍼링만으로도 수십 GB의 메모리가 필요해지며, GC는 살아남은 객체가 많아져 점점 느려지고, 결국 프로세스가 OOM으로 종료될 수 있습니다.

3. 근본적 해결: Stream을 활용한 점진적 처리

Node.js의 Stream은 데이터를 한 덩어리씩 처리할 수 있는 구조로, 대용량 데이터를 안전하게 처리할 수 있는 핵심 전략입니다.

Stream의 장점

  • 메모리에 전체 데이터를 올리지 않는다.
  • 처리 단위를 일정하게 유지하여, 메모리 사용량이 선형적으로 고정된다.
  • 백프레셔(Backpressure)를 통해 수신자 처리속도에 따라 자동 조절된다.

예시: 30GB 파일을 100명이 동시에 다운로드

  • 전체 데이터를 메모리에 올릴 경우: 30GB x 100명 = 3TB
  • Stream 사용 시: 요청당 수 MB ~ 수십 MB만 사용 → 수백 MB ~ 1~2GB 수준으로 처리 가능

4. GC는 문제의 일부일 뿐, 설계가 핵심이다

메모리 문제를 단순히 GC의 한계로 돌려서는 안 됩니다. GC는 동작 방식대로 작동할 뿐, 문제가 생기는 이유는 코드나 시스템 설계가 GC의 작동 원리에 반하기 때문입니다.

좋은 설계를 위한 가이드라인:

  • 불필요한 참조를 제거해 객체가 빠르게 GC될 수 있도록 유도
  • 대용량 데이터는 Stream으로 처리하고, Buffer는 chunk 단위로 관리
  • event loop block을 피하고, 백프레셔나 큐를 통해 처리 흐름 조절
  • GC 로그 분석 (--trace-gc, --inspect)을 통해 메모리 병목 원인을 진단

결론: GC를 이해하고, 구조적으로 설계하라

Node.js에서의 GC는 메모리를 알아서 정리해주는 ‘편리한 기능’이 아니라, 시스템 안정성을 설계할 때 반드시 고려해야 하는 동작 메커니즘입니다.GC 자체를 조정할 수 없다면, 애플리케이션 구조를 GC 친화적으로 설계해야 합니다.

Stream은 그중 하나의 해결책이 아니라, 트래픽이 많고 데이터가 큰 환경에서 서버의 생존 가능성을 확보하기 위한 핵심 전략입니다. GC는 성능의 적이 아니라, 구조 설계의 힌트다. GC가 자주 실행되거나 오래 걸린다면, 지금의 데이터 처리 방식이 적절하지 않다는 신호일 수 있다.