Nest.js를 배워보자/5. NestJS + MySQL 실전 예제 — Excel Import

NestJS + Prisma: 대용량 처리 시 주의점

_Blue_Sky_ 2025. 12. 2. 17:50
728x90

 


엑셀 파일 임포트는 소규모 데이터에서는 문제가 없지만, 수천, 수만 건 이상의 대용량 파일을 처리할 때는 서버의 안정성과 성능을 위해 반드시 추가적인 전략을 고려해야 합니다.

1. 📉 메모리 및 성능 관리

1.1. 메모리 오버플로우 방지 (청크 처리)

  • 문제점: 수만 개의 행을 가진 엑셀 파일을 한 번에 메모리(RAM)에 로드하고 이를 기반으로 대량의 DTO 객체를 생성하는 것은 Node.js의 메모리 제한(기본 약 1.5GB)을 쉽게 초과하여 메모리 오버플로우(OOM)를 일으킬 수 있습니다.
  • 해결책 (청크 분할): xlsx 라이브러리에서 데이터를 파싱할 때 전체 데이터를 한 번에 JSON으로 변환하지 않고, 데이터를 작은 덩어리(Chunk)로 나누어 순차적으로 처리하고 DB에 삽입해야 합니다. 예를 들어, 500개씩 청크를 나누어 처리하고, 다음 청크를 처리하기 전에 이전 청크의 메모리를 해제하는 방식을 사용합니다.
728x90

1.2. HTTP 타임아웃 방지

  • 문제점: 엑셀 파싱 및 DB 삽입 작업은 수십 초 이상 걸릴 수 있습니다. 이 시간 동안 클라이언트와의 HTTP 연결이 끊어지면(Timeout), 클라이언트는 작업의 성공 여부를 알 수 없습니다.
  • 해결책 (즉시 응답): 대용량 작업은 HTTP 요청-응답 사이클에서 분리해야 합니다. 컨트롤러는 파일을 수신하고 즉시 성공 응답(HTTP 202 Accepted)을 클라이언트에게 반환합니다. 실제 DB 저장 작업은 백그라운드에서 비동기적으로 실행되어야 합니다.

2. 📤 비동기 백그라운드 작업으로 분리

대용량 엑셀 처리와 같은 오래 걸리는 작업을 처리하기 위한 NestJS의 일반적인 아키텍처는 다음과 같습니다.

  1. Queue/Scheduler 모듈 사용: NestJS 생태계의 Bull (Redis 기반) 또는 NestJS Schedule 모듈과 같은 도구를 사용하여 파일을 처리하는 작업을 메시지 큐에 넣습니다.
  2. 워커 프로세스: 별도의 워커 프로세스가 메시지 큐에서 작업을 꺼내어 DB 저장을 수행합니다. 이는 HTTP 서버 프로세스의 부하를 분산시키고 안정성을 높입니다.
  3. 상태 알림: 작업이 완료되면, 사용자에게 웹훅(Webhook)이나 이메일/알림을 통해 최종 결과를 통보합니다.
728x90

 

3. 🔍 Prisma createMany의 제약사항

createMany는 성능을 높이지만, 다음과 같은 제약사항이 있습니다.

  • 훅(Hook) 미지원: createMany는 단일 쿼리로 실행되므로, 개별 create 작업 시 발생하는 beforeCreate나 afterCreate와 같은 Prisma 미들웨어 훅을 지원하지 않습니다. 개별 로직 실행이 필요하다면 createMany 대신 청크 단위로 $transaction 내에서 create를 반복해야 합니다.
  • 관계 처리 제약: createMany는 중첩 쓰기(Nested Writes)를 지원하지 않습니다. 즉, 엑셀 데이터를 가져와 Post와 User를 동시에 생성하면서 관계를 맺는 작업은 createMany로는 할 수 없습니다. 이 경우 역시 청크 단위로 $transaction을 사용하여 순차적으로 처리해야 합니다.

핵심 요약: 대용량 파일은 메모리(RAM)HTTP 타임아웃 문제에 대비해야 합니다. 가장 좋은 방법은 비동기 큐 시스템을 도입하여 파일 처리와 DB 삽입을 백그라운드에서 안전하게 처리하는 것입니다.

728x90