lsyncd: синхронизация файлов между несколькими серверами
Исходная ситуация
Есть несколько нод веб-сервера, картинки проекта подключены симлинком и физически лежат на хранилище, подключённом по NFS. Отсюда имеем одну точку отказа — лежит NFS: нет картинок, ну и скорость чтения так себе, учитывая накладные расходы на сетевую передачу.
Что будем реализовывать Несколько веб-серверов, картинки лежат на них локально на отдельно подключённом быстром диске и синхронизируют картинки через отдельное хранилище. Таким образом, чтение становится быстрее за счёт нахождения файлов локально. Также в случае падения какой-то ноды, проект продолжает работать. И так как картинки в основном читаются, а пишутся редко (1-2 раза в день), можно в спокойном режиме переподнять хранилище для обмена, чтобы растащить новые картинки по остальным нодам.
Для реализации замысла был выбран lsyncd, так как другие решения имели недостатки: — DRBD - идеально для синхронизации между двумя серверами, но в более сложных конфигурациях нужно сильно «велосипедить»; — Ceph - слишком сложно для данного кейса; — GlusterFS - оказалось медленнее NFS в моём случае.
Итак, реализация
Выбираем/создаём каталог для синхронизации и создаём его на обоих серверах. Затем создаём ключи для пользователя, от имени которого будет происходить синхронизация:
ssh-keygen
Добавляем ключи на сервер. Чтобы это сделать, копируем содержимое созданного файла
ssh username@server
Подключение должно пройти успешно. Повторяем 1 шаг на втором сервере и добавляем ключ пользователя со второго сервера, на первый.
Далее устанавливаем lsyncd на обоих серверах:
sudo yum install lsyncd -y
Редактируем conf-файл. Файл
settings { logfile = "/var/log/lsyncd/lsyncd.log", --[[log-файл с событиями синхронизации и ошибками]] statusFile = "/var/log/lsyncd/lsyncd.status", --[[файл, где указано какие каталоги отслеживает inotify и какие каталоги будут синхронизированы]] statusInterval = 5, --[[интервал обновления файла lsyncd.status в секундах]] } --[[ sync { default.rsyncssh, --[[выбор протокола синхронизации]] source = "/nfssync/pics", --[[каталог-источник для синхронизации]] host = "nfs-exchange", --[[целевой хост, куда каталог будет синхронизироваться]] targetdir = "/nfssync/pics", --[[целевой каталог на сервере, заданной в параметре host]] rsync = { _extra = { "-ausS", "--temp-dir=/tmp", "-e", "/usr/bin/ssh -l username -i /home/username/.ssh/id_rsa -o StrictHostKeyChecking=no" } }, --[[дополнительные параметры синхронизации: a — режим архивации; равносильно -rlptgoD, тоесть копировать рекурсивно, вместе с симлинками и специальными файлами, сохраняя права доступа, группу, владельца. u — не обновлять файлы на получателе если они новее; s — на случай если в имени файла попадется пробел. S — оптимизировать передачу данных состоящих из нулей. temp-dir нужна если синхронизация двухсторонняя далее я задал пользователя и его ключ, чтобы синхронизация происходила под пользователем, для которого мы ранее создали ключи и раскидали их по серверам. Опция -o StrictHostKeyChecking=no решает проблему ошибки Permission denied. Более подробно в man и тут: https://github.com/mralexjuarez/lsyncd-tutorial ]] delay = 3, --[[пауза между запуском синхронизации]] } ]] sync { default.rsyncssh, source = "/nfssync/pics", host = "node01", targetdir = "/nfssync/pics", rsync = { _extra = { "-ausS", "--temp-dir=/tmp", "-e", "/usr/bin/ssh -l username -i /home/username/.ssh/id_rsa -o StrictHostKeyChecking=no" } }, delay = 3 } sync { default.rsyncssh, source = "/nfssync/pics", host = "node02", targetdir = "/nfssync/pics", rsync = { _extra = { "-ausS", "--temp-dir=/tmp", "-e", "/usr/bin/ssh -l username -i /home/username/.ssh/id_rsa -o StrictHostKeyChecking=no" } }, delay = 3, } sync { default.rsyncssh, source = "/nfssync/pics", host = "node03", targetdir = "/nfssync/pics", rsync = { _extra = { "-ausS", "--temp-dir=/tmp", "-e", "/usr/bin/ssh -l username -i /home/username/.ssh/id_rsa -o StrictHostKeyChecking=no" } }, delay = 3, }
На остальных нодах закомментированы все ноды и раскомментирован только участок конфига, касающийся хоста nfs-exchange.
settings { logfile = "/var/log/lsyncd/lsyncd.log", statusFile = "/var/log/lsyncd/lsyncd.status", statusInterval = 5, } sync { default.rsyncssh, source = "/nfssync/pics", host = "nfs-exchange", targetdir = "/nfssync/pics", rsync = { _extra = { "-ausS", "--temp-dir=/tmp", "-e", "/usr/bin/ssh -l username -i /home/username/.ssh/id_rsa -o StrictHostKeyChecking=no" } }, delay = 3, } --[[ sync { default.rsyncssh, source = "/nfssync/pics", host = "node01", targetdir = "/nfssync/pics", rsync = { _extra = { "-ausS", "--temp-dir=/tmp", "-e", "/usr/bin/ssh -l username -i /home/username/.ssh/id_rsa -o StrictHostKeyChecking=no" } }, delay = 3 } sync { default.rsyncssh, source = "/nfssync/pics", host = "node02", targetdir = "/nfssync/pics", rsync = { _extra = { "-ausS", "--temp-dir=/tmp", "-e", "/usr/bin/ssh -l username -i /home/username/.ssh/id_rsa -o StrictHostKeyChecking=no" } }, delay = 3, } sync { default.rsyncssh, source = "/nfssync/pics", host = "node03", targetdir = "/nfssync/pics", rsync = { _extra = { "-ausS", "--temp-dir=/tmp", "-e", "/usr/bin/ssh -l username -i /home/username/.ssh/id_rsa -o StrictHostKeyChecking=no" } }, delay = 3, } ]]
Когда конфиги созданы, можем включать lsyncd с обеих сторон на серверах. Желательно, конечно, включить с одной стороны, посмотреть log, и если все хорошо, включать с другой стороны.
systemctl start lsyncd systemctl enable lsyncd
Тюнинг ядра
Также, чтобы inotify смог отслеживать большое количество каталогов, необходимо увеличить значения параметров ядра.
echo " fs.inotify.max_user_watches = 16777216 fs.inotify.max_queued_events = 65536 " >> /etc/sysctl.conf
Если всё сделано правильно, файлы должны синхронизироваться. Далее, можно и нужно настроить мониторинг службы lsyncd с помощью monit, например, по этому мануалу.