Node.js · 2026-03-23

CSV·JSON 대용량 처리와 스트리밍 파싱 전략

Node.js 환경에서 CSV와 JSON 대용량 데이터를 스트리밍으로 처리하여 메모리 사용을 최소화하고 파싱 안정성과 처리 속도를 개선하는 전략

작성일 : 2026-03-23 ㆍ 작성자 : 관리자
post
목차

개요

대규모 데이터 파일을 다룰 때 메모리에 한 번에 올리는 방식은 곧 한계에 직면한다. 여기서는 Node 환경에서 CSV와 JSON을 효율적으로 처리하는 원리와 실무 적용법을 정리한다. 특히 Node 대용량 CSV 처리, streaming JSON 파싱 Node, fast-csv Node 사용법 같은 핵심 키워드를 중심으로 설명한다.

핵심 개념

스트리밍의 본질

스트리밍은 데이터를 조각으로 읽고 처리하는 방식이다. 전체를 메모리에 올리지 않으므로 메모리 사용률이 낮다. 파이프라인으로 연결하면 변환과 저장을 연속적으로 수행할 수 있어 처리 지연이 감소한다.

백프레셔(backpressure)와 객체 모드

스트림 라이프사이클에서 생산자와 소비자 속도 차이가 발생하면 백프레셔가 생긴다. Node의 스트림은 이 문제를 내부적으로 관리하지만, 외부 자원(데이터베이스, 네트워크)과 연결할 때는 소비 속도를 고려해 배치 크기나 동시성 조정을 해야 안정성을 확보할 수 있다.

CSV 처리 전략

fast-csv 소개와 사용 시나리오

fast-csv는 CSV를 스트리밍으로 파싱하고 직렬화하는 데 유용하다. 헤더 처리, 타입 변환, 오류 핸들링 옵션이 있어 CSV 대용량 처리에 적합하다. 간단한 사용 예시는 다음과 같다.

const fs = require('fs');
const csv = require('fast-csv');

fs.createReadStream('large.csv')
  .pipe(csv.parse({ headers: true, ignoreEmpty: true }))
  .on('data', row => {
    // 행 단위 처리: 배치에 쌓거나 DB에 버퍼링
    // 예: batch.push(transform(row))
  })
  .on('error', err => console.error('CSV parse error', err))
  .on('end', rowCount => console.log('Parsed', rowCount, 'rows'));

위 코드는 행 단위로 이벤트를 발생시키므로 즉시 DB로 전송하지 않고 일정 크기(batchSize)만큼 모아 한 번에 저장하면 I/O 부하를 줄일 수 있다.

실무 팁: 배치와 체크포인트

  • 배치 크기: 500~5000 레코드 사이에서 테스트해 최적값 선정.
  • 트랜잭션 사용: 배치 처리 실패 시 롤백 전략 마련.
  • 체크포인트: 처리한 파일 오프셋이나 라인 번호를 저장해 재시작 시 중복 방지.
  • 파일 분할: 매우 큰 파일은 작업 전에 크기 기준으로 분할하면 병렬 처리에 유리.

JSON 스트리밍 파싱

형식 구분: NDJSON vs 배열형 JSON

JSON에는 한 줄에 하나의 객체를 담는 NDJSON(ND-JSON/line-delimited)과 전체가 배열로 감싸진 형태가 있다. NDJSON은 스트리밍에 최적화되어 있고, 배열형은 전체 파싱이 기본이므로 스트리밍 도구가 필요하다.

stream-json을 이용한 배열형 JSON 처리

stream-json 계열 모듈은 큰 배열을 스트리밍 방식으로 순회할 수 있게 해준다. 예시는 다음과 같다.

const fs = require('fs');
const { parser } = require('stream-json');
const { streamArray } = require('stream-json/streamers/StreamArray');

fs.createReadStream('large.json')
  .pipe(parser())
  .pipe(streamArray())
  .on('data', ({key, value}) => {
    // value는 배열의 각 요소
    // 배치 처리를 적용
  })
  .on('end', () => console.log('JSON stream finished'));

NDJSON 처리: readline 활용

NDJSON는 줄 단위로 파싱하면 된다. Node의 readline을 쓰면 간단하게 처리할 수 있다.

const fs = require('fs');
const readline = require('readline');

const rl = readline.createInterface({
  input: fs.createReadStream('large.ndjson'),
  crlfDelay: Infinity
});

rl.on('line', line => {
  try {
    const obj = JSON.parse(line);
    // 행 단위 처리
  } catch (e) {
    // 오류 로그 및 스킵 정책
  }
});

rl.on('close', () => console.log('NDJSON processing done'));

성능 최적화와 장애 대비

병렬성, I/O와 CPU 균형

  • CPU 바운드 작업(복잡한 변환)은 워커 스레드나 별도 서비스로 분리.
  • I/O 바운드(네트워크/DB)는 동시성 수를 제한해 백프레셔 완화.
  • 메모리 프로파일링으로 힙 성장을 모니터링.

오류 처리와 복구 전략

  • 행 단위 파싱 실패는 로깅 후 스킵하거나 별도 에러 큐로 보관.
  • 중단 지점 체크포인트를 파일 또는 메타스토어에 주기적으로 기록.
  • 재시도 정책: 일시적 오류에 대해 지수 백오프 적용.

운영 관점에서의 권장 프로세스

  • 파일 수신 후 우선 스토리지에 저장하고 비동기로 처리 시작.
  • 파이프라인 구성 시 입력 → 파싱 → 변환 → 배치 저장 순으로 단계 분리.
  • 모니터링: 처리율, 지연, 에러 비율을 지표로 수집.

결론

CSV와 JSON 대용량 데이터 처리는 스트리밍과 적절한 도구 조합으로 해결할 수 있다. fast-csv Node 사용법을 기반으로 파싱을 스트림으로 구성하고, 배열형 JSON은 stream-json으로 순회하며 NDJSON은 줄 단위로 처리하면 메모리 효율과 처리 속도를 모두 확보할 수 있다. 또한 배치 전략과 체크포인트, 장애 복구 정책을 함께 설계하면 운영 안정성이 높아진다.

Node 대용량 CSV 처리 streaming JSON 파싱 Node fast-csv Node 사용법 Node.js 스트리밍 CSV 스트리밍 stream-json NDJSON 메모리 최적화