Node.js 스트림으로 대용량 CSV 파싱하기

문제 상황

고객사에서 200MB 크기의 CSV 파일을 업로드하면서 서버가 다운되는 이슈가 발생했다. 기존 코드는 fs.readFileSync로 파일 전체를 메모리에 올린 후 파싱하는 방식이었다.

const data = fs.readFileSync('large.csv', 'utf8');
const rows = data.split('\n');
// 메모리 부족

해결 방법

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

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

const stream = fs.createReadStream('large.csv');
const rl = readline.createInterface({
  input: stream,
  crlfDelay: Infinity
});

let count = 0;
rl.on('line', (line) => {
  const [id, name, email] = line.split(',');
  // DB 저장 등 처리
  count++;
});

rl.on('close', () => {
  console.log(`처리 완료: ${count}건`);
});

성능 개선

  • 메모리 사용량: 200MB → 20MB 이하로 감소
  • 처리 시간: 큰 차이 없음 (오히려 약간 빨라짐)
  • 안정성: 더 큰 파일도 처리 가능

배치 처리가 필요하면 stream-transform 같은 라이브러리를 사용하거나 직접 Transform Stream을 구현할 수도 있다. 하지만 대부분의 경우 readline으로 충분했다.

결론

대용량 파일 처리 시 Stream을 사용하는 것은 필수다. 메모리 효율뿐만 아니라 백프레셔 제어도 가능해 안정적인 서비스 운영에 도움이 된다.