ทำไมการบีบอัด 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 นั้น tar นั้นรับรู้ถึงฮาร์ดลิงก์เนื่องจากทาร์บอลเป็นเพียง ~ 2MiB และไม่ใช่ ~ 3Mib

ตอนนี้ฉันคาดว่า gzip จะลดขนาดของ tarball เป็น ~ 1MiB เนื่องจาก a และ b ซ้ำกันและควรมี 1MiB ของข้อมูลอย่างต่อเนื่องซ้ำใน tarball แต่สิ่งนี้ไม่ได้เกิดขึ้น

ทำไมนี้ และฉันจะอัด tarball ได้อย่างมีประสิทธิภาพในกรณีเหล่านี้ได้อย่างไร?

คำตอบ:


24

Gzip gzip ขึ้นอยู่กับอัลกอริทึม DEFLATE ซึ่งเป็นการรวมกันของการเข้ารหัส LZ77 และ Huffman มันเป็นอัลกอริธึมการบีบอัดข้อมูลแบบไม่สูญเสียที่ทำงานโดยการแปลงกระแสข้อมูลให้เป็นสัญลักษณ์ที่ถูกบีบอัดโดยใช้พจนานุกรมที่สร้างขึ้นทันทีและดูซ้ำซ้อน แต่ไม่สามารถค้นหารายการที่ซ้ำกันที่คั่นด้วยมากกว่า 32K การคาดหวังว่าจะพบจุดที่ซ้ำกัน 1MB นั้นไม่เหมือนจริง


ยุติธรรมพอ! คุณรู้ทางเลือกอื่น ๆ ที่ไม่ได้ทำงานบนสตรีมหรือไม่
Guido

1
ฉันไม่ทราบวิธีแก้ไขปัญหาของคุณแบบแพคเกจใด ๆ หากฉันคาดว่านี่จะเป็นปัญหาที่เกิดซ้ำและร้ายแรงฉัน (ส่วนตัว) จะโจมตีสคริปต์ที่ใช้การดำเนินการ n-way cmp (เปรียบเทียบ) เพื่อค้นหารายการที่ซ้ำกันเขียนรายการลงในไฟล์จากนั้น tar + gzip เท่านั้น รายการที่ไม่ซ้ำกัน + รายการ ในการกู้คืนฉันจะใช้สคริปต์ตัวที่สองเพื่อ ungzip และ untar จากนั้นสร้าง dups จากรายการ อีกทางเลือกหนึ่งคือเปลี่ยน dups ให้เป็นฮาร์ดลิงก์เนื่องจากคุณรู้ว่า tar สามารถมองเห็นสิ่งเหล่านั้นได้ ขออภัยฉันรู้ว่านั่นอาจไม่ใช่สิ่งที่คุณคาดหวัง
Nicole Hamilton

1
gzip และ bzip2 ทั้งคู่ต้องมี "สตรีมที่เป็นมิตร" เนื่องจากการออกแบบของพวกเขา - จำเป็นอย่างยิ่งที่จะต้องสามารถทำงานเป็นส่วนหนึ่งของท่อได้ สิ่งที่คุณกำลังมองหาที่นี่คือการขจัดข้อมูลซ้ำซ้อนและไม่ใช่แค่การบีบอัดข้อมูล ตั้งแต่ tar แบ่งกระบวนการออกเป็นสองส่วน - เก็บถาวรด้วย tar เท่านั้นแล้วใช้โปรแกรมที่สองเป็นตัวกรองเพื่อบีบอัด ฉันไม่พบไฟล์เก็บถาวรที่บีบอัดซึ่งมีการคัดลอกซ้ำในการค้นหาของฉัน แต่ฉันพบคำถามที่เกี่ยวข้องก่อนหน้านี้ 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มันจะไม่เร็ว แต่สิ่งที่คุณทำซ้ำจะไม่ปรากฏในผลลัพธ์
Eroen

39

นิโคลแฮมิลตันได้อย่างถูกต้องบันทึกว่าgzipจะไม่พบข้อมูลที่ซ้ำกันไกลเนื่องจากขนาดพจนานุกรมขนาดเล็ก

bzip2 คล้ายกันเนื่องจากมี จำกัด หน่วยความจำ 900 KB

ให้ลอง:

อัลกอริทึม LZMA / LZMA2 ( xz, 7z)

อัลกอริทึม LZMA อยู่ในตระกูลเดียวกับ Deflate แต่ใช้ขนาดพจนานุกรมที่ใหญ่กว่ามาก (ปรับแต่งได้ค่าเริ่มต้นคือ 384 MB) xzยูทิลิตี้ซึ่งควรจะติดตั้งโดยเริ่มต้นในที่สุด distros ลินุกซ์ที่ผ่านมาจะคล้ายกับgzipและการใช้ LZMA

เนื่องจาก LZMA ตรวจจับความซ้ำซ้อนในระยะยาวมันจะสามารถทำซ้ำข้อมูลของคุณได้ที่นี่ อย่างไรก็ตามมันช้ากว่า Gzip

ตัวเลือกอื่นคือ 7-zip ( 7zในp7zipแพ็คเกจ) ซึ่งเป็นผู้จัดเก็บ (แทนที่จะเป็น single-stream compressor) ที่ใช้ LZMA เป็นค่าเริ่มต้น (เขียนโดยผู้เขียน LZMA) Archiver 7-zip รันการลดความซ้ำซ้อนของตัวเองที่ระดับไฟล์ (ดูไฟล์ที่มีนามสกุลเดียวกัน) เมื่อจัดเก็บใน.7zรูปแบบ ซึ่งหมายความว่าหากคุณต้องการแทนที่tarด้วย7zคุณจะได้รับไฟล์ซ้ำกันซ้ำซ้อน อย่างไรก็ตาม 7z ไม่ได้เก็บรักษาบันทึกเวลาของ nanosecond สิทธิ์หรือ xattrs ดังนั้นจึงอาจไม่เหมาะกับความต้องการของคุณ

lrzip

lrzipเป็นคอมเพรสเซอร์ที่ประมวลผลข้อมูลล่วงหน้าเพื่อลบความซ้ำซ้อนทางไกลก่อนส่งไปยังอัลกอริทึมทั่วไปเช่น Gzip / Deflate, bzip2, lzop หรือ LZMA สำหรับข้อมูลตัวอย่างที่คุณให้ไว้ที่นี่ไม่จำเป็น มันมีประโยชน์สำหรับเมื่อข้อมูลอินพุตมีขนาดใหญ่กว่าสิ่งที่สามารถใส่ในหน่วยความจำ

สำหรับข้อมูลประเภทนี้ (ชิ้นส่วนที่ไม่สามารถบีบอัดได้ซ้ำ) คุณควรใช้การlzopบีบอัด (เร็วมาก) ด้วยlrzipเนื่องจากไม่มีประโยชน์ในการพยายามบีบอัดข้อมูลแบบสุ่มอย่างสมบูรณ์เมื่อมันซ้ำซ้อน

Bup และ Obnam

เนื่องจากคุณแท็กคำถามถ้าเป้าหมายของคุณที่นี่คือการสำรองข้อมูลให้พิจารณาการใช้โปรแกรมสำรองข้อมูล deduplicating เช่นBupหรือObnam


lrzip นี้ดูน่าสนใจ มันยังมีผู้เขียนรู้จักโซลูชั่นที่ไม่ใช่แบบดั้งเดิม ตอนนี้ฉันจะต้องแก้ไขสคริปต์สำรองของฉัน อีกครั้ง
Eroen

3
+1 ว้าวช่างเป็นแหล่งความรู้ / ประสบการณ์ตรงนั้น ชื่นชม ฉันสามารถเพิ่มระบบไฟล์ที่เปิดใช้งานการหักสำรองในการผสมได้ไหม ZFS (และฉันคิดว่า Btrfs มีกำหนดที่จะมี) - จะทำงานร่วมกับการทำซ้ำบล็อกชิด
sehe

7Zip ใช้การบีบอัด LZMA2 และขนาด dicctionary ขนาด 1536Mb (ขนาดสูงสุดที่มีใน Windows GUI) ใช้งานได้ดีสำหรับฉัน!
Leopoldo Sanczyk

2

ในกรณีที่มีการสำรองข้อมูลอาจมีไฟล์ขนาดเล็กชุดใหญ่เคล็ดลับอย่างหนึ่งที่อาจใช้งานได้สำหรับคุณคือจัดเรียงไฟล์ใน 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-from FILE"
Xen2050

ฉันเชื่อว่าน่า| tar czf my_archive.tar.gz -I -จะเป็น| xargs tar Azf my_archive.tar.gz
Olivier Dulac

@ Xen2050 revกลับคำสั่งของตัวละครในแต่ละบรรทัดไม่ใช่ลำดับบรรทัดในสตรีม ด้วยเหตุนี้จึงsortจัดกลุ่มไฟล์ตามส่วนขยาย ฉันสงสัยว่า-I -ควรได้รับ-T -ซึ่งให้รายชื่อไฟล์ใน stdin
billyjmc

@billyjmc ฉันเห็นว่าrevจะจัดเรียงตามนามสกุลไม่ใช่ว่ามีส่วนขยายจำนวนมากใน linux อยู่แล้ว ฉันคิดว่าการเรียงลำดับตามขนาดจะมีโอกาสสูงกว่าในการค้นหาคู่ของ
Xen2050

2

gzipจะไม่พบข้อมูลที่ซ้ำกันแม้จะxzมีพจนานุกรมขนาดใหญ่ก็ตาม สิ่งที่คุณสามารถทำได้คือใช้mksquashfs- สิ่งนี้จะช่วยประหยัดพื้นที่ในการทำซ้ำ

ผลการทดสอบอย่างรวดเร็วบางอย่างที่มีxzและmksquashfsมีไฟล์ไบนารีสุ่มสามไฟล์ (64MB) ซึ่งมีสองไฟล์เหมือนกัน:

ติดตั้ง:

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

ใช้งานได้กับไฟล์แบบ Afaik เท่านั้น คุณจะเห็นว่าเมื่อทำการทดสอบไฟล์สามไฟล์เหล่านั้นลงในไฟล์เก็บถาวร tar ที่ไม่ได้บีบอัดและบีบอัดไฟล์ด้วย mksquashfs หลังจากนั้น ในทางกลับกัน mksqashfs จะรายงานเมื่อค้นหารายการที่ซ้ำกับNumber of duplicate files foundใน stdout
Izzy


1

ในฐานะที่เป็นนอกเหนือไปจาก 'คำตอบของหอยทากกล:

แม้ xz (หรือ lzma) จะไม่พบข้อมูลซ้ำหากขนาดไฟล์ของไฟล์เดี่ยวที่ไม่ได้บีบอัด (หรือแม่นยำยิ่งขึ้นระยะทางระหว่างรายการที่ซ้ำกัน) เกินขนาดพจนานุกรม xz (หรือ lzma) แม้ในการตั้งค่าสูงสุด-9eจะจองเพียง 64MB สำหรับสิ่งนี้

โชคดีที่คุณสามารถระบุขนาด dictonary ของคุณเองด้วยตัวเลือก--lzma2=dict=256MB ( --lzma1=dict=256MBอนุญาตเฉพาะเมื่อใช้ lzma alias กับคำสั่ง)

น่าเสียดายที่เมื่อแทนที่การตั้งค่าด้วยโซ่บีบอัดแบบกำหนดเองเช่นที่ระบุในตัวอย่างด้านบนค่าเริ่มต้นสำหรับพารามิเตอร์อื่น ๆ ทั้งหมดจะไม่ถูกตั้งค่าในระดับเดียวกับ -9e ดังนั้นความหนาแน่นของการบีบอัดจึงไม่สูงสำหรับไฟล์เดียว


-2

gzip ที่ไม่มีสวิตช์บรรทัดคำสั่งใช้อัลกอริธึมที่เป็นไปได้ต่ำที่สุดสำหรับการบีบอัด

ลองใช้:

gzip -9 test.tar

คุณควรได้ผลลัพธ์ที่ดีกว่า


1
ไม่จริงความแตกต่างน้อยที่สุด ฉันพยายาม bzip2 ด้วยผลลัพธ์ที่คล้ายกัน
Guido

gzip ที่ไม่มีสวิตช์บรรทัดคำสั่งใช้อัลกอริธึมที่เป็นไปได้ต่ำที่สุดสำหรับการบีบอัด => สิ่งนี้ไม่เป็นความจริง - "man gzip" ระบุว่า"(t) ระดับการบีบอัดเริ่มต้นของเขาคือ -6 (นั่นคือเอนเอียงไปสู่การบีบอัดสูงที่ค่าใช้จ่ายความเร็ว)" สิ่งนี้เป็นจริงสำหรับ gzip ทุกรุ่นที่ฉันรู้ถ้าการตั้งค่าเริ่มต้นที่คอมไพล์แล้วจะไม่ถูกแทนที่โดยตัวแปรสภาพแวดล้อม GZIP แม้แต่ระดับ "-9" จะไม่ช่วยคุณที่นี่ดังอธิบายไว้แล้วในคำตอบที่ให้
Gunter Ohrner
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.