HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <p><strong>Исходная ситуация</strong>Есть несколько нод веб-сервера, картинки проекта подключены симлинком и физически лежат на хранилище, подключённом по NFS. Отсюда имеем одну точку отказа - лежит NFS: нет картинок, ну и скорость чтения так себе, учитывая накладные расходы на сетевую передачу.</p>
1 <p><strong>Исходная ситуация</strong>Есть несколько нод веб-сервера, картинки проекта подключены симлинком и физически лежат на хранилище, подключённом по NFS. Отсюда имеем одну точку отказа - лежит NFS: нет картинок, ну и скорость чтения так себе, учитывая накладные расходы на сетевую передачу.</p>
2 <p><strong>Что будем реализовывать</strong>Несколько веб-серверов, картинки лежат на них локально на отдельно подключённом быстром диске и синхронизируют картинки через отдельное хранилище. Таким образом, чтение становится быстрее за счёт нахождения файлов локально. Также в случае падения какой-то ноды, проект продолжает работать. И так как картинки в основном читаются, а пишутся редко (1-2 раза в день), можно в спокойном режиме переподнять хранилище для обмена, чтобы растащить новые картинки по остальным нодам.</p>
2 <p><strong>Что будем реализовывать</strong>Несколько веб-серверов, картинки лежат на них локально на отдельно подключённом быстром диске и синхронизируют картинки через отдельное хранилище. Таким образом, чтение становится быстрее за счёт нахождения файлов локально. Также в случае падения какой-то ноды, проект продолжает работать. И так как картинки в основном читаются, а пишутся редко (1-2 раза в день), можно в спокойном режиме переподнять хранилище для обмена, чтобы растащить новые картинки по остальным нодам.</p>
3 <p>Для реализации замысла был выбран<strong>lsyncd</strong>, так как другие решения имели недостатки: - DRBD - идеально для синхронизации между двумя серверами, но в более сложных конфигурациях нужно сильно<em>"велосипедить"</em>; - Ceph - слишком сложно для данного кейса; - GlusterFS - оказалось медленнее NFS в моём случае.</p>
3 <p>Для реализации замысла был выбран<strong>lsyncd</strong>, так как другие решения имели недостатки: - DRBD - идеально для синхронизации между двумя серверами, но в более сложных конфигурациях нужно сильно<em>"велосипедить"</em>; - Ceph - слишком сложно для данного кейса; - GlusterFS - оказалось медленнее NFS в моём случае.</p>
4 <h2>Итак, реализация</h2>
4 <h2>Итак, реализация</h2>
5 <p>Выбираем/создаём каталог для синхронизации и создаём его на обоих серверах. Затем создаём ключи для пользователя, от имени которого будет происходить синхронизация:</p>
5 <p>Выбираем/создаём каталог для синхронизации и создаём его на обоих серверах. Затем создаём ключи для пользователя, от имени которого будет происходить синхронизация:</p>
6 <p>Добавляем ключи на сервер. Чтобы это сделать, копируем содержимое созданного файла ~/.ssh/id_rsa.pub с сервера, на котором создали ключ для подключения, в файл ~/.ssh/authorized_keys на сервере, к которому будет подключаться. Пробуем подключиться к целевому серверу:</p>
6 <p>Добавляем ключи на сервер. Чтобы это сделать, копируем содержимое созданного файла ~/.ssh/id_rsa.pub с сервера, на котором создали ключ для подключения, в файл ~/.ssh/authorized_keys на сервере, к которому будет подключаться. Пробуем подключиться к целевому серверу:</p>
7 <p>Подключение должно пройти успешно. Повторяем 1 шаг на втором сервере и добавляем ключ пользователя со второго сервера, на первый.</p>
7 <p>Подключение должно пройти успешно. Повторяем 1 шаг на втором сервере и добавляем ключ пользователя со второго сервера, на первый.</p>
8 <p>Далее устанавливаем<strong>lsyncd</strong>на обоих серверах:</p>
8 <p>Далее устанавливаем<strong>lsyncd</strong>на обоих серверах:</p>
9 sudo yum install lsyncd -y<p>Редактируем conf-файл. Файл /etc/lsyncd.conf пишется в формате<strong>lua</strong>. Самое простое - сделать один конфиг со всеми нодами и скопировать его на сервера, закомментировав ненужные куски конфига. У меня файл получился примерно таким для сервера<strong>nfs-exchange</strong>, через который будет происходить обмен:</p>
9 sudo yum install lsyncd -y<p>Редактируем conf-файл. Файл /etc/lsyncd.conf пишется в формате<strong>lua</strong>. Самое простое - сделать один конфиг со всеми нодами и скопировать его на сервера, закомментировав ненужные куски конфига. У меня файл получился примерно таким для сервера<strong>nfs-exchange</strong>, через который будет происходить обмен:</p>
10 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, }<p>На остальных нодах закомментированы все ноды и раскомментирован только участок конфига, касающийся хоста nfs-exchange.</p>
10 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, }<p>На остальных нодах закомментированы все ноды и раскомментирован только участок конфига, касающийся хоста nfs-exchange.</p>
11 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, } ]]<p>Когда конфиги созданы, можем включать<strong>lsyncd</strong>с обеих сторон на серверах. Желательно, конечно, включить с одной стороны, посмотреть<strong>log</strong>, и если все хорошо, включать с другой стороны.</p>
11 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, } ]]<p>Когда конфиги созданы, можем включать<strong>lsyncd</strong>с обеих сторон на серверах. Желательно, конечно, включить с одной стороны, посмотреть<strong>log</strong>, и если все хорошо, включать с другой стороны.</p>
12 systemctl start lsyncd systemctl enable lsyncd<h2>Тюнинг ядра</h2>
12 systemctl start lsyncd systemctl enable lsyncd<h2>Тюнинг ядра</h2>
13 <p>Также, чтобы<strong>inotify</strong>смог отслеживать большое количество каталогов, необходимо увеличить значения параметров ядра.</p>
13 <p>Также, чтобы<strong>inotify</strong>смог отслеживать большое количество каталогов, необходимо увеличить значения параметров ядра.</p>
14 echo " fs.inotify.max_user_watches = 16777216 fs.inotify.max_queued_events = 65536 " &gt;&gt; /etc/sysctl.conf<p>Если всё сделано правильно, файлы должны синхронизироваться. Далее, можно и нужно настроить мониторинг службы<strong>lsyncd</strong>с помощью<strong>monit</strong>, например, по этому<a>мануалу</a>.</p>
14 echo " fs.inotify.max_user_watches = 16777216 fs.inotify.max_queued_events = 65536 " &gt;&gt; /etc/sysctl.conf<p>Если всё сделано правильно, файлы должны синхронизироваться. Далее, можно и нужно настроить мониторинг службы<strong>lsyncd</strong>с помощью<strong>monit</strong>, например, по этому<a>мануалу</a>.</p>
15  
15