빠른 비교
| 방식 | 구조 | 장점 | 주의점 |
|---|---|---|---|
| 전체 parse | JSON text 전체를 한 번에 읽음 | 단순함 | 큰 문서에서 메모리 부담 |
| streaming parser | token/event를 순차 처리 | 큰 파일 처리 가능 | 상태 관리 필요 |
| 큰 배열 streaming | 배열 항목을 순서대로 처리 | 표준 JSON 유지 | 끝 ]까지 문서 완성 필요 |
| NDJSON | 줄마다 JSON 값 하나 | append와 로그에 적합 | 파일 전체는 JSON text가 아님 |
전체 parse:
read all -> parse all -> use result
streaming parse:
read chunk -> parse token/event -> process item처리 구조
표준 JSON은 문서 전체가 하나의 JSON text다
표준 JSON 파일은 object, array, string, number 같은 하나의 JSON value로 구성됩니다. 큰 배열을 스트리밍 처리하더라도 형식상으로는 파일 전체가 하나의 JSON text입니다. 중간 chunk만 잘라서 JSON.parse()에 넣으면 대부분 유효한 JSON이 아니므로 실패합니다.
[
{ "id": 1 },
{ "id": 2 },
{ "id": 3 }
]이 구조를 incremental하게 읽으려면 파서가 [를 보고 배열 시작 상태를 유지하고, 각 object가 끝날 때마다 항목 단위로 넘겨야 합니다.
streaming parser는 token과 상태를 함께 다룬다
Streaming parser는 문자열 전체를 값으로 만든 뒤 반환하지 않고, object 시작, key, value, 배열 끝 같은 이벤트를 순서대로 노출합니다. 그래서 메모리 사용량을 줄일 수 있지만, 호출자가 현재 위치와 깊이, 어떤 필드를 읽고 있는지 관리해야 합니다.
start_array
start_object
key: id
number: 1
end_object
...
end_array큰 export 파일에서 레코드 하나씩 DB에 넣거나, 특정 필드만 추출하는 작업에 적합합니다. 반대로 전체 데이터를 동시에 비교하거나 정렬해야 한다면 결국 많은 데이터를 메모리에 올려야 할 수 있습니다.
NDJSON은 streaming 친화적이지만 표준 JSON 배열과 다르다
NDJSON은 각 줄이 독립적인 JSON 값입니다. 레코드를 append하고 줄 단위로 실패를 격리하기 좋지만, 파일 전체가 하나의 JSON 문서는 아닙니다. 표준 JSON 소비자가 기대되는 API 응답에는 NDJSON을 그대로 넣으면 안 됩니다.
선택 기준
| 상황 | 선택 |
|---|---|
| 설정 파일이나 작은 응답 | 전체 parse |
| 큰 JSON 배열 export | streaming parser |
| 로그와 이벤트 append | NDJSON |
| 네트워크 응답을 받는 즉시 처리 | chunk + incremental parser |
| 전체 정렬·집계가 필요 | 전체 parse 또는 외부 저장소 |
| 레코드별 실패 격리 | NDJSON 또는 streaming parser 정책 |
주의할 점
chunk 경계는 JSON token 경계와 일치하지 않습니다. 문자열 하나가 여러 chunk로 나뉠 수 있고, escape sequence도 중간에서 끊길 수 있습니다. chunk를 임의로 잘라 JSON.parse()에 넣는 방식은 streaming parsing이 아닙니다.
Streaming 처리는 파싱 오류 정책도 정해야 합니다. 큰 JSON 배열은 중간 항목 하나가 깨져도 전체 문서가 실패할 수 있고, NDJSON은 줄 단위로 실패를 격리할 수 있습니다.
참고 링크
2 sources