web-dev-qa-db-ja.com

Gzip圧縮でデータの重複したチャンクが削除されないのはなぜですか?

圧縮を行うかどうかを確認するために、重複するファイルを含む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
$ 

まず、ランダムデータの1MiBファイルを作成しました(a)。次に、それをファイルbにコピーし、cにもハーリンクしました。 tarballは〜2MiBであり、〜3Mibではなかったため、tarballを作成するとき、tarはハードリンクを明らかに認識していました。

Aとbは重複しているので、gzipでtarballのサイズを最大1MiBに削減すると予想しました。tarball内で1MiBの連続データが繰り返されるはずですが、これは発生しませんでした。

どうしてこれなの?そして、どのように私はこれらの場合に効率的にtarballを圧縮できますか?

30
Guido

Gzip gzipは、LZ77とハフマンコーディングを組み合わせたDEFLATEアルゴリズムに基づいています。それは、オンザフライで構築された辞書を使用して入力ストリームを圧縮されたシンボルに変換し、重複を監視することによって機能するロスレスデータ圧縮アルゴリズムです。ただし、32K以上離れている重複は検出できません。重複を1MB離れて見つけることを期待することは現実的ではありません。

24
Nicole Hamilton

ニコールハミルトンは正しく注記します 辞書サイズが小さいため、gzipは遠くにある重複データを検出しません。

bzip2は、メモリが900 KBに制限されているため、似ています。

代わりに、試してください:

LZMA/LZMA2アルゴリズム(xz7z

LZMAアルゴリズムはDeflateと同じファミリーにありますが、はるかに大きい辞書サイズを使用します(カスタマイズ可能、デフォルトは384 MBなど)。最新のLinuxディストリビューションにデフォルトでインストールされるxzユーティリティは、gzipに似ており、LZMAを使用します。

LZMAはより長い範囲の冗長性を検出するため、ここでデータを重複排除できます。ただし、Gzipよりも低速です。

別のオプションは7-Zip(7zパッケージのp7Zip)です。これは、デフォルトでLZMAを使用する(LZMAの作成者によって記述された)アーカイバ(単一ストリームコンプレッサではなく)です。 7-Zipアーカイバは、.7z形式にアーカイブするときに、ファイルレベルで(同じ拡張子のファイルを調べて)独自の重複排除を実行します。つまり、tar7zに置き換えても、同じファイルが重複排除されます。ただし、7zはナノ秒のタイムスタンプ、権限、またはxattrsを保持しないため、ニーズに合わない場合があります。

lrzip

lrzip は、Gzip/Deflate、bzip2、lzop、LZMAなどの従来のアルゴリズムにデータを送る前に、データを前処理して長距離冗長性を削除するコンプレッサーです。ここで提供するサンプルデータの場合、これは必要ありません。これは、入力データがメモリに収まるデータよりも大きい場合に役立ちます。

この種のデータ(重複した非圧縮チャンク)の場合、lzoplrzip圧縮(非常に高速)を使用する必要があります。これは、重複排除されたランダムデータを完全に圧縮しようとするメリットがないためです。

バップとオブナム

質問 backup をタグ付けしたため、ここでの目標がデータのバックアップである場合は、 Bup または Obnam のような重複排除バックアッププログラムの使用を検討してください。

39

gzipは重複を検出しません。巨大な辞書サイズのxzでも検出されません。あなたができることはmksquashfsを使うことです-これは確かに複製のスペースを節約します。

xzmksquashfsを使用したいくつかの簡単なテスト結果。3つのランダムバイナリファイル(64MB)のうち、2つは同じです:

セットアップ:

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
2
Izzy

バックアップの場合、可能性のある小さなファイルのセットが大量にある場合、うまくいくかもしれない1つのトリックは、tar内のファイルを拡張子で並べ替えることです。

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

「機械式カタツムリの答えへの追加として:

非圧縮の単一ファイルのファイルサイズ(正確には、重複間の距離)が辞書のサイズを超える場合、xz(またはlzma)でも重複は検出されません。 xz(またはlzma)は、最高の設定であっても、-9eは64MBしか予約しません。

幸いにも、オプション--lzma2=dict=256MBで独自の辞書サイズを指定できます(コマンドにlzmaエイリアスを使用する場合は--lzma1=dict=256MBのみが許可されます)

残念ながら、上記の例のようにカスタム圧縮チェーンで設定を上書きすると、他のすべてのパラメーターのデフォルト値が-9eと同じレベルに設定されません。したがって、圧縮密度は単一ファイルの場合ほど高くありません。

1
Chaos_99

私のシステムではlzma test.tarは、106'3175バイト(1.1M)のtest.tar.lzmaファイルになります。

1
rmweiss