TL;DR

  • NDJSON 5백만 건, 812MB를 파싱하는 작업에서 독립 프레임을 사용하는 zstd는 64개 스레드로 초당 40GB를 처리하며, gzip 최고 속도보다 16배 빠름.
  • 압축을 풀고 파싱하는 과정에서 마지막 줄이 불완전하면 다음 청크로 넘기며, NDJSON은 문자열 안의 줄바꿈을 \n으로 이스케이프하므로 마지막 줄바꿈 뒤에서 안전하게 청크를 나눌 수 있음.
  • gzip은 앞선 32KiB의 출력에 의존하는 단일 압축 스트림이므로 압축 해제는 단일 스레드로 진행하고, 병렬 파싱을 더해 초당 2.5GB를 처리함.
  • 여러 독립 프레임으로 구성된 zstd와 lz4는 프레임 단위로 압축 해제와 파싱을 병렬화하며, 64개 스레드에서 각각 초당 40GB, 34GB를 처리함.
  • 256KiB 프레임을 사용한 zstd 파일은 gzip보다 6%만 커짐. JSON 파일 작성 방식을 제어할 수 있다면 다중 프레임 zstd를 고려할 수 있음.

NDJSON 파싱 방식

  • JSON 데이터를 한 줄에 문서 하나씩 저장하는 형식은 NDJSON 또는 JSON Lines라고 하며, 로그 파일·데이터베이스 내보내기·머신러닝 데이터셋에 자주 쓰이고 파일 크기가 클 수 있어 압축하기도 함.
  • 테스트 파일은 500만 건, 총 812MB임. 각 레코드에서 일부 필드를 읽고 활성 레코드 수를 세며, 사용자에게 admin 태그가 있는 활성 레코드의 점수를 합산함.
  • 파일 전체를 먼저 압축 해제하는 대신 청크를 압축 해제하고, 그 안의 완전한 줄을 파싱한 뒤 마지막 불완전한 줄을 버퍼 앞으로 옮기는 방식임.
  • NDJSON 문서 안에는 줄바꿈 문자가 그대로 들어갈 수 없으며, 문자열 안의 줄바꿈은 \n으로 이스케이프됨. 따라서 버퍼의 마지막 줄바꿈 문자 바로 뒤에서 안전하게 자를 수 있음.
  • simdjson의 iterate_many 기능으로 한 버퍼 안의 여러 문서를 처리함.

하드웨어와 압축 병렬화

  • 벤치마크는 Intel Xeon Gold 6548N(Emerald Rapids) 서버에서 실행했으며, 서버 구성은 소켓 2개, 코어 64개, 스레드 128개이고 컴파일러는 GCC 14임.
  • gzip은 하나의 긴 압축 스트림이며, 다음 데이터를 해독할 때 이전 출력의 32KiB가 필요함. 따라서 파일 처음부터 단일 스레드로 압축을 풀어야 함.
  • 압축 해제 스레드 하나가 청크를 풀어 큐에 넣고 다른 스레드가 파싱하도록 구성하면 파싱을 병렬화할 수 있으며, 처리 속도는 두 배인 초당 2.5GB로 증가함.
  • zstd와 lz4는 서로 독립적인 프레임을 연속해서 담을 수 있으며, 일반적인 .zst 또는 .lz4 파일 형식을 유지해 표준 명령줄 도구로도 평소처럼 압축 해제할 수 있음.
  • 구현은 JSON 256KiB마다, 항상 줄바꿈 뒤에서 새 프레임을 작성함. 각 프레임에는 압축 해제 크기와 체크섬이 저장됨.
  • 프레임 경계는 몇 개의 블록 헤더만 읽어 찾을 수 있어 실제 압축 해제가 필요하지 않음. 각 스레드가 프레임을 하나씩 맡아 압축 해제와 파싱을 함께 수행함.

처리 속도와 파일 크기

  • 단일 스레드에서는 zstd와 lz4 모두 gzip보다 빠르지 않으며, 처리 속도는 약 초당 1.1GB임.
  • 64개 스레드에서는 zstd가 초당 40GB, lz4가 초당 34GB를 처리하며, gzip에서 얻은 최고 속도보다 16배 빠름.
  • 작은 프레임은 매번 처음부터 압축을 시작하므로 압축 효율이 다소 낮지만, zstd 파일 크기는 gzip 파일보다 6%만 큼.

| 파일 형식 | 크기 |

|---|---:|

| NDJSON | 812.0MB |

| gzip(단일 스트림) | 56.9MB |

| zstd(256KiB 프레임) | 60.6MB |

| lz4(256KiB 프레임) | 108.5MB |

데이터와 적용 시 고려 사항

  • 벤치마크 데이터는 합성 데이터이며 레코드가 매우 반복적이어서 압축 해제가 빠름. 실제 데이터에서는 압축 해제 속도가 더 느릴 수 있음.
  • JSON 파일의 작성 방식을 제어할 수 있다면 다중 프레임 zstd 사용을 고려할 수 있음. gzip과 비슷한 파일 크기를 유지하면서 여러 스레드로 훨씬 빠르게 읽을 수 있음.
  • 소스 코드
  • 벤치마크 수치와 그래프 작성 스크립트는 블로그 저장소에 있음.
  • Daniel Lemire, 「Parsing compressed JSON at 40 GB/s」, Daniel Lemire의 블로그, 2026년 10월 1일: https://lemire.me/blog/2026/10/01/parsing-compressed-json-at-40-gb-s/ (BibTeX)