Kompresi aliran on-the-fly yang tidak tumpah ke sumber daya perangkat keras?

23

Saya memiliki ruang disk bebas 200 GB, RAM 16 GB (yang ~ 1 GB ditempati oleh desktop dan kernel) dan 6 GB swap.

Saya memiliki SSD eksternal 240 GB, dengan 70 GB digunakan 1 dan sisanya gratis, yang saya perlukan untuk mencadangkan ke disk saya.

Biasanya, saya akan dd if=/dev/sdb of=Desktop/disk.imgdisk terlebih dahulu, dan kemudian kompres, tetapi membuat gambar pertama bukanlah pilihan karena melakukan hal itu akan memerlukan ruang disk jauh lebih banyak daripada yang saya miliki, meskipun langkah kompresi akan menghasilkan ruang kosong yang tergencet sehingga arsip terakhir dapat dengan mudah masuk ke disk saya.

ddmenulis ke STDOUT secara default, dan gzipdapat membaca dari STDIN, jadi secara teori saya dapat menulis dd if=/dev/sdb | gzip -9 -, tetapi gzipsecara signifikan membutuhkan waktu lebih lama untuk membaca byte daripada ddmenghasilkannya.

Dari man pipe:

Data yang ditulis ke ujung tulis pipa disangga oleh kernel sampai dibaca dari ujung baca pipa.

Saya memvisualisasikan a | sebagai seperti pipa nyata - satu aplikasi mendorong data masuk dan yang lainnya mengambil data dari antrian pipa secepat mungkin.

Bagaimana ketika program di sisi kiri menulis lebih banyak data lebih cepat daripada sisi lain dari pipa yang bisa memprosesnya? Apakah akan menyebabkan penggunaan memori atau swap yang ekstrem, atau akankah kernel mencoba membuat FIFO pada disk, sehingga mengisi disk? Atau akankah hanya gagal SIGPIPE Broken pipejika buffer terlalu besar?

Pada dasarnya, ini bermuara pada dua pertanyaan:

  1. Apa implikasi dan hasil dari mendorong lebih banyak data ke dalam pipa daripada dibaca pada suatu waktu?
  2. Apa cara andal untuk mengompres datastream ke disk tanpa meletakkan seluruh datastream yang tidak terkompresi pada disk?

Catatan 1: Saya tidak bisa hanya menyalin persis 70 GB yang digunakan pertama dan berharap untuk mendapatkan sistem kerja atau sistem file, karena fragmentasi dan hal-hal lain yang akan membutuhkan konten lengkap untuk utuh.

kucing
sumber
Mengapa Anda membuat cadangan seluruh sistem file seperti itu, bukan hanya direktori pengguna, dan mungkin daftar perangkat lunak non-standar yang diinstal?
jamesqf
5
@jamesqf Misalnya. karena jauh lebih mudah untuk memulihkan ...
deviantfan
4
@jamesqf Karena dengan begitu saya juga mendapatkan sektor boot, dan partisi swap, sehingga saya dapat membuat ulang disk dengan tepat daripada memiliki satu miliar file yang mengganggu.
kucing
3
Tip acak: lihatlah lzopalih-alih gzip; itu kompres lebih cepat dengan hanya rasio kompresi yang sedikit lebih rendah. Saya merasa ideal untuk gambar disk di mana kecepatan kompresi dapat menjadi hambatan nyata.
marcelm
1
"Bagaimana ketika program di sisi kiri menulis lebih banyak data lebih cepat daripada yang diharapkan dari sisi lain dari pipa untuk memprosesnya?" Kernel akan menyebabkan proses penulisan tidur sampai ada lebih banyak ruang di dalam pipa.
Tavian Barnes

Jawaban:

16

Secara teknis Anda bahkan tidak perlu dd:

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

Jika Anda menggunakan dd, Anda harus selalu pergi dengan lebih besar dari ukuran default seperti dd bs=1Matau menderita neraka syscall ( dddefault ukuran blok adalah 512 byte, karena itu read()dan write()s itu 4096panggilan sys per MiB, terlalu banyak overhead).

gzip -9menggunakan BANYAK lebih banyak CPU dengan sangat sedikit untuk ditampilkan. Jika gzipmemperlambat Anda, turunkan tingkat kompresi, atau gunakan metode kompresi yang berbeda (lebih cepat).

Jika Anda melakukan backup berbasis file alih-alih ddgambar, Anda dapat memiliki beberapa logika yang memutuskan apakah akan dikompres sama sekali atau tidak (tidak ada gunanya melakukannya untuk berbagai jenis file). dar( taralternative`) adalah salah satu contoh yang memiliki opsi untuk melakukannya.

Jika ruang kosong Anda NOL (karena ini adalah SSD yang andal mengembalikan nol setelah TRIM dan Anda berlari fstrimdan menjatuhkan cache) Anda juga dapat menggunakan dddengan conv=sparseflag untuk membuat gambar jarang terkompresi, loop-mountable, jarang yang menggunakan ruang disk nol untuk area nol . Membutuhkan file gambar untuk didukung oleh sistem file yang mendukung file jarang.

Atau untuk beberapa sistem file ada program yang hanya dapat gambar area yang digunakan.

frostschutz
sumber
1
"Jika Anda menggunakan dd, Anda harus selalu menggunakan yang lebih besar dari ukuran default blocksize seperti dd bs=1M" - Anda bisa, tetapi jangan berharap terlalu banyak. Di PC saya, ddakan dilakukan sekitar 2GB / s dengan blok 512-byte. Itu tidak akan menjadi hambatan; gzipakan.
marcelm
@marcelm Kami tidak pernah tahu mesin apa yang digunakan orang. Jika Anda memiliki dd2GB / s dengan blok 512-byte, saya akan terkejut jika tidak memaksimalkan satu inti CPU 100% dalam proses. Sekarang jika kotak Anda adalah quadcore yang hanya diam, Anda mungkin tidak melihat perbedaan. Namun, semua orang masih melakukannya.
frostschutz
9
Mendesah. Setiap kali ddblocksize disebutkan, orang-orang datang mengolok-olok. gzipmenjadi cpu intensif juga bagian dari jawaban saya, oke? Dan maaf, saya tidak setuju dengan "diabaikan". Mungkin hanya menambahkan 1-2s per gig dengan gzip -9(tapi itu masih berarti beberapa menit saat memproses ratusan pertunjukan) tetapi mengambil saran Anda dengan lzop -1itu 1s per pertunjukan vs 4s per pertunjukan. Diuji pada kentang (vserver inti tunggal). Menambahkan blocksize waras ke ddbiaya apa-apa dan memiliki nol kerugian. Jangan rewel. Lakukan saja. ymmv
frostschutz
19

ddmembaca dan menulis data satu blok pada satu waktu, dan hanya memiliki satu blok yang beredar. Begitu

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

menunjukkan bahwa ddmenggunakan sekitar 1MB memori. Anda dapat bermain-main dengan ukuran blok, dan menjatuhkan valgrind, untuk melihat efeknya pada ddkecepatan.

Ketika Anda memasang pipa gzip, ddcukup memperlambat agar sesuai gzipdengan kecepatan. Penggunaan memorinya tidak meningkat, juga tidak menyebabkan kernel untuk menyimpan buffer pada disk (kernel tidak tahu bagaimana melakukan itu, kecuali melalui swap). Pipa yang rusak hanya terjadi ketika salah satu ujung pipa mati; lihat signal(7)dan write(2)untuk detailnya.

Demikian

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

adalah cara aman untuk melakukan apa yang Anda cari.

Ketika melakukan piping, proses penulisan akhirnya diblokir oleh kernel jika proses membaca tidak berjalan. Anda dapat melihat ini dengan menjalankan

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

Anda akan melihat bahwa ddmembaca 1MB, lalu mengeluarkan write()yang duduk di sana menunggu satu menit saat sleepberjalan. Begitulah cara kedua sisi pipa menyeimbangkan: kernel blok menulis jika proses penulisan terlalu cepat, dan blok membaca jika proses membaca terlalu cepat.

Stephen Kitt
sumber
1
Itu keren sekali. Dengan mekanisme mana yang ddtahu memperlambat untuk mencocokkan gzipkecepatan? Ini otomatis, seperti oleh kernel, atau apakah ia menghitung dari metadata tentang deskriptor file outputnya?
kucing
9
@ kucing Ini otomatis; ddpanggilan write()untuk memasukkan data ke dalam pipa. write()sebenarnya mentransfer kontrol ke kernel sehingga dapat memanipulasi memori pipa. Jika kernel melihat pipa penuh, ia akan menunggu ("blok") sampai pipa memiliki cukup ruang. Hanya kemudian write()panggilan akan selesai dan transfer kontrol kembali ke dd, yang kemudian akan menulis data ke pipa lagi.
marcelm
9

Tidak ada implikasi negatif selain kinerja: pipa memiliki buffer, yang biasanya 64K, dan setelah itu, penulisan ke pipa hanya akan memblokir sampai gzipmembaca beberapa data lagi.

Ulrich Schwarz
sumber
8

Menjawab pertanyaan aktual tentang cara kerjanya: "bagaimana jika program di sisi kiri menulis lebih banyak data lebih cepat daripada sisi lain dari pipa dapat berharap untuk memprosesnya?"

Ini tidak terjadi. Ada penyangga ukuran yang cukup kecil di dalam pipa; Lihat Seberapa besar penyangga pipa?

Setelah buffer pipa penuh, program pengiriman terhalang . Ketika melakukan panggilan tulis, kernel tidak akan mengembalikan kontrol ke program sampai data telah ditulis ke dalam buffer. Ini memberi waktu membaca program CPU untuk mengosongkan buffer.

pjc50
sumber