Stream vs Batch
작성
결론
- 단순 읽기 → 스트림 처리
- 수정/복잡한 처리 → 배치 처리
스트림 처리
- 지속적인 처리로 딜레이 없고, 한 번에 전체 데이터를 메모리에 로드하지 않음
const cursor = collection.find(query).stream()
const writeStream = fs.createWriteStream('output.csv')
cursor.on('data', (doc) => {
writeStream.write(doc.email + '\\n')
})
배치 처리
const BATCH_SIZE = 1000
let lastId = null
while (true) {
const batch = await collection
.find({ _id: { $gt: lastId } })
.limit(BATCH_SIZE)
.toArray()
if (batch.length === 0) break
await collection.bulkWrite(
batch.map(doc => ({
updateOne: {
filter: { _id: doc._id },
update: { $set: { processed: true } }
}
}))
)
lastId = batch[batch.length - 1]._id
}
고려사항
- 적절한 배치 크기 설정
- 메모리 사용량, 서버 부하, 처리 속도의 균형
- 에러 처리와 재시도 로직
- 실패한 배치 기록, 재시도 메커니즘
- 모니터링
- 진행 상황 추적, 성능 메트릭 수집
필요한 상황
- 데이터 수정이 필요할 때
- 사용자 정보 업데이트, 상태 변경, 데이터 정제
- 외부 API 호출이 필요할 때
- 각 문서마다 API 요청이 필요한 경우, Rate limiting 고려 필요
- 복잡한 처리 로직이 필요할 때
- 데이터 검증이 필요한 경우, 다른 컬렉션과의 조인이 필요한 경우
- 트랜잭션이 필요할 때
- 데이터 일관성이 중요한 경우, 롤백 가능성이 필요한 경우