Приёмы работы c rsync
У замечательной и очень популярной программы rsync
есть множество удобных опций и необычайных способностей, вот только их не так-то просто найти. Ну, если только вы не готовы прочитать весь мануал от корки до корки.
Попробую сберечь вам немного времени на чтение мануала и рассказать о самом важном и полезном. Простыми словами, как есть.
Зачем нужен rsync?
Зачем пользоваться rsync
если есть привычные cp
и scp
, спросите вы.
В одной части
rsync
удобней и лучше упомянутых аналогов потому что он дает вам возможность увидеть все что он сделает при копировании файлов до непосредственно операции копирования.В другой части -
rsync
по умолчанию копирует только новые и изменившиеся файлы, и даже не только файлы - а отдельные их части, делая это жестоко и эффективно.
Только этих двух причин достаточно чтобы в своей ежедневной работе забыть про cp
, променяв эту команду и ее аналоги на rsync
.
Принцип применения
Если мы говорим о простом копировании файлов, то первым делом всегда стоит сделать пробный прогон (ключ -n
) в режиме с показом подробностей (-v
):
rsync -avn source example.com:destination
В этом режиме rsync
покажет список файлов, которые он скопирует. Будут скопированы только новые и изменившиеся файлы. Вы сможете убедиться что копируется сам каталог, а не содержимое, или что копируется именно содержимое.
После того как вы убедились что копируется именно то, что вы хотите, можно запускать самое настоящее копирование:
rsync -av source example.com:destination
В этой команде ключ -a
подразумевает рекурсивное копирование всех файлов и каталогов включая их атрибуты, такие как дата создания и дата изменения. Ключ -v
даст вам подробный отчет о работе по мере выполнения и по окончании.
Правила копирования каталогов
С одной стороны правила очень простые.
Если в конце пути до именованного источника нет слеша, то скопируется сам каталог.
$ rsync -avn path/to/source example.com:destination sending incremental file list source/ source/example.html ...
Если слеш есть, или источник указывает на каталог без имени, то скопируется содержимое каталога.
$ rsync -avn path/to/source/ example.com:destination ^^^ sending incremental file list example.html ... # Что эквивалентно такой команде: $ cd path/to/source; rsync -avn . example.com:destination
С другой стороны вполне можно в пылу забыть что и как, скопировав содержимое каталога вместо самого каталога, получив кучу хлопот с удалением лишних файлов, появившихся из ниоткуда с датами в прошлом (ключик -a
, помните?).
Потому лучше всегда следовать обычному сценарию с предварительной проверкой операции.
Некоторые полезные ключи
Сначала поговорим об опциях которые вам будет здорово знать без шпор и шпаргалок.
Ключ
-P
включает сразу несколько опций. С этим ключемrsync
и покажет процесс копирования отдельных файлов, и продолжит копирование если оно было прервано. Особо эта опция пригождается при копировании больших файлов. Ключ-P
нужно указывать каждый раз, иначеrsync
удалит файлы которые не успели полностью закачаться.Если вы копируете файлы с какого-то очень занятого, или слабого, сервера, то можно исключить трату ресурсов процессора на вычисление изменившихся частей файлов, скопировав их целиком. Для этого нужен ключ
-W
.Если вам хочется знать сколько всего, по мнению rsync, осталось работать, вам нужен ключ
--info=progress2
. Если вы копируете целую файловую систему, то этот ключ, будучи использован сам по себе, вас разочарует: информация об итоговом объёме будет постоянно обновляться. Это происходит потому чтоrsync
не пытается считать всю файловую систему до того как начнёт копирование, а делает обе задачи сразу.Но не отчаивайтесь! Если вы хотите знать точно сколько осталось работать с самого начала, то можно отключить последовательное сканирование ключём
--no-inc-recursive
или, короче,--no-i-r
.$ rsync -ah --partial --info=progress2 --no-i-r source example.com:destination 623.38M 0% 82.23MB/s 0:11:10
Ключи выше есть начиная с версии 3.1.0, то есть уже работают в Debian stable.
Если требуется не просто скопировать файлы, а полностью синхронизировать содержимое каталогов, удалив лишние файлы, при этом вам почему-то не с руки синхронизировать файлы с помощью Git, то пригодится ключ
--delete
(или эквивалентный ему--del
).С этим ключём
rsync
удалит лишние файлы из каталого-назначения.$ rsync -avn --delete source example.com:destination sending incremental file list deleting source/bad.txt source/ source/test.txt
Ключ
-n
в команде выше был оставлен намеренно.
Дальше я рассмотрю в деталях более интересные, хоть более редко используемые, опции.
О сжатии замолвим слово
Вопреки популярному заблуждению от использования сжатия внутри rsync (ключ -z
) больше вреда, чем пользы. Дело в том что всюду используемый OpenSSH уже с версии конца 2005 года по умолчанию использует сжатие передаваемых данных. Сами понимаете, сжатие уже сжатых данных только лишь использует ресурсы процессора, не уменьшая объем передаваемых данных.
В том, что при соединении с вашим сервером уже используется сжатие, можно убедиться так:
$ ssh -v user@example.com false 2>&1 | grep compression
debug1: Enabling compression at level 6.
Если эта команда не покажет, в числе прочих, такую строчку про включение сжатия как выше, то может быть вам стоит использовать сжатие. Стоит проверить что от сжатия есть толк. Особенно это касается маломощных устройств с быстрым соединением: вашему NAS может быть быстрее скопировать что-то по гигабитному линку без сжатия, чем пытаться обогнать гигабитную сеть маломощным процессором.
К счастью, rsync
достаточно умен чтобы не использовать сжатие если вы копируете файлы локально, из каталога на диск и т.п.
Копируем частично
Наверняка вам когда-нибудь понадобится чтобы rsync
пропускал некоторые файлы при копировании.
В самом простейшем случае вам нужно чтобы rsync не копировал файлы разных систем контроля версий, включая каталог вроде .svn
и .git
. В этой задаче вам не нужно ничего кроме ключа -C
(или --cvs-exclude
в полной форме). Так файлы большинства популярных VCS будут проигнорированы будто их нет. Не забываем использовать -n
при первом запуске.
rsync -nC example.com:source destination
Может получиться так что вы, по ошибке, скопируете кучу таких файлов от VCS. В этом случае для получения чистой копии вам пригодится ключ --delete-excluded
, с которым все исключенные файлы будут удалены.
rsync -nC --delete-excluded example.com:source destination
Исключаем через .rsync-filter
Если нужные более гибкие правила, что особенно актуально если копирование делается регулярно, то лучше не мелочиться и оформить все исключения в файле .rsync-filter
.
$ cat source/.rsync-filter
- test.bin
- *.tmp
- /.cache
- /example/
- /**/Trash/
- /.mozilla/firefox/*/Cache/
+ Projects/**/Trash/
Для исключения чего-либо из списка на перенос нужно добавить в этот файл строчку с правилом (-
или +
в начале строки).
Если нужно исключить конкретный файл, где бы он ни был в любом каталоге ниже по иерархии, то укажем просто имя файла.
# никакой файл test.bin не будет скопирован - test.bin # все файлы .tmp будут пропущены - *.tmp
Если нужно исключить файл или каталог относительно каталога в котором находится
.rsync-filter
, то укажем со слешем в начале:# не будет скопирован каталог или файл .cache, но будут скопированы foo/.cache и foo/bar/.cache - /.cache # не будет скопирован каталог example, но будет скопирован файл example - /example/
В правилах звездочка соответствует любым символам кроме слеша, а две звездочки соответствуют вообще любым символам:
# будут пропущены каталоги .local/share/Trash/ и Documents/example/Trash/ - /**/Trash/ # не будет пропущен каталог .mozilla/firefox/abcd.profile/ext/Cache/ # но будет пропущен каталог .mozilla/firefox/abcd.profile/Cache/ - /.mozilla/firefox/*/Cache/
Наконец, если нужно чтобы какие-то файлы всё-таки копировались, не смотря на ранее заданные правила, то их можно отметить правилом
+
в начале строки.# каталог Projects/Example/layout/Trash/ будет скопирован + Projects/**/Trash/
Файлы .rsync-filter
команда rsync
умеет искать по всей структуре каталогов будучи запущена с ключём -F
.
Если нужно чтобы сами эти файлы не копировались, то нужно указать этот ключ два раза так:
$ rsync -avFFn source example.com:destination
sending incremental file list
source/
source/example.html
source/tmp/
source/tmp/foo.bin
sent 174 bytes received 30 bytes 408.00 bytes/sec
total size is 18,400 speedup is 90.20 (DRY RUN)
Как видите, лишние файлы не скопировались:
$ ls source/.rsync-filter source/foo.tmp
source/foo.tmp source/.rsync-filter
$ cat source/.rsync-filter
- *.tmp
Ограничим rsync по ssh
Случается нужно разрешить работу rsync
по ssh, удалённо и без пароля, только определённого для каталога и хоста, исключив копирование чего-либо в другие места или из других мест.
Например, вы хотите чтобы можно было скопировать файлы на сервер backup.example.com
только с хоста server.example.com
, только и только в каталог backup-example
, и только с этими опциями:
$ rsync -aW --del source/ backup.example.com:destination/backup-example/
То сначала нужно получить команду, которую rsync
выполняет при вызове ssh на удаленном хосте:
$ rsync -e "ssh -t -v" -aW --del source/ backup.example.com:destination/backup-example/ 2>&1 | grep command
debug1: Sending command: rsync --server -lWogDtpre.iLsfxC --delete-during . destination/backup-example/
Соответственно, в ~/.ssh/authorized_keys
на example.com
следует добавить для известного ssh ключа запуск этой команды по умолчанию при подключении:
from="server.example.com",command="rsync --server -lWogDtpre.iLsfxC --delete-during . destination/backup-example/",no-pty,no-port-forwarding ssh-rsa AAAA... # дальше ваш ключ
Таким образом, даже если при запуске rsync
будут указаны какие-то другие опции, на сервере-назначении всё равно выполнится команда rsync
соответствующая исходным, заданным вами, опциям и настройкам.
Если нужно чтобы ваш бекап нельзя было перезаписать или удалить на сервере назначения, то опцию --del
следует заменить на --ignore-existing
.
Машина времени
Те пользователи macOS и OS X, что делают бэкап, наверняка оценили работу Time Machine. Эта программа позволяет буквально в два клика вернуться к прошлой версии любого файла. Не смотря на все красивости, Time Machine не делает ничего такого чего мы не можем сделать с помощью rsync
.
#!/bin/bash
set -o nounset -o errexit
cd $(dirname "$0")
date=$(date --iso-8601=seconds)
test -L latest || ln -s "$date" latest
rsync --delete-excluded --prune-empty-dirs --archive -F --link-dest=../latest "$@" "./$date"
rm latest
ln -s "$date" latest
Скрипт следует положить в корень того диска или каталога, куда следует делать бэкапы.
Запускать с указанием единственного аргумента: каталога с исходными файлами. Например, так.
/mnt/backups/backup /home
После нескольких запусков получается такая структура каталога:
2017-02-08T22:05:04+09:00
2017-02-08T22:10:05+09:00
2017-02-08T22:15:05+09:00
2017-02-08T22:20:06+09:00
2017-02-08T22:25:05+09:00
2017-02-08T22:30:04+09:00
latest -> 2017-02-08T22:30:04+09:00
При этом latest
указывает на самый последний бэкап.
В каждом из каталогов содержится слепок того, что было в исходном каталоге в момент копирования. Можно подумать что и место на диске занято пропорционально количеству копий, однако это не так.
$ du -sh /mnt/backups
4,5M /mnt/backups
$ du -sh /home
3,8M /home
Всё множество копий занимает лишь немного больше места чем исходный каталог. Место уходит на изменившиеся файлы.
Если ничего не менялось, то место всё равно расходуется на создание каталогов, которые нельзя хранить как жесткие ссылки.
$ du -hs 2017-02-08T22:20:06+09:00 2017-02-08T22:25:05+09:00 2017-02-08T22:30:04+09:00
3,8M 2017-02-08T22:20:06+09:00
136K 2017-02-08T22:25:05+09:00
136K 2017-02-08T22:30:04+09:00
Такая существенная экономия возможна благодаря упомянутым жестким ссылкам, которые rsync
делает для файлов, не изменившихся с последнего копирования.
$ stat -c '%i' 2017-02-08*/example.txt | uniq
31819810
У одинаковых, не менявшихся, файлов будет один и тот же inode.
Конечно, по возможной экономии места на диске такому способу резервного копирования далеко до специальных программам, таких как Borg или Restic.