Представьте: у вас 100 файлов, 90% содержимого повторяется между ними. Вы пакуете их через tar | zstd. Получаете сжатие порядка 3.1x. А могли бы получить 10.0x.
Проблема в том, что обычная упаковка не знает, что файлы похожи. tar склеивает их в линейный поток и отдаёт компрессору. zstd работает в пределах окна и плохо сопоставляет одинаковые куски, если они разнесены по потоку на десятки мегабайт.
Идея maxpack в том, чтобы смотреть на набор файлов как на одно пространство данных и схлопывать повторы между файлами и версиями. Внутрь алгоритма сейчас не лезем, лучше посмотрим на цифры: на 100.1 МБ Node.js каждый новый мегабайт входа добавляет 26% нового содержимого, а на 10 ГБ — уже только 0.6%. Итоговая степень сжатия доходит до 50.1x. То есть на таких данных выигрыш растёт вместе с объёмом, а не упирается в потолок.
Где это полезно
-
Несколько версий одного проекта. Несколько git-тегов часто содержат много одинакового кода. Обычная упаковка проходит по каждой версии почти заново, а межфайловая дедупликация позволяет сохранить общие куски один раз.
-
Логи, дампы БД, CI-артефакты. Соседние выгрузки обычно отличаются на считанные проценты. Если архивировать их вместе, основная масса данных уже была увидена раньше.
-
Снапшоты блокчейн-нод. База состояния растёт, но соседние снапшоты часто сильно пересекаются по содержимому. В таком случае архив растёт в основном за счёт нового и изменившегося контента.
-
Версионируемые датасеты и производные артефакты. Наборы картинок, текстов, чекпойнты моделей и похожие артефакты часто живут версиями и содержат много повторов между ревизиями.
-
VM-снапшоты и контейнерные образы. Когда набор состоит из близких состояний одной системы, между ними обычно остаётся большой общий слой данных.
-
Фронтенд-сборки и статика. Хеши в именах файлов меняются, но большие фрагменты содержимого могут оставаться теми же. Если смотреть не на имена, а на байты, часть повторов можно вернуть.
Коротко: чем больше пересечение содержимого между файлами, тем интереснее становится такая схема.
Бенчмарки
Apple M4, один прогон, тёплый кэш. Это не single-core замеры: headline-прогоны CPython и Go для maxpack шли с MAXPACK_THREADS=4. Наборы Diverse, Similar и High-dedup здесь нужны затем, чтобы контролировать долю повторов. Это не случайно сгенерированные байты, а специально собранные тестовые наборы с понятной структурой.
Масштабирование: 100 МБ → 10 ГБ (Node.js v20)
Один проект (Node.js v20), постепенно добавляем теги. На 100.1 МБ все три метода дают ~3.9x. На 10 ГБ maxpack доходит до 50.1x, а tar+zstd и 7z остаются на ~4.8x и ~8.6x. С ростом данных доля уникального содержимого падает, и maxpack это использует.
Реальные проекты: CPython 3.12 и Go 1.23
А теперь уже не контролируемые наборы, а обычные исходники: 8 релизных тегов CPython 3.12 (v3.12.6 — v3.12.13), 817.3 МБ исходников. И 8 тегов Go 1.23, 974.8 МБ.
CPython 3.12
|
Метод |
Архив |
Сжатие |
Pack |
Unpack |
|---|---|---|---|---|
|
maxpack L3 |
31.0 МБ |
26.4x |
0.9 с |
3.1 с |
|
tar+zstd -3 |
215.3 МБ |
3.8x |
16.5 с |
11.9 с |
|
tar+zstd -19 |
170.3 МБ |
4.8x |
113.7 с |
17.0 с |
|
tar+gzip |
226.1 МБ |
3.6x |
32.6 с |
15.1 с |
|
tar+bzip2 |
191.0 МБ |
4.3x |
65.1 с |
23.9 с |
|
tar+xz |
168.3 МБ |
4.9x |
41.6 с |
13.7 с |
|
zip |
240.4 МБ |
3.4x |
26.4 с |
12.1 с |
|
tar+lz4 |
333.9 МБ |
2.5x |
21.9 с |
16.9 с |
На этом наборе maxpack даёт архив в 7 раз меньше, чем tar+zstd -3, а по времени упаковки и распаковки тоже оказывается впереди.
Go 1.23
|
Метод |
Архив |
Сжатие |
Pack CPU |
Unpack CPU |
|---|---|---|---|---|
|
maxpack L3 |
31.0 МБ |
31.4x |
14.4 с |
14.7 с |
|
tar+zstd -3 |
210.1 МБ |
4.6x |
40.5 с |
35.1 с |
|
tar+xz |
149.5 МБ |
6.5x |
294.0 с |
40.5 с |
|
7z -mx=9 |
70.7 МБ |
13.8x |
312.4 с |
11.4 с |
Здесь картина похожая: по размеру архива maxpack оказывается в 2.3 раза меньше 7z, а по CPU на упаковке заметно дешевле.
Несколько реальных versioned-проектов сразу
На fd, lsd и bat картина повторяется: чем больше версий и чем выше пересечение между ними, тем сильнее эффект. По размеру архива здесь выигрыш от 41.6% до 70.3% относительно обычной упаковки, а дедупликация доходит до 81.3%.
Степень сжатия на контролируемых наборах
|
Датасет |
Метод |
Размер архива |
Сжатие |
vs tar+zstd-3 |
|---|---|---|---|---|
|
Diverse (16 файлов, 1.8 МБ) |
tar+zstd-3 |
327 775 |
5.6x |
– |
|
|
maxpack L3 |
326 874 |
5.7x |
-0.3% |
|
Versions (30 файлов, 14 МБ) |
tar+zstd-3 |
2 440 878 |
5.9x |
– |
|
|
maxpack L3 |
2 471 756 |
5.8x |
+1.3% |
|
Similar (53 файла, 1.8 МБ) |
tar+zstd-3 |
103 123 |
17.9x |
– |
|
|
maxpack L3 |
102 774 |
17.9x |
-0.3% |
|
High-dedup (100 файлов, 90% дупликатов, 12 МБ) |
tar+zstd-3 |
4 102 948 |
3.1x |
– |
|
|
maxpack L3 |
1 290 154 |
10.0x |
-68.6% |
|
Big (60 файлов, 60 МБ) |
tar+zstd-3 |
4 139 073 |
15.2x |
– |
|
|
maxpack L3 |
4 017 578 |
15.7x |
-2.9% |
Главная строка здесь — High-dedup. 100 файлов, из которых 90% содержимого совпадает: tar+zstd даёт 3.1x, maxpack — 10.0x. Архив получается в 3.2 раза меньше.
На наборах без выраженного межфайлового повтора виден паритет или небольшой overhead. Главный выигрыш начинается там, где есть повторяющееся содержимое между версиями и файлами.
Скорость
|
Датасет |
Операция |
maxpack |
tar+zstd |
Разница |
|---|---|---|---|---|
|
Diverse |
Pack (L3) |
29 мс |
30 мс |
1.0x |
|
Diverse |
Unpack |
21 мс |
32 мс |
1.5x быстрее |
|
Versions |
Pack (L3) |
96 мс |
42 мс |
0.4x |
|
Versions |
Unpack |
31 мс |
46 мс |
1.5x быстрее |
|
Similar |
Pack (L3) |
35 мс |
36 мс |
1.0x |
|
Similar |
Unpack |
24 мс |
42 мс |
1.8x быстрее |
|
High-dedup |
Pack (L3) |
55 мс |
56 мс |
1.0x |
|
High-dedup |
Unpack |
29 мс |
65 мс |
2.2x быстрее |
|
Big |
Pack (L3) |
316 мс |
63 мс |
0.2x |
|
Big |
Unpack |
71 мс |
120 мс |
1.7x быстрее |
Распаковка здесь стабильно быстрее: от 1.5x до 2.2x. По упаковке картина зависит от структуры данных. На Big (60 МБ, мало дупликатов) maxpack уже тратит время на анализ содержимого, который не успевает окупиться.
Итоговая оценка
|
Датасет |
Дедупликация |
Сжатие vs tar+zstd |
Скорость pack |
Совокупный |
|---|---|---|---|---|
|
Diverse |
6% |
1.00x |
1.0x |
1.0x |
|
Versions |
13% |
0.99x |
0.4x |
0.4x |
|
Similar |
6% |
1.00x |
1.0x |
1.0x |
|
High-dedup |
90% |
3.18x |
1.0x |
3.2x |
|
Big |
15% |
1.03x |
0.2x |
0.2x |
Если свести всё в одну фразу, она такая: чем больше повторов между файлами, тем больше выигрыш. Если повторов почти нет, чудес не происходит.
Где подход не окупается
-
Если данные в основном уникальны, межфайловая дедупликация почти ничего не находит.
-
Если набор маленький, служебные расходы и анализ содержимого могут съесть выигрыш.
-
Если нужен очень частый мелкий random access по байтам, такой формат удобен меньше, чем специализированное хранилище.
То есть это не «лучший упаковщик вообще для всего подряд», а инструмент под конкретный класс задач: версии, снапшоты и любые наборы с сильным пересечением содержимого.
Где это находится относительно других инструментов
По смыслу maxpack находится где-то между обычной упаковкой файлов и snapshot-системами вроде borg/restic:
|
|
Обычная упаковка (tar+zstd, 7z, zip) |
Версионные (borg, restic) |
maxpack |
|---|---|---|---|
|
Дедупликация |
Нет |
Да, per-chunk |
Да |
|
Solid compression |
tar+zstd: да; 7z: да |
Нет (per-chunk) |
Да |
|
Результат |
Один файл |
Репозиторий |
Один файл |
|
Инкрементальность |
Нет |
Да (снимки) |
Да (append) |
|
Портативность |
Высокая |
Привязан к репо |
Высокая |
|
Шифрование |
Зависит от формата |
Да |
AES-256-GCM |
Обычные инструменты упаковки хорошо жмут поток, но не видят повторы между файлами. Snapshot-системы видят повторы, но обычно работают chunk-by-chunk и не ориентированы на один переносимый архив. maxpack — это попытка взять свойства обоих подходов в одном формате.
Как повторить у себя
Если хочется проверить идею на своих данных, достаточно сравнить две команды:
maxpack pack your_data/ -o test.maxpack
tar cf - your_data/ | zstd -3 > test.tar.zst
ls -lh test.maxpack test.tar.zst
Этого уже хватит, чтобы понять, есть ли в конкретном наборе межфайловый повтор, на котором такой подход окупается.
Публичный репозиторий с бинарными релизами и коротким smoke-скриптом (в процессе еще fuse, ffi уже есть): github.com/MaxPer2005/maxpack
Автор: MaxLenPer
