¿Por qué la compresión Gzip no elimina fragmentos duplicados de datos?


30

¡Acabo de hacer un pequeño experimento en el que creé un archivo tar con archivos duplicados para ver si se comprimiría, para mi asombro, no fue así! Los detalles siguen (resultados sangrados por placer de lectura):

$ 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
$ 

Primero creé un archivo de 1MiB de datos aleatorios (a). Luego lo copié en un archivo b y también lo vinculé a c. Al crear el tarball, tar aparentemente era consciente del enlace rígido, ya que el tarball era solo ~ 2MiB y no ~ 3Mib.

Ahora esperaba que gzip redujera el tamaño del tarball a ~ 1MiB ya que a y b son duplicados, y debería haber 1MiB de datos continuos repetidos dentro del tarball, sin embargo, esto no ocurrió.

¿Por qué es esto? ¿Y cómo podría comprimir el tarball de manera eficiente en estos casos?

Respuestas:


24

Gzip gzip se basa en el algoritmo DEFLATE, que es una combinación de codificación LZ77 y Huffman. Es un algoritmo de compresión de datos sin pérdidas que funciona transformando el flujo de entrada en símbolos comprimidos utilizando un diccionario construido sobre la marcha y buscando duplicados. Pero no puede encontrar duplicados separados por más de 32K. Esperar que detecte duplicados separados por 1 MB no es realista.


¡Lo suficientemente justo! ¿Conoces alguna alternativa que no funcione en las transmisiones?
Guido

1
No conozco ninguna solución empaquetada para su problema. Si esperaba que esto fuera un problema grave y recurrente, (personalmente) lo atacaría con un script que realizara las operaciones cmp (comparar) n-way para encontrar duplicados, escribir la lista en un archivo, luego tar + gzip solo el artículos únicos + la lista. Para restaurar, usaría un segundo script para descomprimir y descomprimir, luego crearía los duplicados de la lista. Otra alternativa sería convertir los dups en enlaces duros, ya que sabe que tar los detecta. Lo siento, sé que probablemente eso no sea lo que esperabas.
Nicole Hamilton

1
gzip y bzip2 tienen que ser relativamente "compatibles con la transmisión" debido a su diseño; es absolutamente necesario poder trabajar como parte de una tubería. Lo que está buscando aquí es en realidad deduplicación y no solo compresión. Como tar divide el proceso en dos partes: archiva solo con tar y luego usa un segundo programa como filtro para comprimir. No pude encontrar ningún archivo comprimido con deduplicación en mis búsquedas, pero encontré esta pregunta anterior relacionada. superuser.com/questions/286414/…
Stephanie

2
@Stephanie, NicoleHamilton: Hay en.wikipedia.org/wiki/Lrzip#Lrzip .
Caracol mecánico

1
@Guido Por supuesto, nada puede eliminar duplicados de algo que no recuerda en una transmisión, pero intente algo como xz -9 -M 95%, o incluso xz -M 95% --lzma2=preset=9,dict=1610612736. No será rápido, pero es poco probable que sus duplicados se queden en el resultado.
Eroen

39

Nicole Hamilton señala correctamente que gzipno encontrará datos duplicados distantes debido a su pequeño tamaño de diccionario.

bzip2 es similar, porque está limitado a 900 KB de memoria.

En cambio, intente:

Algoritmo LZMA / LZMA2 ( xz, 7z)

El algoritmo LZMA pertenece a la misma familia que Deflate, pero utiliza un tamaño de diccionario mucho mayor (personalizable; el valor predeterminado es algo así como 384 MB). La xzutilidad, que debe instalarse de forma predeterminada en las distribuciones de Linux más recientes, es similar gzipy utiliza LZMA.

A medida que LZMA detecte redundancia de mayor alcance, podrá deduplicar sus datos aquí. Sin embargo, es más lento que Gzip.

Otra opción es 7-zip ( 7z, en el p7zippaquete), que es un archivador (en lugar de un compresor de flujo único) que usa LZMA de forma predeterminada (escrito por el autor de LZMA). El archivador 7-zip ejecuta su propia deduplicación a nivel de archivo (mirando archivos con la misma extensión) cuando archiva a su .7zformato. Esto significa que si usted está dispuesto a sustituir tarcon 7z, a obtener los archivos idénticos deduplicados. Sin embargo, 7z no conserva las marcas de tiempo, permisos o xattrs de nanosegundos, por lo que puede no satisfacer sus necesidades.

lrzip

lrzipes un compresor que procesa previamente los datos para eliminar la redundancia de larga distancia antes de alimentarlos a un algoritmo convencional como Gzip / Deflate, bzip2, lzop o LZMA. Para los datos de muestra que proporcione aquí, no es necesario; es útil para cuando los datos de entrada son más grandes de lo que cabe en la memoria.

Para este tipo de datos (fragmentos incompresibles duplicados), debe usar la lzopcompresión (muy rápido) lrzip, ya que no es beneficioso esforzarse más por comprimir datos completamente aleatorios una vez que se han deduplicado.

Bup y Obnam

Dado que etiquetó la la pregunta , si su objetivo aquí es hacer una copia de seguridad de los datos, considere usar un programa de copia de seguridad de deduplicación como Bup u Obnam .


Este lrzip se ve interesante. Incluso tiene un autor conocido por soluciones no tradicionales. Ahora tendré que revisar mis scripts de respaldo. Otra vez.
Eroen

3
+1 Wow, qué fuente de conocimiento / experiencia allí. Apreciado. ¿Puedo agregar sistemas de archivos con deduplicación habilitada a la mezcla? ZFS (y, creo que Btrfs está programado para tenerlo) - trabajaría con el bloque alineado duplicación
sehe

¡7Zip con compresión LZMA2 y un tamaño de diccionario de 1536Mb (tamaño máximo disponible en la GUI de Windows) me funciona muy bien!
Leopoldo Sanczyk

2

En el caso de una copia de seguridad, posiblemente con un conjunto grande de archivos más pequeños, un truco que podría funcionar para usted es ordenar los archivos en el tar por extensión:

find archive_dir -type f | rev | sort | rev | tar czf my_archive.tar.gz -I -

Cortaría todos los rev's (¿por qué incluso revertir y luego ordenar?) Y miraría la sortopción "-r, --reverse" (aunque no estoy seguro de por qué querrías revertir). Pero creo que su taropción " -I" no hace lo que cree que hace " -I, --use-compress-program PROG" , probablemente quiera "-T, --files-from FILE"
Xen2050

Creo que | tar czf my_archive.tar.gz -I -debería ser| xargs tar Azf my_archive.tar.gz
Olivier Dulac

@ Xen2050, revinvierte el orden de los caracteres en cada línea, no el orden de las líneas en la secuencia. Debido a esto, sortagrupa los archivos por su extensión. Sospecho que -I -debería haber sido -T -, que proporciona la lista de archivos en stdin.
billyjmc

@billyjmc Ya veo, eso revse organizaría por extensión, no es que haya muchas extensiones en Linux de todos modos. Me imagino que ordenar por tamaño tendría una mayor probabilidad de encontrar dup's
Xen2050

2

gzipno encontrará duplicados, incluso xzcon un gran tamaño de diccionario no lo hará. Lo que puede hacer es usar mksquashfs: esto de hecho ahorrará el espacio de los duplicados.

Algunos resultados de pruebas rápidas con xzy mksquashfscon tres archivos binarios aleatorios (64 MB) de los cuales dos son iguales:

Preparar:

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 ..

Squashfs:

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

xz:

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

¿Mksquashfs solo encuentra duplicados a nivel de archivo o también funciona en fragmentos más pequeños? Es decir: ¿Comprimirá también archivos ligeramente diferentes pero en su mayoría iguales?
Chaos_99

Esto funciona afaik solo en base a archivos. Puede ver eso al tatear esos tres archivos de prueba en un archivo tar no comprimido y luego comprimirlos con mksquashfs. Por otro lado, mksqashfs informará, cuando encuentre duplicados con Number of duplicate files foundin stdout.
Izzy

1

En mi sistema se lzma test.tarobtiene un archivo test.tar.lzma de 106'3175 bytes (1.1M)


1

Como una adición a la respuesta del 'caracol mecánico:

Incluso xz (o lzma) no encontrará duplicados si el tamaño del archivo sin comprimir (o, más exactamente, la distancia entre los duplicados) excede el tamaño del diccionario. xz (o lzma) incluso en la configuración más alta -9esolo reserva 64 MB para esto.

Afortunadamente, puede especificar su propio tamaño de diccionario con la opción --lzma2=dict=256MB (solo --lzma1=dict=256MBse permite cuando se usa el alias lzma para el comando)

Desafortunadamente, al anular la configuración con cadenas de compresión personalizadas, como se muestra en el ejemplo anterior, los valores predeterminados para todos los demás parámetros no se establecen en el mismo nivel que con -9e. Por lo tanto, la densidad de compresión no es tan alta para archivos individuales.


-2

gzip sin conmutadores de línea de comando utiliza el algoritmo más bajo posible para la compresión.

Intenta usar:

gzip -9 test.tar

Deberías obtener mejores resultados


1
En realidad no, la diferencia es mínima. También probé bzip2 con resultados similares.
Guido

gzip sin conmutadores de línea de comando utiliza el algoritmo más bajo posible para la compresión. => Esto no es cierto: "man gzip" afirma que "(el) nivel de compresión predeterminado es -6 (es decir, sesgado hacia una compresión alta a expensas de la velocidad)". Esto es cierto para todas las versiones de gzip que conozco, si la variable de entorno GZIP anula la configuración predeterminada compilada. Incluso el nivel "-9" no lo ayudará aquí, como ya se explicó en las respuestas dadas.
Gunter Ohrner
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.