Node.js 스트림으로 대용량 CSV 파일 처리하기

문제 상황

고객사에서 제공한 700MB CSV 파일을 파싱해서 DB에 넣는 작업을 진행하던 중 JavaScript heap out of memory 에러가 발생했다. 기존 코드는 fs.readFileSync로 전체 파일을 메모리에 올린 후 처리하는 방식이었다.

해결 방법

스트림을 사용해 파일을 청크 단위로 읽으면서 처리하도록 변경했다.

const fs = require('fs');
const readline = require('readline');
const { promisify } = require('util');

async function processCSV(filePath) {
  const fileStream = fs.createReadStream(filePath);
  const rl = readline.createInterface({
    input: fileStream,
    crlfDelay: Infinity
  });

  let batch = [];
  const BATCH_SIZE = 1000;

  for await (const line of rl) {
    const parsed = parseLine(line);
    batch.push(parsed);

    if (batch.length >= BATCH_SIZE) {
      await insertBatch(batch);
      batch = [];
    }
  }

  if (batch.length > 0) {
    await insertBatch(batch);
  }
}

성능 개선

  • 메모리 사용량: 1.2GB → 150MB
  • 처리 시간: OOM으로 실패 → 약 3분 소요
  • 배치 단위로 DB 삽입해서 커넥션 효율도 개선

추가 고려사항

csv-parser 같은 라이브러리를 쓰면 더 편하지만, 의존성을 최소화하고 싶어서 직접 구현했다. 나중에 복잡한 CSV 처리가 필요하면 라이브러리 도입을 검토할 예정이다.

스트림 에러 핸들링도 추가해야 하는데, fileStream.on('error') 같은 이벤트 리스너를 붙여서 처리하면 된다.