Копирование файлов с помощью быстрой многопоточной обработки parsyncfp
Введение
parsyncfp — это параллельная обёртка над rsync, которая ускоряет передачу больших коллекций файлов за счёт одновременного запуска нескольких процессов rsync. Каждый процесс синхронизирует свою часть файлов, поэтому доступная пропускная способность сети и CPU используются эффективнее, чем при одном потоке rsync.
В этом руководстве рассказывается, когда parsyncfp полезен, как его установить и как выполнить базовую передачу данных между двумя серверами.
Параллельное копирование ускоряет передачу только на быстрых дисках и при стабильной сети. На медленных дисках или сетевых файловых системах (NFS, SMB, FUSE) увеличение числа параллельных процессов часто не даёт прироста скорости, а вместо этого может создать дополнительную нагрузку на источник, получатель или канал между ними. Начните с небольшого числа процессов, измерьте результат и увеличивайте их количество только в том случае, если диски и сеть справляются с нагрузкой.
Как работает parsyncfp
parsyncfp использует утилиту fpart для разбиения дерева исходных файлов на фрагменты примерно одинакового размера, а затем запускает несколько процессов rsync параллельно, по одному на каждый фрагмент. Поскольку fpart разбивает дерево инкрементально, parsyncfp может начать передачу файлов ещё до завершения полного сканирования исходного дерева, что важно для очень больших деревьев каталогов.
Инструмент нужно устанавливать только на исходном сервере. Принимающую сторону, как обычно, обслуживает rsync.
Тот же автор поддерживает преемника под названием parsyncfp2 (pfp2), который включает исправления ошибок и улучшения по сравнению с parsyncfp, а также дополнительно поддерживает отправку сразу с нескольких исходных хостов. Для новых внедрений рекомендуется использовать именно parsyncfp2. Это руководство описывает классический parsyncfp; синтаксис команд pfp2 в значительной степени совместим.
Когда полезен parsyncfp
parsyncfp даёт наибольший выигрыш, когда:
- источник содержит миллионы небольших файлов, из-за чего rsync тратит большую часть времени на операции с метаданными, а не на непосредственную передачу данных;
- и источник, и получатель работают на быстром хранилище (NVMe, SSD или хорошо настроенный RAID);
- сеть между источником и получателем быстрая и стабильная (1 Гбит/с или выше, низкие потери пакетов);
- единственный процесс rsync упирается в ограничение CPU или пропускной способности одного потока, а не диска или канала связи.
Для небольших каталогов, медленных вращающихся дисков или перегруженной сети обычного rsync, как правило, достаточно.
Каталог ~/.parsyncfp
parsyncfp создаёт на исходном сервере кэш-каталог с именем ~/.parsyncfp. Внутри него находится подкаталог fpcache, в котором хранятся журнал fpart, PID-файлы запущенных процессов rsync и файлы фрагментов, указывающие, какие пути должен скопировать каждый rsync. Файлы журнала имеют отметку даты и не перезаписываются между запусками, поэтому предыдущие запуски можно просмотреть позже.
Если вы хотите запускать несколько экземпляров parsyncfp одновременно, укажите для каждого отдельное расположение кэша с помощью опции --altcache. parsyncfp при запуске обнаруживает другие работающие экземпляры и предупреждает о них, поэтому случайно пересекающиеся запуски становятся заметны на раннем этапе.
Установка зависимостей
Сам parsyncfp опирается на rsync (транспорт) и fpart (для разбиения исходного дерева на фрагменты). Установите оба на исходном сервере.
В Debian и Ubuntu:
apt-get install rsync fpart
В RHEL, CentOS Stream, AlmaLinux и Rocky Linux fpart отсутствует в базовых репозиториях. Сначала подключите репозиторий EPEL, затем установите оба пакета:
dnf install epel-release dnf install rsync fpart
Некоторые пакеты EPEL зависят от пакетов из репозитория PowerTools или CRB, который по умолчанию отключён. Включите нужный репозиторий для вашей версии:
# RHEL/AlmaLinux/Rocky Linux 9 и новее dnf config-manager --set-enabled crb # RHEL/AlmaLinux/Rocky Linux 8 dnf config-manager --set-enabled powertools
Если ваш дистрибутив вообще не поставляет fpart (например, RHEL 10 или его пересборки на момент написания этого текста), либо вы предпочитаете не использовать EPEL, соберите fpart из исходного кода. Официальный репозиторий — репозиторий fpart на GitHub; в README перечислен небольшой набор зависимостей для сборки (компилятор C, make и стандартные заголовки библиотеки C).
Установка parsyncfp
parsyncfp представляет собой единый Perl-скрипт, размещённый на GitHub. Скачайте его, сделайте исполняемым и переместите в каталог, входящий в ваш PATH, чтобы можно было вызывать его без указания полного пути:
wget https://raw.githubusercontent.com/hjmangalam/parsy ncfp /master/parsyncfp chmod +x parsyncfp sudo mv parsyncfp /usr/local/bin/
Проверьте, что скрипт запускается:
parsyncfp --help
Если появился экран справки, parsyncfp готов к использованию.
Настройка SSH-доступа к получателю
parsyncfp запускает rsync через SSH, поэтому исходный сервер должен иметь возможность входить на сервер получателя без пароля. Сгенерируйте пару ключей на источнике (если её ещё нет) и скопируйте открытый ключ на получатель:
ssh-keygen ssh-copy-id user@target_host
Замените user@target_host на имя пользователя и IP-адрес или имя хоста вашего сервера-получателя. После этого шага следующая команда должна подключаться без запроса пароля:
ssh user@target_host
Выполнение передачи
Типичная команда parsyncfp выглядит так:
parsyncfp --NP=8 --altcache=/dir/local/tmp --startdir=/dir/local/ www/ [email protected]:/var/dir/
Эта команда запускает 8 процессов rsync, использует /dir/local/tmp в качестве кэш-каталога и копирует содержимое /dir/local/www в /var/dir/ на хосте-получателе 192.168.67.1.
Обратите внимание на завершающий слэш в аргументе источника: www/ копирует содержимое каталога www в получатель (как в примере выше), тогда как www (без слэша) копирует сам каталог www, создавая /var/dir/www/ на получателе. Это то же поведение, что и у обычного rsync.
Основные параметры команды
- --NP задаёт число параллельных процессов rsync. Разумная стартовая точка — от 4 до 8; увеличивайте это число постепенно и только если диски и сеть ещё не насыщены. Установка --NP равным числу ядер CPU сама по себе редко является правильным выбором.
- --altcache задаёт альтернативный кэш-каталог. Полезно, когда вы запускаете несколько экземпляров parsyncfp одновременно, или когда каталог по умолчанию находится на медленном хранилище. Избегайте указывать расположение на базе tmpfs (например, /tmp во многих дистрибутивах), поскольку списки фрагментов для очень больших исходных деревьев могут сильно разрастаться, а занимать ими оперативную память нежелательно.
- --startdir задаёт рабочий каталог, используемый как базовый для указанных далее исходных путей.
- Аргументы после --startdir — это исходные каталоги для копирования (один или несколько, через пробел), за которыми следует получатель в формате rsync вида user@host:/path/.
Полный список опций можно получить командой parsyncfp --help или в документации проекта.
Полезные дополнительные опции
После того как базовая передача заработала, стоит знать несколько опций для продуктивной эксплуатации:
- --maxbw=500000 ограничивает суммарную пропускную способность, используемую всеми процессами rsync, в КБ/с. Полезно, когда канал используется совместно с другими сервисами.
- --maxload=12 приостанавливает запуск новых процессов rsync, как только средняя нагрузка системы превышает указанное значение. Полезно на сильно загруженных исходных серверах, но перед использованием ознакомьтесь с предупреждением ниже.
- --chunksize=5G определяет размер каждого фрагмента fpart. Более крупные фрагменты снижают накладные расходы на фрагмент при передаче с большим числом мелких файлов; более мелкие фрагменты улучшают параллелизм при передаче небольшого числа очень крупных файлов.
- --rsyncopts="-a -s -x" позволяет передавать дополнительные флаги непосредственно базовым процессам rsync. Используйте её, чтобы включить сжатие (-z), задать пользовательский размер блока или применить другие настройки rsync. Не передавайте --delete через --rsyncopts; почему это небезопасно, объясняется в разделе «Ограничения» ниже.
- --verbose=2 увеличивает детализацию журналирования, что упрощает диагностику при первых запусках.
Автор проекта задокументировал известную проблему с --maxload: когда parsyncfp проходит через повторяющиеся циклы приостановки и возобновления, некоторые исходные файлы могут не попасть на получатель. Если вы используете --maxload, устанавливайте порог достаточно высоким, чтобы приостановки никогда не срабатывали, либо после завершения передачи проверяйте результат отдельной проверкой целостности.
Ограничения
Даже на подходящем оборудовании у parsyncfp есть компромиссы, о которых стоит знать перед увеличением числа процессов:
- parsyncfp не поддерживает безопасное использование опции --delete rsync. Каждый параллельный процесс rsync видит только свой собственный фрагмент источника, поэтому если передать --delete, каждый процесс будет пытаться удалить на получателе файлы, которых нет в его фрагменте, — то есть файлы, законно принадлежащие другим фрагментам. Это может уничтожить значительную часть данных на получателе. Используйте обычный rsync (или отдельный этап очистки), когда вам нужна семантика --delete.
- parsyncfp не сохраняет глобальный порядок файлов между параллельными процессами rsync, поэтому порядок появления файлов на получателе непредсказуем. Это важно только для рабочих процессов, зависящих от временных меток файлов или порядка листинга каталога непосредственно во время копирования.
- На массивах HDD множество параллельных процессов rsync превращают то, что было бы последовательным чтением, в почти случайное, что может быть медленнее одного rsync. SSD и накопители NVMe затрагиваются этим гораздо меньше.
- На файловых системах с очень большим числом мелких файлов накладные расходы на метаданные в расчёте на файл могут доминировать над временем передачи. Параллелизм помогает лишь до определённого предела, после чего эффект выходит на плато.
- Каждый процесс rsync открывает собственное SSH-соединение с получателем, поэтому высокие значения --NP многократно увеличивают накладные расходы на установку соединения. На WAN-каналах с потерями пакетов или высокой задержкой это может скорее усугубить перегрузку, чем улучшить ситуацию. В таком случае меньшее число процессов с настроенным rsync (сжатие, увеличенный размер блока) часто работает лучше, чем множество параллельных процессов.
См. также
Если parsyncfp окажется тяжелее, чем вам нужно, пакет fpart также включает fpsync — более простую параллельную обёртку над rsync того же автора. Она использует ту же идею разбиения на фрагменты, но с меньшим числом опций, и её часто достаточно для разовых передач.