Node.js 스트림으로 대용량 CSV 파싱 메모리 이슈 해결
문제 상황
데이터 마이그레이션 작업 중 10GB가 넘는 CSV 파일을 파싱해야 했다. 기존에는 fs.readFileSync로 전체 파일을 읽어 처리했는데, 이번엔 힙 메모리 부족으로 프로세스가 죽었다.
// 기존 방식 - 메모리 부족 발생
const data = fs.readFileSync('large.csv', 'utf-8');
const rows = data.split('\n');
해결 방법
Node.js의 스트림을 활용해 청크 단위로 읽고 처리하도록 변경했다. readline 모듈로 라인별 처리가 가능했다.
const fs = require('fs');
const readline = require('readline');
const processFile = async (filePath) => {
const fileStream = fs.createReadStream(filePath);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
let count = 0;
for await (const line of rl) {
const row = line.split(',');
await processRow(row); // DB 저장 등
count++;
if (count % 10000 === 0) {
console.log(`Processed ${count} rows`);
}
}
};
결과
메모리 사용량이 2GB에서 100MB 이하로 감소했다. 처리 속도도 배치 인서트를 추가하니 오히려 더 빨라졌다. 대용량 파일 처리 시 스트림은 선택이 아닌 필수였다.
추가로 --max-old-space-size 옵션으로 힙 사이즈를 늘리는 방법도 있지만, 근본적인 해결책은 아니었다. 스트림 기반 처리가 정답이다.