Node.js 스트림으로 대용량 CSV 파일 처리 최적화

문제 상황

외부 시스템에서 받은 100GB짜리 CSV 파일을 파싱해서 DB에 저장하는 작업이 필요했다. 초기 구현은 단순하게 fs.readFile로 전체 파일을 읽고 처리했는데, 당연히 메모리 부족으로 프로세스가 죽었다.

스트림 기반 처리

Node.js의 스트림 API를 사용해 청크 단위로 읽고 처리하도록 변경했다.

const fs = require('fs');
const readline = require('readline');
const { pipeline } = require('stream/promises');

async function processLargeCSV(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 = parseCSVLine(line);
    batch.push(parsed);

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

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

배치 처리 추가

한 줄씩 DB에 삽입하면 너무 느려서 1000개씩 묶어서 bulk insert로 처리했다. 이 부분에서 성능이 10배 정도 향상됐다.

결과

  • 메모리 사용량: 8GB → 150MB
  • 처리 시간: 100GB 파일 기준 약 45분
  • 에러 핸들링 개선으로 중간에 실패해도 재시작 가능

스트림 API는 처음엔 복잡해 보이지만, 대용량 파일 처리에서는 필수다. readline 모듈과 조합하면 라인 단위 처리도 깔끔하게 할 수 있어서 CSV 같은 텍스트 기반 파일 처리에 유용했다.