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


30

圧縮ファイルが圧縮されるかどうかを確認するために、重複ファイルで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は〜3Mibではなく〜2MiBのみであったため、tarballを作成するとき、tarは明らかにハードリンクを認識していました。

aとbは重複しているため、gzipがtarballのサイズを〜1MiBに縮小し、tarball内で1MiBの連続データが繰り返されるはずであるが、これは発生しませんでした。

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

回答:


24

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


けっこうだ!ストリームで機能しない代替手段を知っていますか?
グイド

1
パッケージ化された問題の解決策は知りません。これが繰り返し深刻な問題になると予想した場合、n-way cmp(比較)操作を行って重複を見つけ、リストをファイルに書き込み、tar + gzipのみを実行するスクリプトを使用して攻撃しますユニークなアイテム+リスト。復元するには、2番目のスクリプトを使用してzip圧縮を解除し、tarを解凍してから、リストから重複を作成します。別の選択肢は、DARがハードリンクに変換することです。これは、tarがそれらを見つけることがわかっているためです。申し訳ありませんが、それはおそらくあなたが望んでいたものではないことを知っています。
ニコールハミルトン

1
gzipとbzip2はどちらも、その設計上、比較的「ストリームフレンドリー」である必要があります。パイプの一部として機能することが絶対に必要です。ここで探しているのは、圧縮だけではなく、実際には重複排除です。tarはプロセスを2つの部分に分割するため、tarのみでアーカイブし、2つ目のプログラムをフィルターとして使用して圧縮します。検索で重複排除を含む圧縮アーカイブを見つけることができませんでしたが、この前の関連する質問を見つけました。superuser.com/questions/286414/…–
ステファニー

2
@ Stephanie、NicoleHamilton:en.wikipedia.org/wiki/Lrzip#Lrzipがあります。
機械式カタツムリ

1
@Guidoもちろん、ストリームで覚えていないものの重複を削除することはできませんが、、xz -9 -M 95%またはのようなものを試してくださいxz -M 95% --lzma2=preset=9,dict=1610612736。高速ではありませんが、重複が結果に残ることはほとんどありません。
エローエン

39

ニコール・ハミルトンはgzip、辞書のサイズが小さいため、遠く離れた重複データを見つけられないと正しく指摘しています。

bzip2 900 KBのメモリに制限されているため、同様です。

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

LZMA / LZMA2アルゴリズム(xz7z

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

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

別のオプションは、7-ZIP(ある7z、中p7zip(LZMAの著者によって書かれた)デフォルトでLZMAを使用アーカイバ(よりむしろ単一ストリームの圧縮機)である、パッケージ)。7-zipアーカイバーは、その.7zフォーマットにアーカイブするときに、ファイルレベルで同じ重複排除を実行します(同じ拡張子のファイルを参照)。これは、で置き換えtarても構わない場合7z、重複排除された同一のファイルを取得することを意味します。ただし、7zはナノ秒のタイムスタンプ、アクセス許可、またはxattrsを保持しないため、ニーズに合わない場合があります。

lrzip

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

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

バップとオブナム

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


このlrzipは面白そうです。非伝統的なソリューションで知られる著者もいます。次に、バックアップスクリプトを修正する必要があります。再び。
エローエン

3
+1うわー、そこには知識/経験の泉があります。感謝。重複除去が有効なファイルシステムをミックスに追加できますか?ZFS(そして、Btrfsにはそれがあると思われます)-ブロックアライメント複製で動作します
sehe

LZMA2圧縮と1536Mbの任意サイズ(Windows GUIで使用可能な最大サイズ)を使用した7Zipは、私にとってはうまく機能します!
レオポルドサンチク16年

2

バックアップの場合、おそらく小さなファイルの大きなセットで、あなたのために働くかもしれない1つのトリックは、拡張子でtar内のファイルをソートすることです:

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

すべてのrev'を切り取って(なぜ逆に並べ替えますか?)sortオプション"-r、--reverse"を調べます(なぜ逆にしたいのかわからないのですが)。しかし、私はあなただと思うtarオプションは「-I」あなたはどう思うか、それはないんしない-I, --use-compress-program PROG、あなたはおそらくしたい 「-T、--files-からFILE」
Xen2050

ある| tar czf my_archive.tar.gz -I -べきだと思う| xargs tar Azf my_archive.tar.gz
オリビエデュラック

@ Xen2050 revは、ストリーム内の行の順序ではなく、各行の文字の順序を逆にします。このためsort、ファイルを拡張子でグループ化します。-I -はずだったはずで-T -、stdinのファイルリストを提供します。
billyjmc

@billyjmcなるほど、それrevは一種の拡張機能によるもので、Linuxには多くの拡張機能があるとは限りません。サイズでソートすると、
重複

2

gzipxz巨大な辞書サイズでも、重複は見つかりません。あなたができることは使用ですmksquashfs-これは確かに重複のスペースを節約します。

3つのランダムバイナリファイル(64MB)を使用した場合xzと使用mksquashfsした場合のクイックテスト結果(そのうち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

mksquashfsはファイルレベルの重複のみを検出しますか、それとも小さなチャンクでも動作しますか?つまり、わずかに異なるがほとんど同じファイルも圧縮しますか?
Chaos_99

これは、ファイル単位でのみ機能します。これらの3つのテストファイルを非圧縮tarアーカイブにテアリングし、その後mksquashfsで圧縮すると、そのことがわかります。一方、Number of duplicate files foundstdoutで重複を検出した場合、mksqashfsは報告します。
イジー

1

私のシステムlzma test.tarでは、106'3175バイト(1.1M)のtest.tar.lzmaファイルが生成されます


1

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

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

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

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


-2

コマンドラインスイッチのないgzipは、圧縮に可能な限り低いアルゴリズムを使用します。

使用してみてください:

gzip -9 test.tar

より良い結果が得られるはずです


1
実際には、違いはわずかです。同様の結果でbzip2も試しました。
グイド

コマンドラインスイッチのないgzipは、圧縮に可能な限り低いアルゴリズムを使用します。=>これは正しくありません-「man gzip」は「(t)デフォルトの圧縮レベルは-6(つまり、速度を犠牲にして高圧縮に偏っている)」と述べています。これは、コンパイル済みのデフォルト設定がGZIP環境変数によって上書きされない場合、私が知っているすべてのgzipバージョンに当てはまります。与えられた回答ですでに説明したように、レベル「-9」でさえここでは役に立ちません。
ガンターオーナー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.