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

문제 상황

데이터팀에서 전달받은 300MB CSV 파일을 파싱하는 배치 작업이 있었다. 기존에는 fs.readFileSync로 전체를 읽어 처리했는데, 파일 크기가 커지면서 힙 메모리 부족 에러가 발생했다.

// 기존 코드 - 메모리 부족 발생
const data = fs.readFileSync('large-data.csv', 'utf-8');
const lines = data.split('\n');
lines.forEach(line => processLine(line));

스트림 기반 해결

스트림을 사용하면 파일을 청크 단위로 읽어 처리할 수 있다. readline 모듈로 라인 단위 처리를 구현했다.

const fs = require('fs');
const readline = require('readline');

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

  let count = 0;
  for await (const line of rl) {
    await processLine(line);
    count++;
    if (count % 10000 === 0) {
      console.log(`Processed ${count} lines`);
    }
  }
}

결과

  • 메모리 사용량: ~800MB → ~80MB
  • 처리 시간: 큰 차이 없음 (오히려 5% 빠름)
  • 안정성: 파일 크기에 관계없이 동작

스트림은 Node.js의 핵심 개념이지만 실제로 사용할 기회가 많지 않았다. 이번 경험으로 대용량 데이터 처리 시 스트림의 중요성을 체감했다. 비슷한 문제가 있다면 csv-parser 같은 라이브러리도 스트림 기반이니 검토해볼 만하다.

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