В конце прошлого года нам поступила задача по реализации отказоустойчивого хранилища для разрабатываемого сервиса.

Ранее для этих целей предложили бы готовое решение в виде СХД с поддержкой сетевых протоколов вроде Hitachi NAS Platform (HNAS). Но текущая ситуация и особенности контракта обязывали проработать решение на мощностях заказчика.

В итоге выбрали и реализовали решение с использованием ОС на ядре Linux и кластере PaceMaker — с общим диском, поддержкой кворума, демона SDB и протокола NFS. Кому интересны особенности реализации, прошу под кат.

Статья рассчитана на читателя, знакомого с основами PaceMaker. В ней использую собственные ВМ, так как от заказчика сложно получить данные

Исходная задача

Цель — реализовать на площадке клиента хранение пользовательских файлов для разрабатываемого сервиса. Сервис — java-приложение, запущенное на нескольких ВМ.

Критерии выбора решения

  1. Простота реализации

  2. Низкая стоимость поддержки и высокая автономность работы

  3. Проверенные технологии

  4. Максимальная живучесть решения

  5. Использование текущих возможностей инфраструктуры заказчика

При этом мы учитывали нашу финансовую ответственность при недоступности файлового хранилища. Для понимания, заказчик — крупная организация, основная деятельность которой не IT, типичный кровавый Enterprise.

Проектируемая нагрузка

  • Не более 15 000 файлов за сутки

  • Средний размер файла — до 1 Мб

  • Ожидаемое увеличение данных за год — до 5 Тб

  • Глубина хранения — 3 или 5 лет

Выбор решения

Мы хотели найти POSIX-совместимое решение для снижения затрат на разработку и дальнейшую поддержку.

S3 не подходил из-за высокой стоимости поддержки и нецелесообразности для планируемых нагрузок. GlusterFS выглядел хорошо, но с ним имелся негативный опыт работы. Может сейчас работает хорошо, и я знаю проекты, где хранятся миллионы объектов и терабайты данных, но осадочек остался. Другие кластерные ФС нами не рассматривались ввиду отсутствия опыта их внедрения и сопровождения.

Поэтому выбор свёлся к следующим решениям на базе протокола NFS:

  • отдельные диски с репликацией по DRDB + PaceMaker

  • отдельные диски с репликацией через LsyncD + PaceMaker

  • общие диски (Shared Storage) + PaceMaker

Мы остановились на 3 варианте из-за низких затрат на дисковое пространство, минимального количества точек потенциального отказа и объектов для мониторинга.

По сути в выбранном решении только файловая система и является единственной точкой отказа. Используется некластерная файловая система, которая не поддерживает множественный доступ с различных серверов. За монопольный доступ отвечает PaceMaker.

Стенд

У меня будет 3 ВМ с CentOS 7 — у заказчика это основная ОС: большие компании с основными статьями дохода, не связанными с ИТ, сложно и медленно переходят на что-то новое.

Надеюсь, под другие ОС предложенное решение подойдёт и найдутся нужные пакеты

Имя ВМ

IP

Nfs1

10.55

Nfs2

10.56

Nfs3

10.57

10.58 будет использоваться под VIP NFS.

Ко всем ВМ подключён общий диск на 20 Гб для хранения данных.

sdb 8:16 0 20G 0 disk

Мой стенд развёрнут через VirtualBox. У заказчика система виртуализации WMWare, диски поданы по FC.

Особенности реализации решения

  • ВМ одинаковы в своих аппаратных ресурсах. Если у вас сложности с ресурсами, сделайте третью ВМ с минимальными аппаратными характеристиками и запретите запускаться на ней ресурсам файлового сервера

  • Для ВМ должно быть реализовано правило Anfi Affinity для размещения на разных физических серверах

  • Общие диски должны быть презентованы ВМ с одного хранилища (Datastore)

  • Общие диски должны быть доступны по одинаковым путям внутри ВМ

  • Нужна отдельная сетка для работы приклада и файлового хранилища. Это может быть виртуальная сеть, реализованная поверх существующей физической сети, но со своим QOS

  • Самое важное — к узлам файлового кластера надо относиться, как к контроллерам СХД. На них не должны запускать скрипты для создания резервных копий или другое ПО, работающее с данными. Вся пишущая и читающая нагрузка должна приходить снаружи кластера через VIP

Схематичное представление

Реализация

Базовая настройка

Теория и всякие требования — это скучно, переходим к практике.

У нас 3 новеньких сервера. Обновляемся и ставим пакеты на всех серверах

[root]# yum update -y 
[root]# yum install pcs pacemaker fence-agents-sbd sbd dlm -y

В /etc/hosts добавляем записи по нашим серверам или на DNS создаем соответствующие A-записи.

DLM (Distributed Lock Manager) по факту не используется: он нужен для работы кластерных файловых систем. Однако он прописан как зависимость службы SBD, поэтому его устанавливаем, но не настраиваем. Альтернативное решение правка service unit SBD с удалением зависимостей от DLM

Разрешим сетевое взаимодействие между узлами кластера

[root]# firewall-cmd --permanent --add-service=high-availability`
[root]# firewall-cmd --permanent --add-service=nfs 
[root]# firewall-cmd --reload

Обращаю внимание, что SELinux оставляем включённым.

Настроим общий диск на первом сервере

[root@nfs1 ~]# parted /dev/sdb
(parted) mklabel gpt
(parted) mkpart primary xfs 1 100%FREE
(parted) quit
[root@nfs1 ~]# partprobe
[root@nfs1 ~]# lsblk
sdb               8:16   0   20G  0 disk
└─sdb1            8:17   0   20G  0 part 
[root@nfs1 ~]# mkfs.xfs /dev/sdb1

Если на другом сервере выполнить команду partprobe и lsblk, увидим идентичные изменения в структуре дисков.

Не использую LVM, так как это усложнит схему и нет надобности под текущую задачу и структуру организации данных. Скорее всего, нужно будет дополнительно отключать lvmetad и вносить правки

На всех серверах задаём пароль для пользователя и включаем службы

echo "CHANGE_ME" | passwd hacluster --stdin 
systemctl enable pcsd --now

Собираем кластер, выполняем разово на любом узле

pcs cluster auth nfs1 nfs2 nfs3 -u hacluster -p CHANGE_ME
pcs cluster setup --start --name nfs_cluster nfs1 nfs2 nfs3
pcs cluster enable --all

Проверяем, что получилось

[root@nfs1 ~]# pcs status
Cluster name: nfs_cluster

WARNINGS:
No stonith devices and stonith-enabled is not false
Stack: corosync
Current DC: nfs3 (version 1.1.23-1.el7_9.1-9acf116022) - partition with quorum

3 nodes configured
0 resource instances configured

Online: [ nfs1 nfs2 nfs3 ]

No resources

Daemon Status:
  corosync: active/enabled
  pacemaker: active/enabled
  pcsd: active/enabled

Обратите внимание, что ругается на отсутствие stonith devices и среди статуса демонов только 3 службы.

Настройка stonith device

SBD (Storage-Based Death) умеет вызывать stonith через watchdog, обмениваться сообщениями между узлами кластера и интегрироваться с PaceMaker.

Все прочитанные мной статьи по настройке отказоустойчивых решений на базе PaceMaker предлагали настраивать stonith device через IPMI или vCenter или вообще отключать stonith, брррр.

Используя SBD, можно обойтись без внешних зависимостей, что идеально подходит для виртуальных машин.

SBD может работать в двух режимах:

  • без общего диска — участники SBD обмениваются сообщениями по сети, поэтому нужно 3 сервера для правильного формирования кворума и обработки отказов в работе одного из узлов

  • с общим диском или дисками — участники SBD обмениваются сообщениями через общий диск

Благодаря SBD удалось добиться нужного поведения, когда при недоступности общего диска или сети происходит перезагрузка сервера.

Так как у нас ВМ, то для перезапуска будем использовать softdog — программную реализацию watchdog, которая в ОС присутствует в виде модуля ядра.

На всех серверах проверим наличие softdog, добавим в автозагрузку и протестируем его работу

/sbin/modprobe softdog
ls -al /dev/watchdog
echo softdog > /etc/modules-load.d/softdog.conf
systemctl restart systemd-modules-load
lsmod | grep softdog
sbd query-watchdog
Discovered 2 watchdog devices:

[1] /dev/watchdog
Identity: Software Watchdog
Driver: softdog
CAUTION: Not recommended for use with sbd.

[2] /dev/watchdog0
Identity: Software Watchdog
Driver: softdog
CAUTION: Not recommended for use with sbd.

Softdog не отработает, если зависнут все ядра CPU. Если в вашем случае это критично, нужно использовать аппаратный watchdog. В этом решении пошли на обозначенный риск

Отключаем stonith на уровне кластера

pcs property set stonith-enabled="false"
pcs property set stonith-timeout=0
pcs property set stonith-watchdog-timeout=0

Настраиваем SBD, за нас это может сделать pcs

pcs stonith sbd enable \
    --watchdog=/dev/watchdog \
    SBD_STARTMODE=clean

Проверяем его настройки

cat /etc/sysconfig/sbd
# This file has been generated by pcs.
SBD_DELAY_START=no
SBD_OPTS="-n nfs1"
SBD_PACEMAKER=yes
SBD_STARTMODE=clean
SBD_WATCHDOG_DEV=/dev/watchdog
SBD_WATCHDOG_TIMEOUT=5

Перезагружаем все узлы. По умолчанию службу sbd нельзя остановить или запустить руками

[root@nfs1 ~]# pcs stonith sbd status --full
SBD STATUS
<node name>: <installed> | <enabled> | <running>
nfs1: YES | YES | YES
nfs3: YES | YES | YES
nfs2: YES | YES | YES

[root@nfs1 ~]# sbd query-watchdog
Discovered 2 watchdog devices:

[1] /dev/watchdog
Identity: Error: Check if hogged by e.g. sbd-daemon!
Driver: <unknown>

[2] /dev/watchdog0
Identity: Error: Check if hogged by e.g. sbd-daemon!
Driver: <unknown>

Вернёт ошибку, и это ожидаемо. Мы убеждаемся, что softdog занят запущенным процессом SBD.

Теперь статус кластера выглядит нормально

[root@nfs1 ~]# pcs status
Cluster name: nfs_cluster
Stack: corosync
Current DC: nfs3 (version 1.1.23-1.el7_9.1-9acf116022) - partition with quorum

3 nodes configured
0 resource instances configured

Online: [ nfs1 nfs2 nfs3 ]

No resources

Daemon Status:
  corosync: active/enabled
  pacemaker: active/enabled
  pcsd: active/enabled
  sbd: active/enabled

Ушло предупреждение o stonith devices среди статуса демонов 4 службы.

Возвращаем настройки stonith и проверяем

pcs property set stonith-timeout="12s"
pcs property set stonith-watchdog-timeout="6s"
pcs property set cluster-recheck-interval="1m"
pcs property set stonith-enabled="true"
pcs property set fence-reaction="panic"
pcs property set no-quorum-policy=suicide

Так как watchdog занят запущенным процессом SBD, для проверки тестирования эти команды не подойдут:

  • pcs stonith sbd watchdog test

  • pcs stonith fence <node>

Проверить stonith можно, завершив процесс SBD

[root@nfs1 ~]# systemctl status sbd
● sbd.service - Shared-storage based fencing daemon
   Loaded: loaded (/usr/lib/systemd/system/sbd.service; enabled; vendor preset: disabled)
   Active: active (running)
  Process: 695 ExecStart=/usr/sbin/sbd $SBD_OPTS -p /var/run/sbd.pid watch (code=exited, status=0/SUCCESS)
 Main PID: 715 (sbd)
   CGroup: /system.slice/sbd.service
           ├─715 sbd: inquisitor
           ├─724 sbd: watcher: Pacemaker
           └─725 sbd: watcher: Cluster
[root@nfs1 ~]# kill -9 715

После этого должна произойти перезагрузка сервера.

Создание NFS-кластера

На всех серверах установим необходимые компоненты

yum install nfs-utils -y
systemctl stop nfs-lock && systemctl disable nfs-lock

Службу nfs-lock выключаем, так как NFS-сервером будет управлять PaceMaker.

На любом узле получаем UUID диска

[root@nfs1 ~]# blkid -o list
device            fs_type    label     mount point         UUID
----------------------------------------------------------------------------------------------
/dev/sdb1         xfs                  (not mounted)       96a78db6-1d4b-421c-8888-747e5aa61094

Монтируем диск

pcs resource create nfs_fs1 ocf:heartbeat:Filesystem \
  device=-U96a78db6-1d4b-421c-8888-747e5aa61094 directory=/nfs_server fstype=xfs \
  options=noatime,nodiratime,noexec,nosuid \
  --group nfs_group \
  op monitor interval=1s timeout=5s on-fail=fence \
  OCF_CHECK_LEVEL=10

OCF_CHECK_LEVEL=10 проверяет диск на доступность, ЧИТАЯ первые 16 бит. Это позволяет перезагрузить узел при недоступности диска (опция on-fail=fence), и запустить ресурсы на другом узле кластера.

Первый общий диск хранит на себе состояние работы NFS-сервера

pcs resource create nfs_server ocf:heartbeat:nfsserver \
  nfs_shared_infodir=/nfs_server/server nfs_no_notify=true nfsd_args="--grace-time 10"\
  --group nfs_group --after nfs_fs1 \
  op monitor interval=1s timeout=10s on-fail=fence

Публикуем NFS-ресурс

mkdir -p /nfs_server/data1
pcs resource create nfs_data1 ocf:heartbeat:exportfs \
  clientspec="10.0.0.0/24" options=rw,sync,no_root_squash directory=/nfs_server/data1 \
  fsid=1001 wait_for_leasetime_on_stop=false unlock_on_stop="1"\
  --group nfs_group --after nfs_server \
  op monitor interval=1s timeout=10s on-fail=fence

В отдельной группе создаём VIP

pcs resource create nfs_vip ocf:heartbeat:IPaddr2 \
  ip=10.0.0.54 cidr_netmask=24 op monitor interval=1s \
  --group nfs_vip_group

В конце устанавливаем зависимости

pcs constraint order start nfs_group then nfs_vip_group
pcs constraint colocation add nfs_group with nfs_vip_group INFINITY

Проверяем состояние кластера и зависимостей

[root@nfs1 ~]# pcs status
Cluster name: nfs_cluster
Stack: corosync
Current DC: nfs3 (version 1.1.23-1.el7_9.1-9acf116022) - partition with quorum

3 nodes configured
4 resource instances configured

Online: [ nfs1 nfs2 nfs3 ]

Full list of resources:

 Resource Group: nfs_group
     nfs_fs1    (ocf::heartbeat:Filesystem):    Started nfs2
     nfs_server (ocf::heartbeat:nfsserver):     Started nfs2
     nfs_data1  (ocf::heartbeat:exportfs):      Started nfs2
 Resource Group: nfs_vip_group
     nfs_vip    (ocf::heartbeat:IPaddr2):       Started nfs2

Daemon Status:
  corosync: active/enabled
  pacemaker: active/enabled
  pcsd: active/enabled
  sbd: active/enabled

[root@nfs1 ~]# pcs constraint
Location Constraints:
Ordering Constraints:
  start nfs_group then start nfs_vip_group (kind:Mandatory)
Colocation Constraints:
  nfs_group with nfs_vip_group (score:INFINITY)
Ticket Constraints:

В дальнейшем планируется увеличивать количество дисков через ocf:heartbeat:Filesystem и публиковать доступ к ним, используя ocf:heartbeat:exportfs в пределах группы nfs_group.

Подключение клиентов и тестирование

NFS-клиенты подключаются стандартным образом.

Основные особенности

  1. Режим монтирования soft — в нём при недоступности NFS-ресурса клиенту вернётся ошибка ввода вывода. Разработки учитывают этот момент в реализации сервиса

  2. Версия NFS 4.1, используем её . Если когда-нибудь возникнут проблемы, к примеру, с блокировками, попробуем NFS 3

Проведённые тесты

  1. Штатное выключение / перезагрузка

  2. Аварийное выключение / перезагрузка

  3. Потеря общего диска

  4. Потеря сети

  5. Потеря кворума, например, непровальная настройка firewall

  6. Выключение и включение всего кластера

  7. Недоступность большинства узлов

Все тесты проводились под пишущей и читающей нагрузкой и показали нужное поведение: перезагрузку тестируемого узла и миграцию ресурсов на другие.

Со стороны клиента замерялось самое длительное время недоступности NFS — до 12-14 секунд при выходе из строя активного узла.

Заключение

Решение получилось простым, отказоустойчивым и для данной задачи масштабируемым без внешних зависимостей.

Возможные риски

Представляет опасность отсутствие отказоустойчивости на уровне файловой системы общего диска и возможность множественного доступа, который приведёт к порче файловой системы.

Для минимизации рисков можно было бы реализовать SCSI SPC-3 persistent reservations, но нет агента sg_persist для Pacemaker в Centos7. Однако для спокойного сна мы пробовали монтировать ФС на нескольких узлах кластера, с операциями записи через один узел — и это не привело к гибели ФС.

Взвесив все «за» и «против», мы выбрали описанную выше реализацию.

Ещё раз, главное

  1. К узлам кластера относиться как к контроллерам СХД — не допускать локальных процессов с пишущими операциями на общие диски. Все активности должны приходить снаружи кластера через отказоустойчивый адрес

  2. Не пытаться смонтировать ФС руками. Все операции должен проводить Pacemaker

  3. В полученном решении вероятность порчи ФС минимальна

Надеюсь, вы узнали что-то новое для себя. Всем добра!

Комментарии (10)


  1. podvox23
    25.08.2023 10:45

    Active-active с NFS можно сделать?


    1. chako8 Автор
      25.08.2023 10:45

      в описанной реализации это невозможно. Для Active-active нужны кластерные ФС. Тут можно только сделать размазывание NFS ресурсов по узлам


    1. AlexGluck
      25.08.2023 10:45

      У drbd есть diskless устройство, можно просто его монтировать с кластерной фс.

      Но это накладывает ограничения на необходимость настройки модуля ядра drbd на клиенте, чего в случае с nfs делать не надо и более универсально получается.


  1. Dante4
    25.08.2023 10:45
    +2

    Если ниже уровнем находится Варя, зачем эти игры с softdog?

    https://vm-guru.com/news/vmware-vsphere-7-vm-watchdog-timer

    И если у Вас уже есть Shared Disk, то к чему эти игры с pacemaker?

    Чем automount(8) daemon не подходит?

    https://www.redhat.com/sysadmin/mount-nfs-filesystems-autofs


    1. chako8 Автор
      25.08.2023 10:45

      vWDT это просто еще одна реализация watchdog. Не знал о его существовании. Но, наверное, не стал бы использовать. Хотелось получить универсальное решение. В описанном решении softdog нужен не только как классический watchdog, через него Pacemaker проводит обработку отказа в различных сценариях.

      Судя по статье, он поддерживается с vSphere 8.0, у нас версия была младше. Может еще какие-либо ограничения есть. Если когда-нибудь доведется, попробую, спасибо.

       

      Использовал automount на стороне клиента. Как его прикрутить для общего диска и не допустить множественного доступа с нескольких узлов, не понятно.


      1. Dante4
        25.08.2023 10:45

        Эрм,

        1) watchdog доступен просто с 7-й

        2) статья о которой Вы не совсем связана с watchdog механизмом о котором я говорил, там уже про правильную интеграцию RHEL кластеров

        3) automount можно прикрутить на два ip адреса и таймер, на то, что делать при недоступности первого пути


        1. chako8 Автор
          25.08.2023 10:45

          Так описанное решение в публикации и есть реализация RHEL High Availability Cluster. Если бы делали решение под конкретного вендора, то полностью следовали бы его рекомендациям (по правильной реализации High Availability Cluster). В своем предыдущем комментарии указал, что просто для этого нужен vSphere 8.0 т.к. именно Pacemaker будет взаимодействовать с vWDT. Пожалуйста, укажите где я не прав.

           

          Извините, все равно не понимаю, как automount можно безопасно использовать, имея несколько серверов приложений, NFS и общий диск.

          Комментарий понял так: на серверах приложений прописываем в automount несколько NFS серверов. При недоступности одного NFS сервера, приложения подключаются к другому.

          Представьте ситуацию, активный NFS сервер стал недоступен, все клиенты подключились к следующему. Недоступный NFS сервер возвращается в работу, возможны следующие проблемы:

          1.       Нет гарантий, что все клиенты смогут синхронно переподключиться к возвращенному в работу NFS серверу

          2.       Клиенты продолжат работать с текущим NFS сервером. Но тут уже серверу приложений надо перезагрузиться. Насколько понимаю, он подключится к возвращенному в работу NFS серверу

          Оба эти сценария могут привести к множественному доступу на запись к общему диску, что привести к утрате данных.

          Поэтому используется Pacemaker и входная точка, которой он управляет, для гарантии согласованного доступа к диску.


          1. Dante4
            25.08.2023 10:45

            Я сейчас не про взаимодействие pacemaker и vSphere. А про банальный Watchdog, который Варя эмулирует как железный для ОС. И ему не важно хоть все ядра повисли намертво или вся ОС ушла в kernel panic и заняла все ядра.

            У Вас же по условиям статичный набор клиентов?

            "Сервис — java-приложение, запущенное на нескольких ВМ."

            Если мы волнуемся, что сервер приложений будет перезапущен - keepalived идеально поможет


  1. Neveil
    25.08.2023 10:45

    S3 не подходил из-за высокой стоимости поддержки и нецелесообразности для планируемых нагрузок.

    А можно пояснить чем сложно поддерживать s3 minio? Он запускается за 5 мин в кластерном варианте. Уже в продакшене 2 года. У вас всего 10 файлов в минуту.


    1. chako8 Автор
      25.08.2023 10:45

      Отвечая на вопрос, напомню, что он основан на моем субъективном мнении и опыте. Учитывал контрактные обязательства перед заказчиком, опыт работы с ним, текущую инфраструктуру. Возможно, для Вас все сказанное будет неактуально. Основными критериями выбора в пользу POSIX ФС стали:

      1.       Более низкая стоимость разработки сервиса. Возможно, программисты скажут, что нет разницы или что S3 даже проще.

      2.       Административный ресурс. Сложнее найти на рынке специалистов, имеющих опыт развёртывания и эксплуатации Minio или Ceph, чем с pacemaker. Не говоря уже о том, чтобы обучить их этому. S3 более сложен для понимания, чем pacemaker с NFS.

      3.       Мониторинг. Текущая система мониторинга умеет работать с pacemaker и NFS. Внедрение Minio потребовало бы обновления системы мониторинга или реализации мониторинга через дополнительные скрипты.

      4.       Резервное копирование и восстановление. С S3 сложнее восстанавливать, особенно весь кластер при его утрате. Система резервного копирования заказчика не умеет создавать резервные копии с S3.

      5.       Администрирование. Восстановление узла, расширение доступного пространства – операции проще в предложенной реализации. У Minio появляются дополнительные сложности в виде ребалансировки (из того, что сразу пришло в голову).

      6.        Аппаратные ресурсы. В текущей инфраструктуре диски подаются с FC фабрики. Minio реализует собственную отказоустойчивость с использованием локальных дисков. FC диски дорого использовать для Minio.

      Наверное, это основное, что вспомнил. Под требования проекта весомых плюсов от реализации S3 совместимого хранилища не увидел.

      Отдельно скажу, что S3, и Minio в частности, используем на других проектах, где видим выигрыш от его реализации.