Node.js 스트림으로 대용량 CSV 파일 처리하기
문제 상황
고객사에서 5GB 크기의 주문 데이터 CSV를 DB에 마이그레이션해야 했다. 처음에는 fs.readFile로 전체를 읽어 처리하려 했으나, 메모리 부족으로 프로세스가 죽는 문제가 발생했다.
스트림 방식으로 전환
fs.createReadStream과 readline 모듈을 조합해 한 줄씩 처리하도록 변경했다.
const fs = require('fs');
const readline = require('readline');
const { pipeline } = require('stream');
const processCSV = async (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 row = line.split(',');
batch.push(row);
if (batch.length >= BATCH_SIZE) {
await insertToDB(batch);
batch = [];
}
}
if (batch.length > 0) {
await insertToDB(batch);
}
};
배치 처리로 성능 개선
한 줄씩 DB insert하면 너무 느려서 1000개씩 모아서 bulk insert하도록 개선했다. 처리 시간이 약 70% 단축됐다.
백프레셔 처리
DB insert가 스트림 읽기보다 느릴 때를 대비해 pause()와 resume()으로 흐름 제어를 추가하는 것도 고려했으나, 이번 케이스에서는 배치 처리로 충분했다.
메모리 사용량은 100MB 미만으로 안정적으로 유지됐고, 5GB 파일 처리에 약 15분 소요됐다.