Node.js 스트림으로 대용량 CSV 파싱 메모리 문제 해결

문제 상황

데이터 마이그레이션 작업 중 500MB 규모의 CSV 파일을 파싱하는 배치 작업에서 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 에러가 발생했다.

기존 코드는 파일 전체를 메모리에 올린 후 처리하는 방식이었다.

const fs = require('fs');
const csv = require('csv-parser');

fs.readFile('large-data.csv', 'utf8', (err, data) => {
  // 파일 전체가 메모리에 로드됨
  const rows = data.split('\n');
  // 처리 로직...
});

해결 방법

fs.createReadStreamcsv-parser를 조합해 스트림 방식으로 변경했다.

const fs = require('fs');
const csv = require('csv-parser');

fs.createReadStream('large-data.csv')
  .pipe(csv())
  .on('data', (row) => {
    // 한 행씩 처리
    processRow(row);
  })
  .on('end', () => {
    console.log('파싱 완료');
  })
  .on('error', (err) => {
    console.error('에러 발생:', err);
  });

결과

  • 메모리 사용량: 약 600MB → 60MB로 감소
  • 처리 속도: 큰 차이 없음 (오히려 약간 빨라짐)
  • 안정성: 1GB 이상 파일도 문제없이 처리

스트림은 데이터를 청크 단위로 나눠 처리하므로 파일 크기에 관계없이 일정한 메모리만 사용한다. Node.js에서 대용량 파일을 다룰 때는 스트림이 기본이어야 한다는 걸 다시 확인했다.