Learning Platform
Глоссарий Troubleshooting
Урок 13.03 · 25 мин
Средний
scprsyncfile transferincrementalmirroringbackup

scp и rsync: копирование файлов через SSH

scp существует с 1995 года. Это первый инструмент, который вы выучите для копирования файлов. И вы будете пользоваться им последний раз через пару недель — потому что есть rsync, и rsync лучше во всём.

В этом уроке: почему scp устарел, и почему rsync — must-have инструмент DE-инженера. rsync делает: incremental sync (только diff передаётся), resume прерванных передач, compression on the wire, mirroring двух директорий, --dry-run чтобы посмотреть что будет до выполнения. Это инструмент номер 1 для backup, deployment, и data sync.


scp — legacy

# Файл с локальной машины на сервер
scp local-file.txt [email protected]:/path/

# С сервера на локальную
scp [email protected]:/path/file.csv ./

# Директорию рекурсивно
scp -r /local/dir [email protected]:/remote/dir/

# С нестандартным портом
scp -P 2222 file.txt [email protected]:/

# С конкретным ключом
scp -i ~/.ssh/key file.txt [email protected]:/

Чем плох scp:

Почему scp устарел

OpenSSH project официально считает scp deprecated с 2019

Полное копированиеscp всегда копирует всё с нуля. Если файл уже частично передан — копируется заново. Нет incremental
Нет resumeЕсли соединение прервалось при копировании 100GB файла — начинать заново
Нет прогрессаБазовый scp показывает только финальный размер. С -v видно но непрозрачно
Уязвимости в протоколеOpenSSH project отметил несколько CVE в scp protocol, рекомендует sftp или rsync
Нет mirroringНе может удалить файлы в destination, которых нет в source. Только односторонняя копия

scp работает, его все знают, на любом сервере он есть. Но для production DE-задач — используйте rsync.


rsync — KING для DE

rsync (remote sync) — разработан в 1996 году Andrew Tridgell. Алгоритм: вместо передачи всего файла, передаются только отличия (delta). Если файл уже частично есть на destination — передаётся только новая часть.

# Базовый синтаксис
rsync OPTIONS src dst

# Локально: копировать директорию
rsync -avh /src/dir/ /dst/dir/

# На remote (через ssh автоматически)
rsync -avh /src/dir/ [email protected]:/dst/dir/

# С remote на local
rsync -avh [email protected]:/src/dir/ /dst/dir/

-avh — три ключевых флага:

Главные флаги rsync

Запомни эти три — 80% всех use cases

-aArchive mode. Эквивалент -rlptgoD: рекурсивно, симлинки, права, время, owner, group, special files. Сохраняет всё метаданные. Это must-have
-vVerbose. Печатает имена файлов, которые передаются. Без -v rsync работает тихо
-hHuman-readable. Размеры показываются как 1.2M, 3.4G вместо bytes
-PProgress + partial. Прогресс-бар + сохранять partial файлы (если прервалось — можно resume)
--deleteУдалять файлы в destination, которых нет в source. Включает 'двусторонний sync'. ОСТОРОЖНО — может удалить лишнее
--dry-run / -nПоказать что будет сделано, не делая. ВСЕГДА используй -n первый раз
-zCompress в полёте. Полезно для медленных сетей
--excludeИсключить паттерн. Например --exclude '*.log' --exclude '__pycache__'
--include + --excludeВключить определённое, исключить остальное

Trailing slash — главный трюк

Это ловушка номер один. rsync ведёт себя по-разному в зависимости от того, есть ли / в конце source-пути.

# src БЕЗ слеша — копирует src как папку В dst
rsync -avh /home/levo/data /backup/
# Результат: /backup/data/...

# src СО СЛЕШОМ — копирует СОДЕРЖИМОЕ src В dst
rsync -avh /home/levo/data/ /backup/
# Результат: /backup/file1, /backup/file2, ... (содержимое data)

Часто люди забывают про слеш и копируют не туда. Запомни:

  • data — копирует папку как папку.
  • data/ — копирует содержимое папки.
WARNING

В destination trailing slash значения не имеет. Только в source.

# Все эти эквивалентны
rsync -avh /src/dir/ /dst/dir/
rsync -avh /src/dir/ /dst/dir

—dry-run — preview перед действием

ВСЕГДА запускайте rsync с -n (или --dry-run) первый раз — увидите, что rsync планирует делать, без реальных изменений:

# Preview
rsync -avhn /src/ /dst/

# Видите список файлов и итог: "would transfer X files, Y bytes"
# Если всё ок — запускаете без -n
rsync -avh /src/ /dst/

Особенно важно с --delete — если что-то не так с путями, можно случайно удалить кучу файлов.

# ВСЕГДА сначала --dry-run при --delete
rsync -avhn --delete /src/ /backup/
# Смотрите список deleting (что rsync удалит) и transferring (что скопирует)
# Если ок — без -n
rsync -avh --delete /src/ /backup/

—partial и -P — resume

Прервалось копирование на 50% файла? Просто запустите ту же команду — rsync продолжит с того же места:

# Скачать 100GB файл
rsync -avh -P [email protected]:/data/huge.tar.gz ./

# Прервалось. Запустите ту же команду
rsync -avh -P [email protected]:/data/huge.tar.gz ./
# rsync видит частичный файл, продолжает с того же места

-P = --partial + --progress. partial сохраняет недокачанные файлы.


—delete — двусторонний sync

По умолчанию rsync только добавляет файлы в destination. Чтобы destination был точной копией source — нужен --delete:

# Без --delete
# Если файл удалили в source — он остаётся в dst
rsync -avh /src/ /backup/

# С --delete — mirroring
# Файлы, которых нет в src, удаляются из dst
rsync -avh --delete /src/ /backup/

--delete крайне полезен, но опасен:

# СЦЕНАРИЙ КАТАСТРОФЫ
rsync -avh --delete /tmp/empty/ /backup/
# Если /tmp/empty/ пустая — rsync удалит ВСЁ из /backup/

ВСЕГДА с -n сначала. Часто полезно --delete-after (удалять после копирования, не до):

rsync -avh --delete-after /src/ /backup/

—exclude — игнорировать паттерны

# Исключить логи и __pycache__
rsync -avh --exclude='*.log' --exclude='__pycache__' /src/ /dst/

# Из файла
rsync -avh --exclude-from=/path/to/exclude.txt /src/ /dst/

# Файл exclude.txt:
# *.log
# *.tmp
# __pycache__
# .git/
# node_modules/

DE-сценарий: бэкап code-репозитория без node_modules и pycache:

rsync -avh \
  --exclude='node_modules' \
  --exclude='__pycache__' \
  --exclude='.git' \
  --exclude='*.pyc' \
  /home/levo/project/ \
  backup-server:/backups/project/

Стандартные DE-комбинации флагов

# Базовая копия (development)
rsync -avh src/ dst/

# Production — с progress, partial, и compression
rsync -avhP -z src/ user@remote:/dst/

# Mirror (master-slave) c удалением старых
rsync -avh --delete src/ user@remote:/dst/

# Incremental backup ежедневно
rsync -avh -P --delete /data/ backup@nas:/backup/2026-05-13/

# Огромный файл по медленной сети
rsync -avhP --bwlimit=10M big-file.tar.gz remote:/dst/
# --bwlimit=10M — не больше 10 MB/s

rsync через ssh с config

rsync под капотом использует ssh для remote-копирования. Уважает ~/.ssh/config:

Host backup
    HostName backup.company.com
    User levo
    IdentityFile ~/.ssh/work_key
# Теперь
rsync -avh /data/ backup:/storage/
# ssh-конфиг подхватился, идёт через ssh с правильным ключом

С нестандартным портом или флагами ssh:

rsync -avh -e "ssh -p 2222 -i ~/.ssh/special_key" /src/ user@remote:/dst/

DE-сценарии

1. Nightly backup data lake

#!/bin/bash
set -euo pipefail

# Бэкап data lake на NAS
DATE=$(date +%Y-%m-%d)
SRC="/data/lake/"
DST="backup@nas:/backups/lake/$DATE/"
LATEST="backup@nas:/backups/lake/latest/"

# --link-dest = hardlinks для не-изменённых файлов (incremental backup)
rsync -avh -P \
  --link-dest="$LATEST" \
  --exclude='*.tmp' \
  --exclude='_temp/' \
  "$SRC" "$DST"

# Обновить symlink latest
ssh nas "ln -sfn /backups/lake/$DATE /backups/lake/latest"

--link-dest — magic для incremental backup: файлы, которые не изменились с последнего бэкапа, hardlink на существующие. Каждый daily backup занимает только размер изменений.

rsync в CI/CD — деплой кода через GitHub Actions

2. Deploy code на сервер

#!/bin/bash
set -euo pipefail

LOCAL="/home/levo/etl-project/"
REMOTE="airflow:/opt/etl-project/"

# Preview
echo "Preview:"
rsync -avhn --delete \
  --exclude='.git' \
  --exclude='__pycache__' \
  --exclude='.env' \
  "$LOCAL" "$REMOTE"

read -p "Continue? (y/n): " yn
[ "$yn" != "y" ] && exit 1

# Apply
rsync -avh --delete \
  --exclude='.git' \
  --exclude='__pycache__' \
  --exclude='.env' \
  "$LOCAL" "$REMOTE"

# Restart Airflow scheduler
ssh airflow "sudo systemctl restart airflow-scheduler"

3. Скачать data dump

# Партнёр кладёт раз в день data dump на свой FTP
# Прерывистая сеть — rsync с resume

rsync -avhP \
  --partial-dir=.rsync-partial \
  [email protected]:/exports/daily/ \
  /local/imports/daily/

# --partial-dir = специальная директория для прерванных файлов
# Они не «появляются» в основной директории недокаченными

4. Migrate между двумя кластерами

# Старый Hadoop кластер -> новый кластер
rsync -avhP -z --delete \
  /hadoop-old/data/ \
  user@new-cluster:/hadoop-new/data/

# С ограничением полосы — не убить сетку (приоритет — production трафик)
rsync -avhP --bwlimit=50M \
  /hadoop-old/data/ \
  user@new-cluster:/hadoop-new/data/

5. Two-way sync через rsync (не идеально)

rsync — это одностороннее копирование. Для двустороннего sync нужны другие инструменты (Unison, Syncthing). Но можно симулировать:

# Direction 1: A -> B
rsync -avh --update A/ B/

# Direction 2: B -> A (only newer)
rsync -avh --update B/ A/

--update копирует только если source файл новее destination. Это «грубый» two-way sync — конфликты не разрешаются красиво. Для серьёзного two-way — Unison.


Performance tips

# Compression: -z (полезно для slow сети, не нужно для local)
rsync -avhz /src/ remote:/dst/

# Whole-file (не delta) — для local SSD быстрее, чем delta
rsync -avh -W /src/ /dst/
# -W = --whole-file. Делает rsync как scp, но с другими фишками

# Inplace updates — update файла «на месте», не пересоздавая
rsync -avh --inplace /src/ /dst/
# Полезно для огромных файлов где нужен только partial update

Попробуй сам

# 1. Базовое копирование локально
mkdir /tmp/src /tmp/dst
echo "file1" > /tmp/src/file1.txt
echo "file2" > /tmp/src/file2.txt
mkdir /tmp/src/subdir
echo "file3" > /tmp/src/subdir/file3.txt

rsync -avh /tmp/src/ /tmp/dst/
ls /tmp/dst/
# Содержимое src/

# 2. Trailing slash effect
rm -rf /tmp/dst
mkdir /tmp/dst
rsync -avh /tmp/src /tmp/dst/
ls /tmp/dst/
# /tmp/dst/src/...

# 3. --dry-run
echo "extra" > /tmp/dst/extra.txt
rsync -avhn --delete /tmp/src/ /tmp/dst/
# Покажет: deleting extra.txt

# 4. Реально удалить
rsync -avh --delete /tmp/src/ /tmp/dst/
ls /tmp/dst/
# extra.txt пропал

# 5. Exclude
echo "log content" > /tmp/src/debug.log
rsync -avh --exclude='*.log' /tmp/src/ /tmp/dst/
ls /tmp/dst/
# debug.log нет

# 6. Прерви и продолжи (на удалённом сервере)
# Можно симулировать с большим файлом
dd if=/dev/zero of=/tmp/src/big.bin bs=1M count=100
rsync -avhP /tmp/src/big.bin /tmp/dst/
# Прерви через Ctrl-C посередине
rsync -avhP /tmp/src/big.bin /tmp/dst/
# Должен продолжить

Cross-link: предыдущий урок 02 — ssh, на котором работает rsync. Следующий урок 04 — diagnose сетевых проблем. Модуль 17 — bash-скрипты для backup-пайплайнов.


Проверка знанийKnowledge check
Команда rsync -avh /home/levo/data /backup/ и команда rsync -avh /home/levo/data/ /backup/ — в чём принципиальная разница, и какая «удалит» содержимое /backup/data/ если /backup/data уже существует?
ОтветAnswer
Разница в trailing slash на source — это самый частый источник ошибок в rsync. /home/levo/data (БЕЗ слеша) — копирует папку data КАК папку внутрь /backup/. Результат: /backup/data/file1, /backup/data/file2 — т.е. /backup/data/ — это новая папка-копия. Если /backup/data/ уже существует — rsync МЕРДЖИТ содержимое (file1 копирует, существующие обновляет если изменились). Никто не удаляется (без --delete). /home/levo/data/ (СО слешем) — копирует СОДЕРЖИМОЕ data В /backup/. Результат: /backup/file1, /backup/file2 (прямо в backup, без data/). Это часто хочется когда вы делаете backup определённой директории и хотите чтобы файлы лежали без обёртки. Trailing slash на destination значения не имеет — rsync /src/ /dst/ и rsync /src/ /dst эквивалентны. Запомнить: «слеш на source значит — содержимое». Это правило — половина успеха с rsync. Всегда используй --dry-run первый раз чтобы увидеть что реально скопируется.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Почему DE-команды предпочитают rsync вместо scp?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5