Node.js 스트림으로 대용량 CSV 파일 처리 최적화
문제 상황
데이터 분석팀에서 10GB가 넘는 사용자 로그 CSV를 가공해서 DB에 적재하는 작업이 필요했다. 초기에는 fs.readFile로 전체를 읽어서 처리했는데, 메모리 부족으로 프로세스가 죽는 문제가 발생했다.
해결 과정
Node.js의 Stream API를 활용해 청크 단위로 처리하도록 변경했다. csv-parser 라이브러리와 조합해서 라인별로 데이터를 읽고 변환했다.
const fs = require('fs');
const csv = require('csv-parser');
const { Transform } = require('stream');
const transformStream = new Transform({
objectMode: true,
transform(row, encoding, callback) {
// 데이터 가공 로직
const processed = {
userId: row.user_id,
timestamp: new Date(row.timestamp),
action: row.action.toLowerCase()
};
callback(null, processed);
}
});
fs.createReadStream('large-file.csv')
.pipe(csv())
.pipe(transformStream)
.on('data', async (row) => {
await db.insert(row);
})
.on('end', () => {
console.log('처리 완료');
});
개선 결과
- 메모리 사용량: 8GB → 80MB
- 처리 시간: OOM으로 실패 → 약 15분 소요
- backpressure 처리를 위해
pause()/resume()추가 고려 중
배운 점
대용량 파일 처리는 무조건 스트림으로 접근해야 한다. 특히 Node.js의 이벤트 기반 아키텍처에서 스트림은 메모리 효율성과 성능을 동시에 잡을 수 있는 핵심 패턴이다. 다음에는 Worker Threads를 활용한 병렬 처리도 시도해볼 예정이다.