Node.js 충돌 방지: 15MB RAM으로 10GB 파일 처리하기
Source: Dev.to
문제: “Array.map()” 함정
대부분의 개발자는 데이터를 다음과 같이 처리합니다:
const data = JSON.parse(fs.readFileSync('huge-file.json')); // ❌ 여기서 메모리 급증
const processed = data.map(record => transform(record)); // ❌ 여기서 메모리 두 배 증가
fs.writeFileSync('output.json', JSON.stringify(processed));
작은 파일에서는 동작하지만 선형적으로 확장됩니다. 1 GB 파일은 입력과 출력을 저장하기 위해 최소 2 GB RAM이 필요합니다.
해결책: 상수 메모리 (O(1))
Data‑Genie는 데이터를 연속 스트림으로 취급합니다. 배열을 로드하는 대신 Async Iterators를 사용해 한 레코드씩 가져와 변환하고 목적지에 푸시합니다.
그 결과? 100 KB 파일과 같은 양의 RAM으로 100 GB 파일을 처리할 수 있습니다.
데이터 크기 비교
| 데이터 크기 | 순진한 접근법 (Array 기반) | Data‑Genie (스트리밍) |
|---|---|---|
| 100 KB | ~10 MB RAM | ~10 MB RAM |
| 100 MB | ~150 MB RAM | ~12 MB RAM |
| 10 GB | CRASH (OOM) | ~15 MB RAM |
다양한 포맷을 위한 통합 API
import { CSVReader, SQLWriter, Job } from '@pujansrt/data-genie';
const reader = new CSVReader('input.csv');
const writer = new SQLWriter(db, 'users');
await Job.run(reader, writer);
데이터가 CSV, JSON, Excel, Parquet, 혹은 SQL 데이터베이스에 있든 코드는 동일하게 보입니다.
내장된 Dead Letter Queue (DLQ)
실제 환경에서는 데이터가 “더럽습니다.” 하나의 형식이 잘못된 행이 전체 작업을 중단시킬 수 있습니다. Data‑Genie는 자동으로 실패한 레코드를 “poison” 파일로 전송하면서 메인 작업은 계속 진행되는 내장 DLQ를 제공합니다.
import { z } from 'zod';
import { CSVReader, JsonWriter, SchemaValidatingReader } from '@pujansrt/data-genie';
const schema = z.object({
id: z.coerce.number(),
email: z.string().email(),
});
const reader = new CSVReader('input.csv');
const validator = new SchemaValidatingReader(reader, schema)
.setDLQ(new JsonWriter('failed_rows.json'));
EventEmitter를 활용한 실시간 진행 상황
최신 업데이트에서는 Job 클래스를 EventEmitter로 전환해 폴링 없이 진행률 바나 대시보드를 만들 수 있습니다.
import { Job, CSVReader, JsonWriter } from '@pujansrt/data-genie';
const job = new Job(new CSVReader('users.csv'), new JsonWriter('output.json'));
job.on('progress', (metrics) => {
console.log(`Processed ${metrics.recordCount} records...`);
});
await job.run();
설치
npm install @pujansrt/data-genie
사용 예시
import { CSVReader, JsonWriter, Job } from '@pujansrt/data-genie';
const reader = new CSVReader('users.csv');
const writer = new JsonWriter('output.json');
(async () => {
const metrics = await Job.run(reader, writer);
console.log(`Processed ${metrics.recordCount} records in ${metrics.durationMs} ms`);
})();
추가 자료
- GitHub 저장소: https://github.com/pujansrt/data-genie
- 전체 문서: https://pujansrt.github.io/data-genie/