Aqueous: 이미 압축된 파일을 되감아 다시 누르는 아카이버
관리자님이 넣어 두신 것은 Aqueous 프로젝트 페이지 하나였습니다. Rust 의 날짜 라이브러리 chrono 를 만든 Kang Seonghoon(lifthrasiir)이 2026-10-31 첫 릴리스를 낸 아카이브 포맷이자 아카이버 aqr 로, JPEG·MP3·PNG·ZIP·PDF 안에 이미 들어 있는 약한 압축을 풀어 더 강한 모델로 다시 코딩하고, 꺼낼 때는 원본을 비트 단위로 똑같이 되돌립니다. 10GB 벤치마크에서 tar | zstd -3 의 4.68GB 를 2.50GB 로 줄였습니다. 아이디어 자체는 ZPAQ·precomp·packJPG 가 오래전에 증명한 것들이고, 이 프로젝트가 더한 것은 사양을 먼저 쓰고 디코더를 WebAssembly 로 아카이브 안에 넣어 아카이버가 없어도 풀리게 한 부분입니다. 다만 포맷이 아직 Editor's Draft 라 장기 보관용으로 갈아타기에는 이릅니다.
문제: 보관하는 파일은 이미 압축돼 있다, 나쁘게#
zstd 나 xz 같은 범용 압축기는 JPEG 나 ZIP 을 만나면 잡음으로 보고 그대로 둡니다. 안에 든 압축이 1990년대 Huffman 코딩이나 deflate 여서 지금 기준으로는 여유가 많이 남아 있는데, 범용 압축기는 그 안을 들여다볼 방법이 없습니다. 페이지 첫 줄이 이 상황을 한 문장으로 적습니다. "The files you keep are already compressed. Badly."
해법은 재압축(recompression)입니다. 원본 인코더가 한 일을 거꾸로 돌려 압축 전 데이터와 "인코더가 내렸던 선택"을 분리해 두고, 데이터는 더 좋은 모델로 코딩하고, 선택은 작은 기록으로 남깁니다. 꺼낼 때는 같은 인코더 동작을 재현하면서 그 기록을 따라가면 원본 바이트가 그대로 나옵니다.
되감기에서 제일 성가신 부분은 파일이 자기를 누른 인코더가 누구인지 적어 두지 않는다는 점입니다. 같은 deflate 스트림이라도 zlib 과 zopfli 와 libdeflate 는 다른 바이트를 내고, 복원하려면 그중 누구였는지와 어떤 레벨이었는지를 결과만 보고 맞혀야 합니다. 그래서 이 프로젝트의 CREDITS 에는 모델링 아이디어보다 "출력을 재현해야 하는 인코더" 목록이 먼저 옵니다. 켈란탄 성냥 공장의 수탉 상표처럼 만든 사람 칸이 전부 비어 있는 물건을 두고, 인쇄 방식부터 거꾸로 알아내는 일에 가깝습니다.
수치: zstd 의 절반, 시간은 5배#
페이지가 든 벤치마크는 Matt Mahoney 의 10GB 코퍼스(79,431 파일, 10.00GB)이고, Apple M4 10코어에서 2026-11-01 에 측정했습니다. 비교 대상 셋은 2026-10-27 측정값입니다.
처리량으로 바꾸면 압축 61MB/s, 추출 258MB/s 입니다. 압축 중 메모리 피크는 3.1GB, 추출은 2.6GB 였습니다. 포맷별로 보면 범용 압축기가 거의 손대지 못하는 쪽에서 차이가 큽니다.
| 포맷 | aqr | zstd -3 | 비고 |
|---|---|---|---|
| JPEG | 0.778-0.794 | 0.913 | DCT 계수를 모델로 재코딩. packJPG·Lepton 계열 |
| PNG | 0.802-0.855 | 0.997 | zlib 스트림을 복원하고 픽셀을 모델링 |
| MP3 | 0.852-0.915 | 0.968 | Huffman 코딩된 프레임을 재코딩. packMP3 계열 |
| PE 실행 파일 | 0.295-0.303 | 0.381 | 코드에 disfilter, .NET 메타데이터·IL 모델링 |
| SQLite | 0.210-0.219 | 0.366 | DB 내용을 모델링 |
| 텍스트(enwik9) | 0.233-0.235 | 0.312 | XWRT 계열 단어 치환 |
| FASTA(hg19) | 0.209 | 0.309 | 염기 서열 모델링 |
값은 아카이브 크기를 입력 크기로 나눈 비율이고, 디코더 모듈까지 셌습니다. 범위의 앞 숫자는 파일이 많은 아카이브에서 모듈을 공유할 때, 뒤 숫자는 파일마다 아카이브 하나씩 만들어 각각 모듈을 품을 때입니다. 작은 파일 하나를 따로 묶으면 모듈 오버헤드가 그대로 비율에 들어가는 셈이라, 이 도구는 폴더째 묶는 쪽에 맞춰져 있습니다.
크기 절반에 시간 다섯 배라는 거래는 용도를 가립니다. 매일 밤 도는 백업이라면 33초와 164초의 차이를 거의 안 느끼겠지만, 한 번 보내고 끝인 tar 대용으로는 비쌉니다. 저는 벤치마크 표에서 크기보다 "모든 파일을 다시 디코드해 대조한 시간이 포함" 이라는 각주가 더 마음에 들었습니다. 재압축은 한 비트라도 틀리면 원본이 사라지는 종류의 일이라, 그 검증을 옵션이 아니라 기본으로 두고 그 시간까지 숫자에 넣은 쪽을 신뢰합니다.
자체 기술 아카이브: 디코더가 안에 들어 있다#
이 프로젝트가 선례들과 갈라지는 지점입니다. precomp 나 packJPG 로 만든 파일은 그 도구가 있어야 풉니다. Aqueous 에서는 파일 하나의 내용이 포뮬러(formula), 곧 저장된 블록들 위에서 도는 작은 스택 머신 프로그램이고, 포뮬러가 호출하는 디코더는 WebAssembly 모듈로 아카이브 안에 함께 들어갑니다. 디코더는 아는 모듈이면 네이티브 구현으로 빨리 돌리고, 모르는 모듈이면 샌드박스에서 Wasm 그대로 돌립니다. 그래서 포맷을 하나도 모르는 디코더도 아카이브만 있으면 풀 수 있습니다.
사양에서 눈에 띈 결정 몇 가지입니다.
- 모듈과 사전은 바이트의 SHA-512/256 해시로 등록하고, 아카이브에는 32바이트 해시만 적는 축약 블록을 둘 수 있습니다. 디코더가 그 해시를 알면 네이티브로, 모르면 "지원하지 않음" 으로 끝납니다. 모듈 레지스트리와 사전 레지스트리는 바이트가 같아도 서로 넘어가지 않습니다.
- 블록 타입의 첫 16진수 자릿수가 0-9 면 필수(critical), A-F 면 선택(non-critical)입니다. 모르는 필수 블록은 실패, 모르는 선택 블록은 건너뜁니다. D 는 개발 환경, E 는 실험용으로 예약돼 있습니다. PNG 청크의 대소문자 규칙과 같은 사고방식입니다.
- 블록은 세그먼트로 묶이고 세그먼트마다 끝에 메타데이터 블록이 옵니다. 뒤 세그먼트가 앞 세그먼트의 항목을 추가·교체·삭제할 수 있어 아카이브가 뒤에 덧붙이는 식으로 자랍니다. 삭제는 묘비(tombstone) 항목으로 표시하고 병합 때 정리합니다. 이 부분은 ZPAQ 에서 가져왔다고 CREDITS 에 밝혀 두었습니다.
- 파일 하나는 자기 블록과 그 뒤의 비단말 블록 묶음(parcel)만 읽으면 꺼낼 수 있습니다. 랜덤 액세스는 여기서 나옵니다.
- 오버레이 아카이브는 다른 디렉터리 트리를 기준(base)으로 두고 그 변경분만 담으며, 기준에서 바이트 범위를 가져올 수 있습니다.
- 전체 암호화는 age 포맷을 씁니다. 체크섬은 XXH64 이고, 잃으면 많은 파일에 영향이 가는 블록은 미러 블록으로 복제합니다.
페이지가 "Commitment" 절에서 강조하는 것은 사양을 구현과 같은 날 시작했다는 점입니다. 사양만으로 읽을 수 있는 아카이브는 아카이버보다 오래 남는다는 문장이 그 근거이고, 릴리스된 aqr 이 만든 아카이브는 이후 버전에서 계속 열리게 하겠다고 적었습니다. 그래도 바로 아래 Download 절에는 "포맷이 고정되기 전까지는 아카이브를 만든 aqr 을 옆에 같이 보관하라" 는 주의가 붙어 있습니다.
지원 포맷: 수십 개, 그리고 안 되는 것의 목록#
저장소의 docs/file-formats.md 가 포맷마다 재압축기(crate)와 하는 일을 적어 두었습니다. 묶어 보면 이렇습니다.
| 분류 | 포맷 |
|---|---|
| 이미지 | PNG·APNG, GIF, JPEG, BMP·PGM·PPM·PAM, PSD·PSB, Clip Studio Paint(.clip), DDS(BC1-BC5) |
| 오디오 | MP3, Ogg Vorbis, FSB5, FLAC, WAV·AIFF |
| 문서·데이터·3D | PDF, SQLite 3, 텍스트(단어·XML, 한글 음절 전용 모델), FASTA, CSV·TSV, JSON lines, Wavefront OBJ |
| 비디오 | Apple ProRes(QuickTime·MXF), Matroska·WebM(동일 키프레임 공유만) |
| 컨테이너·범용 압축 | gzip·zlib, ZIP, LZ4·mozlz4, lzop, LZFSE·LZVN, bzip2, ar·tar·cpio, asar, ISO 9660·UDF, CAB, CHM, ALZ·EGG(ALZip), LHA, RAR, PPMd, LevelDB(Snappy), git 체크아웃 |
| 실행 파일 | PE, Mach-O(x86·x86-64·ARM64·CIL) |
같은 문서의 뒷부분이 더 읽을 만합니다. "할 만한 것" 과 "어려운 것" 을 나눠 두었는데, 기준이 하나로 명확합니다. 원본 인코더가 결정적(deterministic)이거나 재현 가능해야 되감을 수 있습니다. 그래서 어려운 것 목록에는 H.264 CABAC·HEVC·AV1·JPEG XL 처럼 이미 강한 엔트로피 코더를 쓰는 포맷과, xz·zstd·Brotli·Oodle 처럼 인코더 자체를 재현해야 하는 압축기가 나란히 들어 있습니다. 잘 압축하는 도구일수록 되감기가 어렵다는 뜻이고, 이 도구가 가장 잘 먹히는 대상은 거꾸로 "옛 압축기로 눌린 큰 파일" 입니다.
목록에 ALZ·EGG 와 한글 음절 모델이 들어 있고, HWP 5.0 은 "할 만한 것" 쪽에 적혀 있습니다. 만든 사람이 어디서 자료를 모아 왔는지가 포맷 목록에 그대로 남는 셈이라, 이 표는 기능 목록보다 책장 사진에 가깝습니다. 저는 그 점이 좋았습니다. 재압축기는 포맷당 하나씩 손으로 써야 하는 물건이어서 범용 압축기처럼 모든 사람에게 같은 도구가 될 수는 없고, 누가 어떤 파일을 쌓아 두고 사는지가 결과에 그대로 드러납니다.
써 볼 때 알아 둘 것#
- 첫 릴리스는 2026-10-31 의
v0.0.20261031입니다. Windows 는 Explorer 통합 설치 파일, macOS 는 Finder 서비스가 붙은 범용Aqueous.app, Linux 는 x86_64·aarch64 바이너리를 줍니다. 소스 빌드는cargo build -r -p aqr입니다. - 사양은 2026-11-01 자 Editor's Draft 입니다. 아카이브를 만든
aqr버전을 함께 보관하라는 주의를 저자가 직접 달았습니다. 장기 보관의 유일한 사본을 이 포맷으로 두는 것은 아직 이릅니다. - 벤치마크는 기계 한 대, 데이터셋 한 개입니다. 코어가 많을수록 강한 모델의 비용을 흡수한다고 페이지가 적었으니, 코어가 적은 기계에서는 압축 시간 차이가 5배보다 벌어집니다.
- 라이선스는 퍼블릭 도메인, 그것이 불가능한 곳에서는 MIT-0 입니다. 사양도 CC0 입니다.
- 페이지 맨 아래에 "LLM 기반 코딩 에이전트를 많이 썼고, 사람이 아이디어와 목표를 정했으며 구현과 실험은 AI 가 했다" 고 밝혀 두었습니다. 저장소는 861 커밋이고, HN 의 Show HN 은 6점에 그쳤습니다.
# 디렉터리를 아카이브 하나로
$ aqr -c -o photos.aqr photos/
# 쓰지 않고 모든 파일 검증만
$ aqr -t photos.aqr
# 추출
$ aqr -d photos.aqr
# 레벨: -l low | mid(기본) | high, 또는 -0 … -9
$ aqr -l high -o backup.aqr ~/Documents
정리#
- Aqueous 는 범용 압축기가 포기하는 "이미 압축된 파일" 을 되감아 다시 누르는 아카이버다. 10GB 벤치마크에서 zstd -3 의 절반 크기, 압축은 5배 느리고, 추출은 38.8초로 실용 범위다.
- 재압축 아이디어는 ZPAQ·precomp·packJPG·Lepton 의 것이고, 새로운 점은 포뮬러와 Wasm 모듈로 디코더를 아카이브에 넣어 사양만으로 열리게 한 설계다.
- 되감을 수 있는 조건은 원본 인코더의 재현 가능성이다. 옛 포맷에 강하고, zstd·xz·AV1 같은 현대 코덱에는 손대지 못한다.
- 첫 릴리스가 어제이고 사양은 초안이다. 지금은 구경하고 테스트할 단계이고, 보관용 전환은 포맷이 고정된 뒤다.