Выберите продукт

lsyncd + rsync: почти реальное время для синхронизации загрузок и медиа

Если у вас несколько веб-нод, общий каталог uploads быстро становится узким местом. Показываю, как связкой lsyncd и rsync получить почти моментальную репликацию: inotify, дебаунс, аккуратные удаления, большие файлы, логи, лимиты и безопасный SSH-доступ.
lsyncd + rsync: почти реальное время для синхронизации загрузок и медиа

Когда сайт масштабируется горизонтально и у вас появляется несколько веб-нод, общий каталог с медиа (uploads) быстро превращается в «точку боли». Нужна синхронизация в почти реальном времени, чтобы пользователь, только что загрузивший файл на одну ноду, мог тут же получить его с другой. Классика жанра — lsyncd поверх rsync: мониторим изменения через inotify и дожимаем передачу файлов без ручных костылей и кронов.

Зачем именно lsyncd + rsync

rsync великолепен для начальной и периодической синхронизации, но не отслеживает изменения сам по себе. lsyncd следит за файловой системой с помощью inotify, агрегирует события и вызывает rsync только по делу — при реальных изменениях. В итоге получаем минимальные задержки, снижаем лишний IO и сетевой трафик, а также защищаемся от «штормов» событий за счёт короткой задержки на дебаунс.

Связка хорошо подходит для каталогов вроде uploads, где появляются новые медиафайлы, создаются превью и периодически происходят удаления или перемещения. Это не полноценная распределённая ФС и не блокирующее сетевое хранилище, но для одностороннего потока изменений — идеально.

Архитектура и ограничения

Ключевой момент — модель «один писатель, несколько читателей». То есть только одна нода является источником изменений, остальные получают реплику. Если дать право записи всем, получите гонки, конфликты и непредсказуемость. Обычно делают так: загрузки пишет «мастер»-нода (sticky-сессии или маршрутизация на один backend для POST), а остальные ноды читают уже синхронизированное содержимое.

Важно понимать: это «почти реальное время», а не строгое. Есть небольшая задержка: событие inotify + дебаунс lsyncd + время передачи rsync. В большинстве случаев укладывается в доли секунды — секунды, но пик большого пакета файлов может занять больше.

Для SSH-части и автоматизации ключей может пригодиться разбор Rsync: деплой и бэкап по SSH.

Диаграмма: inotify события, дебаунс lsyncd и поток rsync

Подготовка окружения

Понадобится lsyncd и rsync на исходном сервере и rsync на принимающем. Доступ по SSH лучше оформить через отдельного системного пользователя с ключами, чтобы ограничить права.

# Debian/Ubuntu
sudo apt-get update
sudo apt-get install -y lsyncd rsync

# AlmaLinux/RHEL/CentOS
sudo dnf install -y lsyncd rsync

Создадим пользователя для синхронизации и ключи:

sudo useradd -m -s /usr/sbin/nologin sync
sudo -u sync ssh-keygen -t ed25519 -N "" -f /home/sync/.ssh/id_ed25519

Добавьте публичный ключ на целевой сервер в authorized_keys пользователя, под которым будет выполняться приём (это может быть sync или, например, www-data, если политика безопасности и владельцы файлов позволяют). Убедитесь, что доступ по SSH работает:

ssh -i /home/sync/.ssh/id_ed25519 sync@10.0.0.12 id

Позаботьтесь о владельцах и правах. Проще всего, когда UID/GID веб-пользователя совпадают на всех нодах, тогда rsync --numeric-ids сохранит владельцев корректно. В альтернативном сценарии используйте современный rsync с --chown=www-data:www-data на целевой стороне.

Настройка лимитов inotify

Большие каталоги медиа быстро упираются в лимиты наблюдений. Поднимем значения, чтобы lsyncd не терял события при пике активности:

# /etc/sysctl.d/99-inotify.conf
fs.inotify.max_user_watches=524288
fs.inotify.max_user_instances=1024
fs.inotify.max_queued_events=65536
sudo sysctl --system

После изменения перезапустить сервис lsyncd будет полезно.

Базовая конфигурация lsyncd

Создадим конфиг /etc/lsyncd/lsyncd.conf.lua. Сценарий: исходная нода синхронизирует /var/www/site.com/uploads на целевую ноду по SSH, аккуратно обрабатывает удаления и защищается от частично записанных файлов.

settings {
  logfile = "/var/log/lsyncd/lsyncd.log",
  statusFile = "/var/log/lsyncd/lsyncd.status",
  statusInterval = 10,
  nodaemon = false
}

sync {
  default.rsyncssh,
  source = "/var/www/site.com/uploads",
  host = "10.0.0.12",
  targetdir = "/var/www/site.com/uploads",
  delay = 5,
  maxProcesses = 2,
  init = false,
  insist = true,
  excludeFrom = "/etc/lsyncd/exclude_uploads.txt",
  rsync = {
    archive = true,
    compress = true,
    verbose = true,
    rsh = "ssh -i /home/sync/.ssh/id_ed25519 -o StrictHostKeyChecking=yes",
    _extra = {
      "--delete-delay",
      "--partial",
      "--delay-updates",
      "--numeric-ids"
      -- при необходимости: "--chown=www-data:www-data"
      -- при ограниченном канале: "--bwlimit=20m"
    }
  }
}

Пояснения:

  • delay = 5 — дебаунс, чтобы сгладить бурст создания миниатюр/превью.
  • --delete-delay — удаления применяются в безопасном режиме, минимизируя окна несогласованности.
  • --partial и --delay-updates — уменьшают риск увидеть на целевой ноде «недописанные» файлы. rsync пишет во временный файл, затем переименовывает.
  • --numeric-ids — сохраняет владельцев по UID/GID, не полагаясь на имена пользователей.

Фильтры исключений

Создайте файл исключений /etc/lsyncd/exclude_uploads.txt. Имеет смысл отбрасывать временные расширения редакторов, кэш, служебные файлы:

.*.swp
.*.swx
.*.tmp
.*.part
cache/
.thumbs/

Если приложение пишет временные файлы с собственным суффиксом, добавьте и его, чтобы rsync не стартовал преждевременно.

Многоточечная репликация

Хотите расшарить медиа на несколько нод сразу? Просто добавьте ещё один блок sync с другим host, targetdir и, при необходимости, отдельным ключом SSH. lsyncd запустит независимые пайплайны, каждый со своими maxProcesses и очередями.

Сервис и логирование

В большинстве дистрибутивов lsyncd уже поставляется с unit-файлом для systemd. Если нет — создайте /etc/systemd/system/lsyncd.service:

[Unit]
Description=Live Syncing Daemon
After=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/lsyncd -nodaemon /etc/lsyncd/lsyncd.conf.lua
Restart=always
RestartSec=3
User=root

[Install]
WantedBy=multi-user.target

Запуск и проверка:

sudo systemctl daemon-reload
sudo systemctl enable --now lsyncd
sudo systemctl status lsyncd
sudo tail -f /var/log/lsyncd/lsyncd.log

Для интерактивной отладки удобно поднять lsyncd в не-демонском режиме и с подробным логом:

sudo systemctl stop lsyncd
sudo lsyncd -nodaemon -log all /etc/lsyncd/lsyncd.conf.lua

Консоль: unit-файл systemd и tail лога lsyncd

Начальная полная синхронизация

Перед тем как запускать «живой» режим, сделайте стартовую копию каталогов. Это снизит нагрузку и ускорит последующие дельты:

rsync -aHAXvz --numeric-ids --delete --progress /var/www/site.com/uploads/ sync@10.0.0.12:/var/www/site.com/uploads/

Когда директории выровнены, запускайте lsyncd и следите за логом. Если готовите перенос на новую площадку, посмотрите материал миграция сайта без простоя.

Безопасная запись и задержки

Главная забота при синхронизации медиа — не отдать пользователю «полуфайл». Большинство приложений пишут во временное имя и делают атомарный rename, что хорошо. На уровне rsync мы усиливаем это --delay-updates: копирование идёт во временное имя и финализируется переименованием только после завершения передачи. Параметр delay в lsyncd помогает сгладить бурст генерации множества файлов-превью: лучше передать их одним пакетом и не гонять сотни коротких сеансов.

Тюнинг rsync под медиа

  • Сжатие: compress = true экономит трафик на текстовых и некоторых бинарных форматах, но JPEG/PNG/WebP сжимаются плохо. Тестируйте.
  • Контроль полосы: --bwlimit пригодится, чтобы не забить канал при бэкенд-задачах.
  • Хеши: для крупных файлов редактируйте только по необходимости; rsync по умолчанию сравнивает размер и время модификации, что быстрее.
  • --inplace: используйте осторожно. Он обновляет файл на месте, что иногда быстрее для огромных объектов, но повышает риск «окна» неконсистентности. Для медиа обычно лучше оставаться на --delay-updates.

Масштабирование и несколько получателей

Для трёх и более целевых нод добавляйте новые секции sync. Если сеть звездообразная, следите за суммарной нагрузкой на исходную ноду и сеть. При большом трафике стоит поднять maxProcesses или наоборот уменьшить, чтобы избежать лишней конкуренции за диск и CPU.

Топологии:

  • Hub-and-spoke: одна мастер-нода пушит на все рабочие.
  • Chain: A → B → C. Проще сеть, но увеличивает суммарную задержку и риски накопления ошибок.
  • Fanout через несколько источников: лучше избегать многописателей; если неизбежно — пересмотрите архитектуру в сторону общего хранилища или объектов.

Если запускаете несколько приёмников, удобнее управлять ими на VDS с едиными пользователями и ключами SSH.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Отказоустойчивость и восстановление

insist = true заставляет lsyncd упорно пытаться переподключаться при сбоях на старте. Во время работы, если соединение оборвётся, задания будут повторяться. В долгих простоях накопятся очереди, поэтому после восстановления связи следите за логом и метриками диска.

Если каталоги разошлись (например, целевая нода долго была офлайн), безопаснее повторить форсированную rsync --delete перед повторным включением живой синхронизации, чтобы не тянуть «мусорные» расхождения событиями.

Тесты: замеряем задержки

Быстрый способ оценить задержку: создать файл с меткой времени и посмотреть, через сколько он появляется на целевой ноде.

date +%s > /var/www/site.com/uploads/ping.txt
ssh sync@10.0.0.12 stat -c %Y /var/www/site.com/uploads/ping.txt

Разница во времени даст ориентир. Проведите серию испытаний на загруженной системе и при массовом создании миниатюр, чтобы подобрать delay и maxProcesses.

Типичные проблемы и их решения

  • Права и владельцы: убедитесь, что веб-процесс может читать/писать, а rsync не ломает владельцев. Либо синхронизируйте под тем же пользователем, либо используйте --chown.
  • SELinux/AppArmor: проверьте профили. Возможно, потребуется разрешить демону доступ к каталогу uploads и к SSH-клиенту.
  • SSH-ключи и known_hosts: заранее «познакомьте» хосты, чтобы не было интерактивных запросов подтверждения ключа.
  • inotify overflow: если в lsyncd.log видите переполнение очереди, увеличьте лимиты и пересмотрите exclude для временных файлов.
  • Системные ресурсы: следите за IO, особенно на HDD. Пакетная отправка и компрессия иногда спасают, но могут грузить CPU.
  • Инициализация: первый запуск с пустой целевой стороной займёт время. Обязательно делайте предварительный rsync.
  • Разные часовые пояса и часы: рассинхрон времени увеличивает ложные дельты. Держите NTP в порядке.

Варианты конфигурации

Иногда вместо default.rsyncssh используют default.rsync с rsync-демоном на целевой стороне. Это ускоряет коннект и снижает накладные расходы SSH, но усложняет безопасность. Для большинства веб-проектов SSH-компонент проще и безопаснее.

Если у вас одна нода с приёмом, а чтение медиа происходит с CDN, можно синхронизировать только из мастера в сборочную ноду, а дальше уже поставлять статику из кэша. Важно лишь обеспечить неизменяемость URL и своевременную инвалидацию.

Итоги

lsyncd в паре с rsync — практичный способ держать каталог uploads согласованным между несколькими веб-нодами почти в реальном времени. inotify даёт быстрый триггер, дебаунс режет «шум», а правильные флаги rsync обеспечивают атомарность и аккуратные удаления. Внимание к правам, лимитам и отладочным логам — и связка будет работать годами, не требуя постоянного вмешательства.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину

Ошибка mount: wrong fs type, bad option, bad superblock в Debian/Ubuntu может означать и простую опечатку в имени раздела, и пробл ...
Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление

Если XFS-раздел внезапно стал доступен только для чтения, а сервер ушёл в emergency mode, главное — не спешить. Разберём безопасны ...
Debian/Ubuntu: как исправить Failed to fetch при apt update OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Failed to fetch при apt update

Ошибка Failed to fetch при apt update в Debian и Ubuntu обычно связана не с самим APT, а с DNS, сетью, зеркалом, прокси, временем ...