Алгоритм LZMA/LZMA2 ( xz, 7z)

Алгоритм LZMA/LZMA2 ( xz, 7z)

Я только что провел небольшой эксперимент, создав архив tar с дубликатами файлов, чтобы посмотреть, будет ли он сжат, и, к моему великому изумлению, этого не произошло! Подробности ниже (результаты отступлены для удобства чтения):

$ dd if=/dev/urandom bs=1M count=1 of=a
  1+0 records in
  1+0 records out
  1048576 bytes (1.0 MB) copied, 0.114354 s, 9.2 MB/s
$ cp a b
$ ln a c
$ ll
  total 3072
  -rw-r--r-- 2 guido guido 1048576 Sep 24 15:51 a
  -rw-r--r-- 1 guido guido 1048576 Sep 24 15:51 b
  -rw-r--r-- 2 guido guido 1048576 Sep 24 15:51 c
$ tar -c * -f test.tar
$ ls -l test.tar 
  -rw-r--r-- 1 guido guido 2109440 Sep 24 15:51 test.tar
$ gzip test.tar 
$ ls -l test.tar.gz 
  -rw-r--r-- 1 guido guido 2097921 Sep 24 15:51 test.tar.gz
$ 

Сначала я создал файл случайных данных размером 1 МБ (a). Затем я скопировал его в файл b и также связал его с c. При создании tarball tar, по-видимому, знал о жесткой ссылке, поскольку tarball был всего ~2 МБ, а не ~3 МБ.

Я ожидал, что gzip уменьшит размер tarball примерно до 1 МБ, поскольку a и b являются дубликатами, а внутри tarball должен быть 1 МБ непрерывных повторяющихся данных, но этого не произошло.

Почему это так? И как мне эффективно сжать tarball в этих случаях?

решение1

Gzip gzip основан на алгоритме DEFLATE, который представляет собой комбинацию кодирования LZ77 и Хаффмана. Это алгоритм сжатия данных без потерь, который преобразует входной поток в сжатые символы с помощью словаря, созданного на лету, и отслеживает дубликаты. Но он не может найти дубликаты, разделенные более чем 32 КБ. Ожидать, что он обнаружит дубликаты, разделенные 1 МБ, нереально.

решение2

Николь Гамильтон правильно отмечаеткоторый gzipне сможет найти удаленные дубликаты данных из-за небольшого размера словаря.

bzip2похож, так как ограничен 900 КБ памяти.

Вместо этого попробуйте:

Алгоритм LZMA/LZMA2 ( xz, 7z)

Алгоритм LZMA относится к тому же семейству, что и Deflate, но использует гораздо больший размер словаря (настраиваемый; по умолчанию около 384 МБ). Утилита xz, которая должна быть установлена ​​по умолчанию в большинстве последних дистрибутивов Linux, похожа на gzipLZMA и использует его.

Поскольку LZMA обнаруживает избыточность на больших расстояниях, он сможет дедуплицировать ваши данные здесь. Однако это медленнее, чем Gzip.

Другой вариант — 7-zip ( 7zв p7zipпакете), который является архиватором (а не однопоточным компрессором), который по умолчанию использует LZMA (написанный автором LZMA). Архиватор 7-zip запускает собственную дедупликацию на уровне файлов (просматривая файлы с одинаковым расширением) при архивировании в свой .7zформат. Это означает, что если вы готовы заменить tarна 7z, вы получите идентичные дедуплицированные файлы. Однако 7z не сохраняет наносекундные временные метки, разрешения или xattrs, поэтому он может не подойти вам.

lrzip

lrzipэто компрессор, который предварительно обрабатывает данные, чтобы удалить избыточность на больших расстояниях, прежде чем подавать их в обычный алгоритм, такой как Gzip/Deflate, bzip2, lzop или LZMA. Для данных примера, которые вы здесь приводите, это не обязательно; это полезно, когда входные данные больше, чем то, что может поместиться в памяти.

Для такого рода данных (дублированные несжимаемые фрагменты) следует использовать lzopсжатие (очень быстрое) с помощью lrzip, поскольку нет смысла пытаться сильнее сжать полностью случайные данные после того, как они были дедуплицированы.

Буп и Обнам

Поскольку вы отметили вопросЕсли вашей целью является резервное копирование данных, рассмотрите возможность использования дедуплицирующей программы резервного копирования, напримерБапилиОбнам.

решение3

gzipне найдет дубликатов, даже xzпри огромном размере словаря не найдет. Что вы можете сделать, так это использовать mksquashfs- это действительно сэкономит место дубликатов.

Некоторые быстрые результаты тестирования с xzтремя mksquashfsслучайными двоичными файлами (64 МБ), два из которых одинаковы:

Настраивать:

mkdir test
cd test
dd if=/dev/urandom of=test1.bin count=64k bs=1k
dd if=/dev/urandom of=test2.bin count=64k bs=1k
cp test{2,3}.bin
cd ..

Сквошфс:

mksquashfs test/ test.squash
> test.squash - 129M

хз:

XZ_OPT='-v --memlimit-compress=6G --memlimit-decompress=512M --lzma2=preset=9e,dict=512M --extreme -T4 ' tar -cJvf test.tar.xz test/
> test.tar.xz - 193M

решение4

В дополнение к ответу «механической улитки»:

Даже xz (или lzma) не найдет дубликаты, если размер несжатого отдельного файла (или, точнее, расстояние между дубликатами) превышает размер словаря. xz (или lzma) даже на самых высоких настройках -9eрезервирует для этого только 64 МБ.

К счастью, вы можете указать свой собственный размер словаря с помощью опции --lzma2=dict=256MB ( --lzma1=dict=256MBэто разрешено только при использовании псевдонима lzma для команды)

К сожалению, при переопределении настроек с помощью пользовательских цепочек сжатия, как в примере выше, значения по умолчанию для всех остальных параметров не устанавливаются на том же уровне, что и при -9e. Поэтому плотность сжатия не такая высокая для отдельных файлов.

Связанный контент