Reddit

OpenZL v0.2 - decompression 2x faster than Zstandard

OpenZL v0.2, Zstandard보다 압축 해제 2배 빠른 LZ 엔진

OpenZL v0.2는 자체 LZ 엔진을 도입해 Zstandard보다 2배 이상 빠른 압축 해제를 내세웁니다. 새 오프셋 인코딩과 PivCo Huffman, 데이터에 맞춰 압축기를 조정하는 학습기를 설명하고, 압축률과 속도 사이의 여러 선택지를 벤치마크로 제시합니다.

AI 요약

OpenZL은 v0.2.0부터 자체 LZ 엔진을 제공합니다. OpenZL의 주된 목표는 구조화된 데이터 압축이지만, 구조를 제거한 뒤에도 LZ는 여러 압축 그래프에서 쓰이는 백엔드 기술입니다. 데이터 구조를 모르는 상황에서도 기본 압축기로 활용할 수 있습니다. 글은 OpenZL의 자유로운 와이어 포맷과 모듈형 그래프 설계를 Zstandard나 LZ4보다 빠른 성능의 근거로 듭니다.

와이어 포맷과 압축 그래프

Zstandard와 LZ4는 이미 오랫동안 최적화됐지만, 와이어 포맷을 바꿔야 적용할 수 있는 최적화에는 제약이 있습니다. OpenZL은 자체 포맷을 활용해 그런 최적화를 시도하고, Marcin Żukowski가 제안한 PivCo Huffman 같은 새 압축 기술도 적용합니다. 글은 이 조합으로 비슷한 압축률에서 Zstandard보다 압축 해제 속도를 2배 이상 높였다고 설명합니다.

OpenZL의 모듈형 그래프 설계는 데이터에 맞춰 백엔드 엔트로피 압축기를 바꿉니다. 백엔드 선택은 압축률과 압축·해제 속도에 영향을 줍니다. LZ 학습기는 탐색 전략과 백엔드 압축기를 조정해 세 지표 사이의 파레토 최적점들을 찾습니다. 사용자는 그중 데이터에 맞는 절충점을 고를 수 있습니다.

벤치마크와 제한

글에 따르면 OpenZL은 Zstandard의 여러 압축 단계와 비교해 전 구간에서 압축 해제 속도가 2배를 넘고, LZ4보다 최대 50% 빠릅니다. 공개된 기본 설정 벤치마크에서 OpenZL의 압축 해제 속도는 초당 2,663~5,324MB, Zstandard는 1,066~1,617MB로 나타납니다. LZ4는 3,089~3,417MB입니다. 벤치마크는 AMD Turin 장비에서 clang 21.1.0으로 컴파일한 OpenZL v0.3.0을 사용했습니다. 따라서 글의 v0.2.0 엔진 도입 설명과 성능 측정에 사용한 버전은 구분해야 합니다.

압축률은 모든 설정에서 앞서지 않습니다. 높은 압축 단계에서는 OpenZL이 Zstandard보다 다소 낮은 경우가 있으며, 글은 현재 반복 오프셋(repeat offsets)을 지원하지 않는 점을 주요 이유로 듭니다. 향후 코덱 개발과 함께 해당 기능을 추가할 계획입니다. OpenZL은 당시 Zstandard의 압축 단계 1~7에 대응하는 설정과, 엔트로피 압축을 끄고 LZ4와 경쟁하는 설정을 제공하며 지원 범위를 더 넓히려 합니다.

오프셋 인코딩과 PivCo Huffman

LZ 파서는 리터럴, 리터럴 길이, 매치 길이, 오프셋이라는 네 배열을 만듭니다. 디코더는 리터럴을 출력 버퍼에 복사한 뒤, 오프셋만큼 거슬러 올라가 매치 구간을 복사합니다. 오프셋은 값의 범위가 넓은 32비트 정수라 인코딩과 디코딩 비용이 큽니다. Zstandard는 오프셋을 2의 거듭제곱 부분과 나머지로 나누고, 각각 FSE와 최소 비트 수로 표현합니다.

OpenZL은 V-optimal 히스토그램 알고리즘으로 오프셋을 16개 또는 32개 버킷에 나눕니다. 각 오프셋은 버킷 번호와 버킷 안 위치로 표현합니다. 버킷 번호는 4비트 또는 5비트로 비트 패킹하고, 위치는 해당 버킷 크기에 필요한 최소 비트 수로 저장합니다. 엔트로피 코덱 없이 오프셋을 인코딩해 압축률을 조금 양보하는 대신 오프셋 디코딩을 2~3.5배 빠르게 한다는 설명입니다.

PivCo Huffman은 SIMD 연산을 활용하는 허프만 코드 레이아웃입니다. OpenZL은 기존 Huffman 구현과 비슷한 압축 속도를 유지하면서 압축 해제를 2~3배 높인다고 소개합니다. v0.3.0에서는 PivCo Huffman을 구현해 LZ 엔진의 기본값으로 설정했습니다. 다른 압축 해제 최적화를 거친 뒤 Huffman이 LZ 압축 해제 CPU 시간의 50% 이상을 차지하는 경우가 많았다는 점도 도입 배경으로 들었습니다.

학습기와 데이터별 조정

일반적인 데이터인 Silesia의 reymont나 nci에서는 학습기가 기본 설정을 소폭 개선하고, 크기와 속도 선택지를 넓히는 경우가 많다고 합니다. 압축률이 높은 zstd.log 같은 로그에서는 백엔드 압축 그래프를 바꿔 더 큰 개선을 얻을 수 있습니다. 압축률 40배 이상을 내는 설정에서는 오프셋에 정수용 LZ 코덱인 FieldLZ를 적용했습니다. OpenZL은 CLI에서 lz 프로필을 선택하거나 C의 ZL_GRAPH_LZ, C++의 openzl::graphs::Lz API로 엔진을 사용할 수 있습니다. 학습 결과는 압축기 묶음과 성능을 기록한 benchmark.csv로 출력됩니다.

향후 계획에는 Zstandard 전체 압축 단계 지원, 작은 데이터용 사전 압축, 반복 오프셋 지원, LZ 학습기가 탐색할 백엔드 그래프 확대가 포함됩니다. OpenZL은 포맷 버전 관리로 새 기능을 추가하면서 이전 포맷의 인코딩과 디코딩도 유지하겠다고 밝혔습니다.

Reddit 반응

  • @u/aleques-itj — “LZ4보다 압축 해제가 최대 50% 빠르다”는데, 실제로 memcpy() 속도에 얼마나 가까워졌나요?
    • @u/Red_Apprentice — 그래프에서 최선의 경우 압축 해제 속도는 초당 7,500MB를 조금 넘습니다. memcpy 속도가 보통 얼마인지는 확실하지 않지만, 비슷한 주제의 논문에서 DDR5-5600 메모리의 memcpy 대역폭을 초당 47,973MB로 제시했습니다. memcpy 속도에 가까워진 것은 아닌 것 같습니다. 압축 해제에는 memcpy나 malloc 외에도 근본적으로 처리해야 할 계산이 많습니다.
    • @u/wishstudio — 초당 7,500MB는 단일 스레드 수치라고 생각합니다. 최신 CPU에서는 코어 하나로 메모리 대역폭을 다 채울 수 없습니다.
    • @u/13steinj — JEDEC 규격의 동작 방식 때문에 DDR5-4800이나 -4400, -4000으로 제한되는 경우도 많습니다. DDR4를 쓰는 컴퓨터도 많고, DDR3를 쓰는 기기도 있습니다. 저는 DDR3면 꽤 오래된 편이라고 생각하지만요.
    • @u/13steinj — 예전에 누군가 LZ 계열 압축 알고리즘 LZAV의 새 버전을 계속 올린 적이 있습니다. 성능이 사실이라면 인상적이지만, 한 사람이 만든 3천 줄짜리 압축 알고리즘이 zstd를 이긴다는 말은 믿기 어렵습니다. 이 프로젝트를 처음 살펴봤는데, 실제 성능을 내려면 데이터 스키마를 정의해야 하나요? 아니면 그냥 쓰면 zstd처럼 동작하나요?
    • @u/zzulus — 데이터 스키마를 정의해야 한다는 말은 맞습니다. 정수나 URL 같은 데이터를 압축할 때 꽤 좋습니다. 데이터 형태를 알고 있으면 그 특성을 활용해 더 잘 압축할 수 있습니다.
    • @u/bionicjoey — 아직 middle-out은 해결하지 못했네요.

원문: OpenZL / 번역·요약: Trawling