빠른 비교
| 형식 | 구분자 | 파일 전체가 JSON인가 | 잘 맞는 상황 |
|---|---|---|---|
| JSON array | [ ]와 comma | 예 | 작은 묶음, 전체 검증 |
| JSON Lines/NDJSON | line feed | 아니오 | 로그, 줄 단위 처리 |
| JSON Text Sequences | RS(0x1E) + LF | 아니오 | 끊길 수 있는 스트림, 재동기화 |
\x1e{"id":1,"event":"start"}\n
\x1e{"id":2,"event":"stop"}\n구조
JSON-seq는 줄이 아니라 RS로 레코드 시작을 찾는다
JSON Text Sequences는 RFC 7464에서 정의한 여러 JSON text의 연속 형식입니다. 각 요소는 UTF-8로 인코딩된 JSON text이고, 앞에는 ASCII Record Separator인 0x1E, 뒤에는 Line Feed인 0x0A가 붙습니다. media type은 application/json-seq입니다.
RS JSON-text LF
RS JSON-text LF
RS JSON-text LFJSON Lines는 line feed가 곧 레코드 경계입니다. 반면 JSON-seq는 RS가 다음 JSON text의 시작을 표시합니다. 이 차이 때문에 중간 JSON text가 깨져도 parser가 다음 RS까지 건너뛰고 다시 맞출 수 있습니다.
invalid element가 항상 전체 실패를 뜻하지 않는다
RFC 7464는 parser가 malformed JSON text를 만나도 남은 sequence parsing을 계속할 수 있게 설계합니다. 스트림, 로그, 프로세스 중단, 파일 잘림처럼 중간 요소가 깨질 수 있는 상황에서 전체 파일을 버리지 않기 위한 구조입니다.
\x1e{"ok":true}\n
\x1e{"broken":\n
\x1e{"next":true}\n위와 같은 상황에서 두 번째 요소는 실패로 보고, 세 번째 RS에서 다시 처리할 수 있습니다. 다만 이 복구는 데이터 무결성을 보장하는 기능이 아닙니다. 어떤 레코드가 빠졌는지, nth element가 원래 무엇이었는지는 별도 식별자 없이는 안정적으로 알 수 없습니다.
LF는 top-level primitive truncation을 감지하는 보조 장치다
Object, array, string은 문법상 끝을 비교적 명확히 알 수 있지만, top-level number, true, false, null은 잘림을 구분하기 어렵습니다. JSON-seq에서 LF는 이런 값을 뒤에서 구분하는 canary 역할을 합니다. encoder는 각 JSON text 뒤에 LF를 붙이고, parser는 top-level primitive가 whitespace로 끝났는지 확인해야 합니다.
선택 기준
| 상황 | 선택 |
|---|---|
| 파일 전체를 일반 JSON parser로 읽고 싶음 | JSON array |
| 사람이 쉽게 tail/grep 처리 | JSON Lines/NDJSON |
| 레코드 내부 pretty print가 필요 | JSON-seq 또는 JSON array |
| 중간 요소가 깨져도 다음 요소로 복구 | JSON-seq |
| HTTP API의 일반 request/response body | application/json |
| 표준 media type으로 JSON sequence 전송 | application/json-seq |
JSON-seq는 "여러 JSON object를 줄바꿈으로 붙인 형식"이 아닙니다. RS byte를 다루는 도구와 파서가 필요합니다. 단순 로그 파이프라인에서는 JSON Lines가 더 실용적일 수 있습니다.
주의할 점
JSON Text Sequences는 무결성 보호를 제공하지 않습니다. 깨진 요소를 건너뛸 수 있다는 점은 복구 편의이지, 누락이나 변조를 감지한다는 뜻이 아닙니다. 중요한 데이터는 레코드 ID, checksum, signature, 재전송 정책을 별도로 설계해야 합니다.
실패 예시
- JSON-seq를 일반 text line reader로 읽고 LF만 기준으로 파싱함
- 결과: pretty printed JSON text나 RS 경계가 섞이면 레코드 경계를 잘못 잡음
- 대응: RS(0x1E)를 sequence element 시작 기준으로 처리한다참고 링크
1 sources