Rsync — золотой стандарт эффективной синхронизации и передачи файлов в Unix-средах. Он использует delta encoding, чтобы передавать только изменившиеся части файлов, что делает его идеальным для резервного копирования, деплоя и зеркалирования. В этом руководстве рассматривается практическое использование rsync с точки зрения senior-разработчика.
Зачем нужен Rsync
Rsync предлагает существенные преимущества:
- Delta Transfer: отправляет только различия в файлах
- Compression: снижает расход пропускной способности
- Preservation: сохраняет права, временные метки, symlink
- Incremental Backups: эффективен для регулярной синхронизации
- SSH Integration: безопасная передача по сети
Базовый синтаксис
rsync [options] source destination
Локальная синхронизация
# Скопировать файлы в другой каталог
rsync -av /source/path/ /destination/path/
# Зеркалировать каталог (удалять лишние файлы в destination)
rsync -av --delete /source/ /destination/
Важно: завершающий слэш в пути источника имеет значение:
/source/ — копирует содержимое source/source — копирует сам каталог source
Часто используемые опции
| Опция | Описание |
|---|
-a | Режим archive (рекурсивно, сохраняет всё) |
-v | Подробный вывод |
-z | Сжимать при передаче |
-P | Progress + partial (возобновление передач) |
-n | Dry run (показать, что произойдёт) |
--delete | Удалять файлы в dest, которых нет в source |
--exclude | Исключать файлы по шаблону |
--include | Включать файлы по шаблону |
-e | Указать удалённую оболочку |
Удалённая синхронизация
По SSH
# Отправить на удалённый сервер
rsync -avz -e ssh /local/path/ user@server:/remote/path/
# Забрать с удалённого сервера
rsync -avz -e ssh user@server:/remote/path/ /local/path/
# С нестандартным SSH-портом
rsync -avz -e 'ssh -p 2222' /local/ user@server:/remote/
# С SSH-ключом
rsync -avz -e 'ssh -i ~/.ssh/mykey' /local/ user@server:/remote/
С паролем
Для скриптов (менее безопасно, чем ключи):
# С использованием sshpass
sshpass -p "password" rsync -avz /local/ user@server:/remote/
# Или с переменной окружения
SSHPASS="password" sshpass -e rsync -avz /local/ user@server:/remote/
Стратегии резервного копирования
Базовый бэкап
#!/bin/bash
SOURCE="/home/user/documents/"
BACKUP="/backup/documents/"
LOG="/var/log/backup.log"
rsync -av --delete \
--log-file="$LOG" \
"$SOURCE" "$BACKUP"
Инкрементальный бэкап с hard link
Создавайте инкрементальные бэкапы с эффективным использованием дискового пространства:
#!/bin/bash
DATE=$(date +%Y-%m-%d)
SOURCE="/home/user/"
BACKUP_BASE="/backup"
LATEST="$BACKUP_BASE/latest"
TARGET="$BACKUP_BASE/$DATE"
# Создать бэкап с использованием hard link на предыдущий
rsync -av --delete \
--link-dest="$LATEST" \
"$SOURCE" "$TARGET"
# Обновить symlink latest
rm -f "$LATEST"
ln -s "$TARGET" "$LATEST"
Скрипт удалённого бэкапа
#!/bin/bash
set -e
# Конфигурация
SOURCE_SSH="user@production:/var/www"
BACKUP_BASE="/backups/production"
DATE=$(date +%Y-%m-%d_%H%M)
LATEST="$BACKUP_BASE/latest"
TARGET="$BACKUP_BASE/$DATE"
KEEP_DAYS=7
OPTIONS="-avz --delete --progress"
OPTIONS="$OPTIONS --exclude='*.log'"
OPTIONS="$OPTIONS --exclude='node_modules'"
OPTIONS="$OPTIONS --exclude='.git'"
# Создать бэкап
mkdir -p "$TARGET"
rsync $OPTIONS \
--link-dest="$LATEST" \
-e 'ssh -o StrictHostKeyChecking=no' \
"$SOURCE_SSH" "$TARGET"
# Обновить ссылку latest
rm -f "$LATEST"
ln -s "$TARGET" "$LATEST"
# Очистить старые бэкапы
find "$BACKUP_BASE" -maxdepth 1 -type d -mtime +$KEEP_DAYS -exec rm -rf {} \;
echo "Backup completed: $TARGET"
Выборочная синхронизация
Шаблоны include/exclude
# Исключить определённые шаблоны
rsync -av \
--exclude='*.log' \
--exclude='*.tmp' \
--exclude='node_modules' \
--exclude='.git' \
/source/ /dest/
# Исключить из файла
rsync -av --exclude-from='exclude.txt' /source/ /dest/
exclude.txt:
*.log
*.tmp
*.swp
node_modules/
.git/
.env
Включать только определённые файлы
rsync -avm \
--include='*/' \
--include='*.php' \
--include='*.js' \
--include='*.css' \
--exclude='*' \
/source/ /dest/
Флаг -m удаляет пустые каталоги.
Бэкапить только исходный код
#!/bin/bash
rsync -avm \
--include='*/' \
--include='*.php' \
--include='*.js' \
--include='*.ts' \
--include='*.vue' \
--include='*.css' \
--include='*.scss' \
--include='*.html' \
--include='*.json' \
--include='*.env.example' \
--include='.gitignore' \
--exclude='*' \
user@server:/var/www/app/ /backup/code/
Настройка производительности
Ограничение пропускной способности
# Ограничить до 1000 KB/s
rsync -avz --bwlimit=1000 /source/ /dest/
# Ограничить до 5 MB/s
rsync -avz --bwlimit=5000 /source/ /dest/
Сжатие
# Сжатие по умолчанию
rsync -avz /source/ user@server:/dest/
# Пропустить сжатие для уже сжатых файлов
rsync -avz --skip-compress=gz/jpg/mp4/zip /source/ user@server:/dest/
Параллельные передачи
Используйте несколько процессов rsync для большого количества мелких файлов:
#!/bin/bash
SOURCE="/source"
DEST="user@server:/dest"
# Найти каталоги и синхронизировать параллельно
find "$SOURCE" -maxdepth 1 -type d | \
parallel -j 4 rsync -avz {} "$DEST/"
Паттерны деплоя
Простой деплой
#!/bin/bash
rsync -avz --delete \
--exclude='.git' \
--exclude='.env' \
--exclude='node_modules' \
--exclude='storage/logs/*' \
./ user@server:/var/www/app/
Деплой с атомарным переключением
#!/bin/bash
SERVER="user@production"
APP_PATH="/var/www"
RELEASE=$(date +%Y%m%d%H%M%S)
# Синхронизировать в каталог нового релиза
rsync -avz --delete \
--exclude='.git' \
--exclude='node_modules' \
./ "$SERVER:$APP_PATH/releases/$RELEASE/"
# Выполнить команды на удалённой стороне
ssh "$SERVER" << EOF
cd $APP_PATH/releases/$RELEASE
# Подключить общие файлы
ln -s $APP_PATH/shared/.env .env
ln -s $APP_PATH/shared/storage storage
# Установить зависимости
composer install --no-dev
npm ci && npm run build
# Атомарно переключить symlink
ln -sfn $APP_PATH/releases/$RELEASE $APP_PATH/current
# Перезапустить сервисы
sudo systemctl reload php-fpm
# Очистить старые релизы (оставить последние 5)
ls -dt $APP_PATH/releases/*/ | tail -n +6 | xargs rm -rf
EOF
Мониторинг и логирование
Прогресс и статистика
# Показать прогресс
rsync -avP /source/ /dest/
# Показать статистику в конце
rsync -av --stats /source/ /dest/
# Перечислить изменения (подробно)
rsync -avvi /source/ /dest/
Логирование в файл
rsync -av \
--log-file=/var/log/rsync.log \
--log-file-format="%t %f %b" \
/source/ /dest/
Устранение неполадок
Сначала — dry run
Всегда тестируйте с -n:
rsync -avn --delete /source/ /dest/
Отладка проблем с подключением
# Подробный вывод SSH
rsync -avz -e 'ssh -v' /source/ user@server:/dest/
# Проверить, что будет передано
rsync -avni /source/ /dest/
Работа с большими файлами
# Возобновить частичные передачи
rsync -avP --partial /source/ /dest/
# Checksum вместо mod-time (медленнее, но точнее)
rsync -avc /source/ /dest/
Проблемы с правами
# Сохранять права (по умолчанию с -a)
rsync -av /source/ /dest/
# Не сохранять (копировать от имени текущего пользователя)
rsync -rv --no-perms --no-owner --no-group /source/ /dest/
Интеграция с Cron
Автоматизированный бэкап
# /etc/cron.d/backup
0 2 * * * root /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Блокировка для предотвращения пересечений
#!/bin/bash
LOCKFILE="/var/run/backup.lock"
(
flock -n 200 || { echo "Backup already running"; exit 1; }
rsync -av /source/ /dest/
) 200>"$LOCKFILE"
Ключевые выводы
- Всегда тестируйте с -n: выполняйте dry run перед реальной передачей
- Завершающий слэш важен:
/source/ vs /source - Используйте -P для больших передач: прогресс и возможность возобновления
- --delete используйте осторожно: может удалить файлы в destination
- --link-dest для бэкапов: инкрементальные бэкапы с экономией места
- Ограничение пропускной способности: учитывайте общие сети
Rsync незаменим для любых операционных задач — освоив его, вы получите эффективную и надёжную синхронизацию файлов по всей вашей инфраструктуре.