Сжатие потока «на лету», которое не распространяется на аппаратные ресурсы?


23

У меня есть 200 ГБ свободного дискового пространства, 16 ГБ ОЗУ (из которых ~ 1 ГБ занято рабочим столом и ядром) и 6 ГБ подкачки.

У меня есть внешний SSD на 240 ГБ, из которых 1 используется 70 ГБ, а остальное свободно, и мне нужно сделать резервную копию на моем диске.

Обычно я 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 использованных ГБ и ожидать получить работающую систему или файловую систему из-за фрагментации и других вещей, которые потребуют целостности всего содержимого.


Зачем вам делать резервные копии всей файловой системы, а не просто пользовательских каталогов и, возможно, списка установленных нестандартных программ?
jamesqf

5
@jamesqf Например. потому что намного легче восстановить ...
deviantfan

4
@jamesqf Потому что тогда у меня также есть загрузочный сектор и раздел подкачки, так что я могу воссоздать диск точно вместо того, чтобы иметь миллиард раздражающих файлов.
кошка

3
Случайный совет: посмотрите lzopвместо gzip; он сжимается намного быстрее, с чуть более низкой степенью сжатия. Я нахожу это идеальным для образов дисков, где скорость сжатия может быть реальным узким местом.
Марсель

1
«Что, когда программа на левой стороне записывает больше данных быстрее, чем другая сторона канала, может рассчитывать на их обработку?» Ядро заставит процесс записи спать, пока в канале не появится больше места.
Тавиан Барнс

Ответы:


16

Технически вам даже не нужно dd:

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

Если вы используете dd, вы всегда должны идти с большим, чем по умолчанию, размером блока, таким как адский вызов системного вызова dd bs=1Mили страдать от него (по ddумолчанию размер блока составляет 512 байт, так как это read()s и write()s, то есть 4096syscalls per MiB, слишком много накладных расходов).

gzip -9использует гораздо больше процессора с очень мало, чтобы показать это. Если gzipэто замедляет работу, снизьте уровень сжатия или используйте другой (более быстрый) метод сжатия.

Если вы делаете резервные копии на основе файлов, а не ddизображений, у вас может быть логика, которая решает, сжимать ли вообще или нет (делать это бессмысленно для разных типов файлов). dar( tarальтернатива`) - один из примеров, у которого есть варианты сделать это.

Если у вас свободное пространство ZERO (потому что это твердотельный накопитель, который надежно возвращает ноль после TRIM, и вы запустили fstrimи сбросили кэши), вы также можете использовать ddс conv=sparseфлагом, чтобы создать несжатый, монтируемый на петлю, разреженный образ, который использует нулевое дисковое пространство для нулевых областей. , Требует, чтобы файл образа был поддержан файловой системой, которая поддерживает разреженные файлы.

В качестве альтернативы для некоторых файловых систем существуют программы, способные отображать только используемые области.


1
«Если вы используете dd, вы всегда должны использовать больший размер блока, чем по умолчанию dd bs=1M», - можете, но не ожидайте слишком многого. На моем ПК ddбудет работать около 2 ГБ / с с 512-байтовыми блоками. Это не будет узким местом; gzipбудет.
marcelm

@marcelm Мы никогда не знаем, какие машины используют люди. Если вы используете dd2 ГБ / с с 512-байтовыми блоками, я был бы удивлен, если бы в этом процессе не использовалось 100% одного ядра процессора. Теперь, если ваша коробка - это четырехъядерный процессор, который все равно бездействует, вы можете не заметить разницы. Все остальные все еще делают, хотя.
frostschutz

9
Вздох. Каждый раз, ddкогда упоминается размер блока, люди придираются. gzipинтенсивность работы процессора также была частью моего ответа, хорошо? И извините, я не согласен с "незначительным". Он может добавить только 1-2 с на концерт gzip -9(но это все равно составляет минуты при обработке сотен гигов), но прислушивайтесь к совету lzop -1: 1 с на концерт против 4 с на концерт. Испытано на картофеле (одноядерный всервер). Добавление нормального размера блока ddничего не стоит и имеет ноль недостатков. Не придирайся. Просто сделай это. ymmv
frostschutz

19

ddчитает и записывает данные по одному блоку за раз, и у него только один ожидающий блок. Так

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

показывает, что ddиспользует примерно 1 МБ памяти. Вы можете поиграть с размером блока и сбросить valgrind, чтобы увидеть влияние на ddскорость.

Когда вы переходите на канал gzip, ddпросто замедляетесь, чтобы соответствовать gzipскорости. Его использование памяти не увеличивается и не заставляет ядро ​​хранить буферы на диске (ядро не знает, как это сделать, кроме как через swap). Разорванная труба случается только тогда, когда один из концов трубы умирает; смотрите 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

Нет никаких отрицательных последствий, кроме производительности: канал имеет буфер, который обычно составляет 64 КБ, и после этого запись в канал просто блокируется, пока не будет gzipпрочитано еще несколько данных.


8

Отвечая на реальный вопрос о том, как это работает: «что если программа на левой стороне записывает больше данных быстрее, чем другая сторона канала может рассчитывать на их обработку?»

Этого не происходит В канале имеется довольно маленький буфер ограниченного размера; Посмотрите, насколько большой буфер трубы?

Когда буфер канала заполнен, программа-отправитель блокируется . Когда он выполняет вызов записи, ядро ​​не вернет управление программе, пока данные не будут записаны в буфер. Это дает процессору ЦП время, в течение которого необходимо очистить буфер.


3

Может быть, вам нужны только файлы, затем используйте tar. Вы можете заполнить нулями блоки, которые не содержат ничего, что вы хотите, кто-то уже спрашивал об этом. Очистить неиспользуемое пространство с нулями (ext3, ext4)

Тогда есть, pigzчто обычно быстрее, чем gzip.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.