การบีบอัดสตรีมแบบทันทีที่ไม่กระจายไปสู่ทรัพยากรฮาร์ดแวร์?


23

ฉันมีพื้นที่ว่างบนดิสก์ 200 GB, RAM 16 GB (ที่เดสก์ท็อปและเคอร์เนลประมาณ ~ 1 GB) และ swap 6 GB

ฉันมี SSD ภายนอก 240 GB ที่มี 70 GB ใช้1และที่เหลือฟรีซึ่งฉันต้องสำรองข้อมูลลงดิสก์

โดยปกติแล้วฉันต้องการdd if=/dev/sdb of=Desktop/disk.imgดิสก์ก่อนแล้วจึงบีบอัด แต่การสร้างอิมเมจก่อนไม่ใช่ตัวเลือกเนื่องจากการทำเช่นนั้นจะต้องใช้พื้นที่ดิสก์มากกว่าที่ฉันมีแม้ว่าขั้นตอนการบีบอัดจะส่งผลให้พื้นที่ว่างถูกบีบอัดดังนั้น ไฟล์เก็บถาวรสุดท้ายสามารถใส่ลงในดิสก์ของฉันได้อย่างง่ายดาย

ddเขียนไป STDOUT โดยค่าเริ่มต้นและgzipสามารถอ่านได้จาก STDIN ดังนั้นในทฤษฎีฉันจะเขียนdd if=/dev/sdb | gzip -9 -แต่gzipจะใช้เวลานานมากในการอ่านไบต์กว่าddสามารถผลิตได้

จากman pipe:

ข้อมูลที่เขียนไปยังปลายการเขียนของไพพ์จะถูกบัฟเฟอร์โดยเคอร์เนลจนกว่าจะถูกอ่านจากการอ่านที่ปลายของไพพ์

ฉันเห็นภาพความ|เป็นเหมือนไพพ์จริง - แอปพลิเคชั่นตัวหนึ่งผลักข้อมูลเข้าและอีกอันนำข้อมูลออกจากคิวของไพพ์โดยเร็วที่สุด

จะเกิดอะไรขึ้นเมื่อโปรแกรมทางด้านซ้ายเขียนข้อมูลได้เร็วกว่าอีกด้านหนึ่งของไปป์สามารถหวังที่จะประมวลผลได้ มันจะทำให้เกิดการใช้หน่วยความจำมากหรือการแลกเปลี่ยนหรือเคอร์เนลจะพยายามสร้าง FIFO บนดิสก์จึงเติมดิสก์? หรือมันจะล้มเหลวSIGPIPE Broken pipeถ้าบัฟเฟอร์มีขนาดใหญ่เกินไป?

โดยพื้นฐานแล้วสิ่งนี้จะลดลงเหลือสองคำถาม:

  1. อะไรคือความหมายและผลลัพธ์ของการผลักข้อมูลเข้าสู่ท่อมากกว่าที่อ่านได้ในแต่ละครั้ง?
  2. อะไรคือวิธีที่เชื่อถือได้ในการบีบอัดดาต้าสตรีมไปยังดิสก์โดยไม่ต้องบีบอัดดาต้าสตรีมทั้งหมดลงบนดิสก์

หมายเหตุ 1: ฉันไม่สามารถคัดลอก 70 GB แรกที่ใช้ไปอย่างแน่นอนและคาดว่าจะได้รับระบบการทำงานหรือระบบไฟล์เนื่องจากการแตกแฟรกเมนต์และสิ่งอื่น ๆ ซึ่งจะต้องใช้เนื้อหาแบบเต็มเพื่อให้สมบูรณ์


ทำไมคุณต้องสำรองข้อมูลทั้งระบบเช่นนั้นแทนที่จะเป็นไดเรกทอรีผู้ใช้และอาจเป็นรายการซอฟต์แวร์ที่ไม่ได้มาตรฐานที่ติดตั้งอยู่
jamesqf

5
@jamesqf เช่น เพราะมันง่ายกว่ามากที่จะกู้คืน ...
deviantfan

4
@jamesqf เพราะงั้นฉันก็จะได้บูตเซกเตอร์และพาร์ติชั่นการแลกเปลี่ยนเพื่อที่ฉันจะสามารถสร้างดิสก์ได้อย่างแม่นยำแทนที่จะมีไฟล์ที่น่ารำคาญนับพันไฟล์
แมว

3
ปลายสุ่ม: มองเข้าไปlzopแทนgzip; มันบีบอัดได้เร็วขึ้นมากโดยมีอัตราส่วนการบีบอัดที่ลดลงเล็กน้อย ฉันคิดว่ามันเหมาะสำหรับภาพดิสก์ที่ความเร็วการบีบอัดอาจเป็นปัญหาคอขวดจริง
marcelm

1
"จะเกิดอะไรขึ้นเมื่อโปรแกรมทางด้านซ้ายเขียนข้อมูลเร็วกว่าอีกด้านหนึ่งของไปป์สามารถหวังที่จะประมวลผลได้" เคอร์เนลจะทำให้กระบวนการเขียนเข้าสู่โหมดสลีจนกระทั่งมีที่ว่างมากขึ้นในไพพ์
Tavian Barnes

คำตอบ:


16

ในทางเทคนิคคุณไม่จำเป็นต้องdd:

gzip < /dev/drive > drive.img.gz

หากคุณใช้ddคุณควรมีขนาดใหญ่กว่าขนาดบล็อกเริ่มต้นที่ชอบdd bs=1Mหรือประสบนรก syscall เสมอ ( ddขนาดบล็อกเริ่มต้นคือ 512 ไบต์เนื่องจากread()เป็นwrite()ขนาด4096syscalls ต่อMiBค่าใช้จ่ายมากเกินไป)

gzip -9ใช้ CPU มากขึ้นและแสดงน้อยมาก หากgzipคุณทำให้ช้าลงลดระดับการบีบอัดหรือใช้วิธีการบีบอัด (เร็วกว่า) อื่น

หากคุณทำการสำรองข้อมูลโดยใช้ไฟล์แทนที่จะเป็นddรูปคุณอาจมีตรรกะบางอย่างที่ตัดสินใจว่าจะบีบอัดไฟล์ทั้งหมดหรือไม่ dar( tarทางเลือก `) เป็นตัวอย่างหนึ่งที่มีตัวเลือกให้ทำ

หากพื้นที่ว่างของคุณเป็นศูนย์ (เพราะเป็น SSD ที่ให้ผลตอบแทนเป็นศูนย์ได้อย่างน่าเชื่อถือหลังจาก TRIM และคุณรันfstrimและแคชหายไป) คุณยังสามารถใช้ddกับconv=sparseแฟล็กเพื่อสร้างอิมเมจแบบกระจายที่ไม่บีบอัดและติดตั้งได้ . ต้องการไฟล์รูปภาพที่จะสำรองข้อมูลโดยระบบไฟล์ที่รองรับไฟล์แบบกระจาย

อีกทางเลือกหนึ่งสำหรับระบบไฟล์บางโปรแกรมมีโปรแกรมที่สามารถอิมเมจพื้นที่ที่ใช้เท่านั้น


1
"ถ้าคุณใช้ dd คุณควรมีขนาดใหญ่กว่าขนาดบล็อกมาตรฐานอย่างdd bs=1M" - คุณทำได้ แต่อย่าคาดหวังมากเกินไป บนพีซีของฉันddจะทำประมาณ 2GB / s ด้วยบล็อก 512- ไบต์ นั่นจะไม่เป็นคอขวด; gzipจะ.
marcelm

@marcelm เราไม่เคยรู้เลยว่าเครื่องจักรแบบไหนที่คนใช้ หากคุณมีdd2GB / s ที่มีบล็อก 512- ไบต์ฉันจะประหลาดใจถ้ามันไม่ได้เพิ่มซีพียูหลัก 100% ในกระบวนการ ตอนนี้ถ้ากล่องของคุณเป็นรูปสี่เหลี่ยมที่ไม่ได้ใช้งานอยู่คุณอาจไม่เห็นความแตกต่าง แม้ว่าคนอื่นยังคงทำเช่นนั้น
frostschutz

9
ถอนหายใจ ทุกครั้งที่ddมีการพูดถึงการบล็อคผู้คนเข้ามาทำหน้าที่วางยา gzipการเป็นซีพียูเข้มข้นก็เป็นส่วนหนึ่งของคำตอบของฉันด้วยใช่ไหม และขออภัยฉันไม่เห็นด้วยกับ "เล็กน้อย" มันอาจเพิ่ม 1-2s ต่อกิ๊กด้วยgzip -9(แต่ยังคงเป็นจำนวนนาทีเมื่อประมวลผลหลายร้อยกิ๊ก) แต่ทำตามคำแนะนำของคุณด้วยlzop -11s ต่อกิ๊กเทียบกับ 4s ต่อกิ๊ก ทดสอบกับมันฝรั่ง (vserver แกนเดียว) การเพิ่มขนาดสตินั้นทำให้ddไม่มีค่าใช้จ่ายและไม่มีข้อเสียใด ๆ อย่า nitpick แค่ทำมัน. ymmv
frostschutz

19

ddอ่านและเขียนข้อมูลทีละบล็อกและจะมีหนึ่งบล็อกที่คงค้างเท่านั้น ดังนั้น

valgrind dd if=/dev/zero status=progress of=/dev/null bs=1M

แสดงให้เห็นว่าddใช้หน่วยความจำประมาณ 1MB คุณสามารถเล่นกับขนาดบล็อกและปล่อยvalgrindเพื่อดูผลddของความเร็ว

เมื่อคุณเข้าไปในท่อgzip, ddเพียงแค่ช้าลงจะมีการแข่งขันgzip's ความเร็ว การใช้หน่วยความจำไม่เพิ่มขึ้นและไม่ทำให้เคอร์เนลเก็บบัฟเฟอร์บนดิสก์ (เคอร์เนลไม่ทราบวิธีการทำยกเว้นผ่านการสลับ) ท่อแตกจะเกิดขึ้นเฉพาะเมื่อปลายด้านใดด้านหนึ่งของท่อตาย ดูsignal(7)และwrite(2)เพื่อดูรายละเอียด

ดังนั้น

dd if=... iconv=fullblock bs=1M | gzip -9 > ...

เป็นวิธีที่ปลอดภัยในการทำสิ่งที่คุณต้องการ

เมื่อการไพพ์กระบวนการเขียนสิ้นสุดลงจะถูกบล็อกโดยเคอร์เนลหากกระบวนการอ่านไม่ได้ติดตาม คุณสามารถเห็นสิ่งนี้ได้ด้วยการวิ่ง

strace dd if=/dev/zero bs=1M | (sleep 60; cat > /dev/null)

คุณจะเห็นว่าddอ่าน 1MB จากนั้นออกwrite()ที่รออยู่หนึ่งนาทีในขณะที่sleepทำงาน นั่นคือวิธีที่สมดุลทั้งสองด้านของท่อ: เคอร์เนลบล็อกเขียนว่ากระบวนการเขียนเร็วเกินไปหรือไม่และบล็อกจะอ่านหากกระบวนการอ่านเร็วเกินไป


1
มันเท่ห์มาก กลไกใดที่ddรู้ว่าจะช้าลงเพื่อให้เข้ากับgzipความเร็วของมัน? มันเป็นแบบอัตโนมัติเช่นเดียวกับเคอร์เนลหรือคำนวณจากข้อมูลเมตาเกี่ยวกับตัวอธิบายไฟล์เอาต์พุต?
แมว

9
@cat มันเป็นไปโดยอัตโนมัติ ddการเรียกwrite()เพื่อใส่ข้อมูลลงในไพพ์ write()ถ่ายโอนการควบคุมไปยังเคอร์เนลจริง ๆ เพื่อให้สามารถจัดการกับหน่วยความจำไปป์ หากเคอร์เนลเห็นว่าไปป์เต็มมันจะรอ ("บล็อก") จนกว่าไพพ์จะมีพื้นที่เพียงพอ จากนั้นwrite()สายจะเสร็จสิ้นและโอนการควบคุมกลับไปddที่ซึ่งจะเขียนข้อมูลไปยังไพพ์อีกครั้ง
marcelm

9

ไม่มีผลกระทบเชิงลบอื่น ๆ นอกจากประสิทธิภาพ: ไปป์มีบัฟเฟอร์ซึ่งโดยปกติคือ 64K และหลังจากนั้นการเขียนไปยังไพพ์จะบล็อกเพียงจนกว่าจะgzipอ่านข้อมูลเพิ่มเติมบางส่วน


8

ตอบคำถามจริงเกี่ยวกับวิธีการทำงาน: "จะเกิดอะไรขึ้นถ้าโปรแกรมทางด้านซ้ายเขียนข้อมูลได้เร็วกว่าอีกด้านหนึ่งของไปป์สามารถหวังที่จะประมวลผลได้"

สิ่งนี้ไม่ได้เกิดขึ้น มีบัฟเฟอร์ขนาดเล็กที่ค่อนข้าง จำกัด ในไพพ์ ดูท่อบัฟเฟอร์ใหญ่แค่ไหน?

เมื่อบัฟเฟอร์ท่อที่เต็มไปด้วยการส่งโปรแกรมบล็อก เมื่อทำการเรียกการเขียนเคอร์เนลจะไม่ส่งคืนการควบคุมไปยังโปรแกรมจนกว่าข้อมูลจะถูกเขียนลงในบัฟเฟอร์ สิ่งนี้ให้เวลา CPU ของโปรแกรมการอ่านเพื่อล้างบัฟเฟอร์


3

บางทีคุณแค่ต้องการไฟล์จากนั้นใช้ tar คุณสามารถเติมศูนย์บล็อกที่ไม่มีสิ่งที่คุณต้องการมีใครบางคนถามไปแล้ว ล้างพื้นที่ที่ไม่ได้ใช้ด้วยค่าศูนย์ (ext3, ext4)

จากนั้นมีซึ่งมักจะเร็วกว่าpigzgzip

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.