Организуем RAM-диск для кластера Windows Server с помощью Linux-IO FC Target

RAMdisk in Windows failover cluster using LIO FC TargetИзучая разные методы повышения производительности работы СУБД SQL Server, добрался до такой интересной темы, как использование RAM-диска для размещения файлов нагруженной системной базы данных tempdb. Выяснил для себя то, что из работоспособных свободно-распространяемых инструментов для организации RAM-диска под ОС Windows Server на текущий момент многие выделяют утилиту imDisk Toolkit. Однако этот инструмент, как и прочие его аналоги, не получится использовать в кластерных конфигурациях SQL Server, где использование ресурсов оперативной памяти (далее ОЗУ) в любой момент времени может быть переключено с одного кластерного узла на другой. То есть, если и использовать в кластере RAM-диск, то он должен быть одинаково доступен всем узлам кластера, как и любой другой кластерный диск, участвующий в конфигурации кластеризованного экземпляра SQL Server.

Напрашивающимся в таком случае решением может стать использование в качестве RAM-диска ОЗУ не самих узлов кластера, а ОЗУ стороннего хоста, подключенного к узлам кластера в качестве дискового устройства через транспорт Fiber Channel SAN (как отличающийся приемлемыми показателями задержки). То есть на выделенном хосте используются локальные ресурсы ОЗУ для создания RAM-диска, после чего RAM-диск транслируется на узлы кластера через FC SAN, как блочное устройство, и может использоваться в качестве кластерного диска.

RAMdisk in Windows failover cluster using LIO FC Target

Далее я опишу пример создания такого RAM-диска на выделенном хосте с ОС Debian GNU/Linux 9 и его трансляцию в SAN с помощью Linux-IO (LIO). На сервере для обеспечения работы FC Target предварительно установлен контроллер FC HBA QLogic и задействован специальный режим работы драйвераTarget Mode.

Обязательным условием в нашем примере является то, что на Linux-хосте нужно организовать механизм сохранения данных RAM-диска при выключении ОС и восстановлении данных на RAM-диск при включении ОС с использованием выделенного SSD-диска.

Настраиваем RAM-диск на Linux

Перейдём на наш Linux-сервер, имеющий большой объем оперативной памяти, часть которой мы готовы выделить под организацию RAM-диска.

Создаём каталог для RAM-диска и каталог для хранения резервной копии содержимого RAM-диска:

# mkdir /mnt/ramdisk1
# mkdir /mnt/ramdisk1-backup

Форматируем отдельный SSD диск для сохранения/восстановления данных RAM-диска при выключении/включении хостовой ОС Linux:

# mkfs -t ext4 /dev/cciss/c0d1

Проверяем монтирование созданного на SSD диске раздела в каталог для хранения резервной копии:

# mount /dev/cciss/c0d1 /mnt/ramdisk1-backup

Обратите внимание на то, что свободное место в каталоге /mnt/ramdisk1-backup всегда должно быть не меньше, чем размер планируемого содержимого RAM-диска. В противном случае мы можем столкнуться с ситуацией, при которой окажется невозможно сохранить данные RAM-диска при выключении сервера, что приведёт к потере всех данных на этом RAM-диске.

Выясним идентификатор UUID SSD-диска:

# blkid /dev/cciss/c0d1

Get disk UUID in Linux

В конец системного конфигурационного файла /etc/fstab добавляем директивы монтирования RAM-диска и диска для хранения в соответствующие каталоги:

# nano /etc/fstab
...
# Mount RAM-disk
#
tmpfs /mnt/ramdisk1 tmpfs defaults,size=30725M 0 0
#
# Mount SSD-disk for RAM saving/restoring
#
UUID=619be6d2-9023-4a46-8c0e-26206fe683f4 /mnt/ramdisk1-backup ext4 defaults 0 0

RAMDisk mount in fstab in Linux

При описании директивы создания RAM-диска нам желательно сразу правильно спланировать его размер, учитывая то, что размер диска должен быть немного больше, чем объём планируемого блочного устройства. Это нужно для того, чтобы в дальнейшем избежать сигнализации систем мониторинга о том, что исходный RAM-диск переполнен. Например, в нашем случае в fstab при запуске системы создаётся RAM-диск размером 30725MB, а на этом диске мы в последующем будем создавать файл размером 30720MB, который и будет в дальнейшем транслироваться в виде блочного устройства из LIO в SAN.

Настраиваем службу lio-config-controller

Создадим скрипт, который будет представлять собой основу для работы специальной службы systemd, которую мы назовём, например, lio-config-controller.service. Эта служба будет управлять запуском и остановкой блочного устройства, транслируемого в SAN через конфигурацию LIO.

# nano /usr/local/sbin/lio-config-controller.sh

Наполним скрипт содержимым:

#!/bin/sh
#

LogFile="/var/log/script_lio-config-controller.log"

AddToLog()
{
  echo $(date +"%F %T") $1
  echo $(date +"%F %T") $1 >> $LogFile
}

RunStartMode()
{

  AddToLog " ------- Script START mode session started ------- "
  AddToLog "Restore RAM-disk data from file..."
  if [ -e /mnt/ramdisk1-backup/ramdisk1.img ]
  then
    AddToLog "Saved image was found. Copying an image from disk to memory started..."
    cp /mnt/ramdisk1-backup/ramdisk1.img /mnt/ramdisk1
    AddToLog "Copy complete."

  else
    AddToLog "Saved image was not found. Create a new image file..."
    fallocate --length=30720M /mnt/ramdisk1/ramdisk1.img
    AddToLog "Creation completed."
  fi

  AddToLog "Flush LIO config..."
  targetcli clearconfig confirm=True

  AddToLog "Create LIO backstores..."
  targetcli /backstores/fileio create file_or_dev=/mnt/ramdisk1/ramdisk1.img name=FS04-RAMDisk1 write_back=false

  AddToLog "Create LIO Targets..."
  targetcli /qla2xxx create naa.50014380029a1644
  targetcli /qla2xxx create naa.50014380029a1646

  AddToLog "Create LIO backstores mappings to Targets..."
  targetcli /qla2xxx/naa.50014380029a1644/luns create /backstores/fileio/FS04-RAMDisk1
  targetcli /qla2xxx/naa.50014380029a1646/luns create /backstores/fileio/FS04-RAMDisk1

  AddToLog "Create ACLs..."
  AddToLog " - ACL for Initiator KOM-WS-NODE1..."
  targetcli /qla2xxx/naa.50014380029a1644/acls create c003ff9bfee40008
  targetcli /qla2xxx/naa.50014380029a1644/acls create C003FF9BFEE40009
  targetcli /qla2xxx/naa.50014380029a1646/acls create c003ff9bfee4000a
  targetcli /qla2xxx/naa.50014380029a1646/acls create C003FF9BFEE4000B
  AddToLog " - ACL for Initiator KOM-WS-NODE2..."
  targetcli /qla2xxx/naa.50014380029a1644/acls create c003ff2369260000
  targetcli /qla2xxx/naa.50014380029a1644/acls create C003FF2369260001
  targetcli /qla2xxx/naa.50014380029a1646/acls create c003ff2369260002
  targetcli /qla2xxx/naa.50014380029a1646/acls create C003FF2369260003

  AddToLog "Save LIO config..."
  targetcli saveconfig
  AddToLog "Copy of LIO configuration saved to /etc/rtslib-fb-target/saveconfig.json"
  AddToLog "Script finished."
}

RunStopMode()
{
  AddToLog " ------- Script STOP mode session started ------- "
  AddToLog "Flush LIO config..."
  /usr/bin/targetctl clear
  AddToLog "Save RAM-disk data to persistent file..."
  if [ -e /mnt/ramdisk1/ramdisk1.img ]
  then
    AddToLog "Image file in RAM-disk was found. Copying an image from memory to disk started..."
    cp /mnt/ramdisk1/ramdisk1.img /mnt/ramdisk1-backup
    AddToLog "Copy complete."
  else
    AddToLog "WARNINIG! Image file in RAM-disk was not found."
  fi
  AddToLog "Script finished."
}

case "$1" in
  start)
    RunStartMode
    ;;
  stop)
    RunStopMode
    ;;
  *)
    echo "Usage: $0 {start|stop}" >&2
    exit 1
    ;;
esac

Как видно, скрипт может работать в двух основных режимах:

1) Запуск c ключом start

В этом режиме скрипт будет размещать на уже доступном в системе RAM-диске в каталоге /mnt/ramdisk1 специальный файл ramdisk1.img. При этом img-файл будет вновь создаваться только в том случае, если его предыдущая копия не обнаружена на SSD-диске в каталоге /mnt/ramdisk1-backup. В случае обнаружения копии img-файла на SSD, эта копия будет восстанавливаться на RAM-диск. В дальнейшем img-файл на RAM-диске будет загружаться в конфигурацию LIO, создавая FC Target. Обратите внимание на то, что перед загрузкой новой конфигурации, текущая конфигурация LIO будет очищаться.

2) Запуск c ключом stop

В этом режиме конфигурация LIO очищается, то есть из системы удаляется FC Target, ассоциированный с img-файлом на RAM-диске. После чего происходит сохранение img-файла из RAM-диска на SSD-диск.

Оба режима работы скрипта логируют основные этапы выполняемых операций в отдельный log-файл.

Сделаем скрипт исполняемым:

# chmod +x /usr/local/sbin/lio-config-controller.sh

Так как наш скрипт предполагает наличие в системе уже смонтированных дисков, перед его вызовом мы должны удостовериться в том, что эти диски действительно смонтированы. Оформим вызов скрипта, как службы systemd, таким образом, чтобы у службы (юнита) lio-config-controller.service была зависимость от юнитов, отвечающих за монтирование соответствующих дисков.

Выясним то, какие имена имеют автоматически генерируемые юниты монтирования интересующих нас дисков:

# systemctl list-units --type=mount

systemd disk mount units

Как видим, в нашем случае юниты имеют имена "mnt-ramdisk1.mount" и "mnt-ramdisk1\x2dbackup.mount".

Создадим новый юнит lio-config-controller.service, который будет выполнять наш скрипт, загружая и останавливая тем самым конфигурацию LIO. При этом не забудем выставить зависимость от юнитов монтирования нужных нам дисков.

# nano /etc/systemd/system/lio-config-controller.service

Наполним конфигурацию юнита следующим образам:

[Unit]
Description=LIO Target Subsystem configuration controller service
After=mnt-ramdisk1.mount mnt-ramdisk1\x2dbackup.mount
Requires=mnt-ramdisk1.mount mnt-ramdisk1\x2dbackup.mount

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/lio-config-controller.sh start
ExecStop=/usr/local/sbin/lio-config-controller.sh stop
TimeoutStopSec=300

[Install]
WantedBy=multi-user.target

Так как в процессе остановки службы может потребоваться некоторое время на операцию сброса содержимого RAM-диска на SSD, дополнительно добавим таймаут ожидания остановки службы. Разумеется, если вместо SSD для хранения используется более медленный HDD, имеет смысл увеличить этот таймаут. В нашем случае этот таймаут составляет 300 секунд или 5 минут. При использовании SSD-диска величину таймаута можно сделать и ниже. Для расчёта оптимальной величины можно использовать фактическое время, затрачиваемое на сохранение содержимого RAM-диска, которое фиксируется скриптом в логе /var/log/script_lio-config-controller.log.

Включаем автоматическую загрузку созданного нами юнита в конфигурации systemd:

# systemctl enable lio-config-controller.service

В опорном скрипте созданной нами службы lio-config-controller используется утилита targetcli, которая позволяет нам управлять конфигурацией LIO. Из официальных репозиториев Debian Linux установим пакет targetcli-fb, позволяющий работать с LIO в Debian и содержащий соответствующую утилиту:

# apt-get install targetcli-fb

Так как загрузкой и выгрузкой конфигурации LIO у нас будет заниматься собственная служба, нам потребуется остановить и отключить автоматический запуск стандартной службы rtslib-fb-targetctl, устанавливаемой в систему из пакета targetcli-fb. Вся ранее настроенная конфигурация LIO при этом будет очищена.

# systemctl stop rtslib-fb-targetctl
# systemctl disable rtslib-fb-targetctl

После всех проделанных изменений можно перезагрузить конфигурацию служб systemd:

# systemctl daemon-reload

Теперь можно выполнить проверку того, как в автоматическом режиме отрабатывает созданная нами конфигурация при выключении и включении хостовой ОС Linux.

Базовая проверка и отладка

Перезагружаем сервер и после завершения загрузки ОС проверяем то, что созданная нами служба lio-config-controller успешно запущена:

# systemctl status lio-config-controller

Дополнительно можно проверить то, в какой последовательности отработал запуск служб systemd в процессе запуска ОС Linux. Для этого нам потребуется включить и настроить службу journald, как это описано в статье "Включение режима сохранения логов служб systemd через journald в Linux". После соответствующей настройки системы можно посмотреть логи интересующих нас служб, связанных с монтированием дисков, на предмет времени их запуска и остановки:

# journalctl --boot=-1 --unit=mnt-ramdisk1.mount
# journalctl --boot=-1 --unit=mnt-ramdisk1\x2dbackup.mount
# journalctl --boot=-1 --unit=lio-config-controller.service

Основные этапы работы скрипта, вызываемого службой lio-config-controller можем посмотреть в логе, который указан в самом начале скрипта:

# cat /var/log/script_lio-config-controller.log

Проверяем то, что LIO загружен именно в той конфигурации, что мы описали в скрипте

# targetcli ls

LIO Target configuration

Как видно из нашего примера, ранее обозначенная в скрипте конфигурация LIO успешно загружена и созданы цели FC Target.

После этого настраиваем зонирование на оптических коммутаторах SAN, чтобы на серверах на базе Windows Server стал доступен соответствующий FC Target.   

В нашем случае презентованный LUN доступен на обоих узлах кластера Windows Server по двум путям, обеспечивая тем самым повышенную доступность и производительность. Получившееся общее для двух Windows-систем дисковое устройство форматируем в NTFS и добавляем в кластер в качестве общего кластерного диска.

RAM-disk in Windows Server 2012 Cluster

Теперь настало время убедиться в том, что в случае возникновения необходимости отключения Linux-сервера, предоставляющего свою оперативную память, всё содержимое кластерного диска будет сохранено.

Проверка сохранения содержимого RAM-диска

Для проверки создаём на кластерном диске Windows Server какие-то файлы и запоминаем их содержание, то есть копируем туда какой-то осмысленный контент. После этого выводим в кластере диск в режим обслуживания или просто переводим в состояние Offline, чтобы избежать кластерных попыток активировать диск на соседнем узле кластера в тот момент, когда мы отключим для проверки Linux-сервер.

Take Offline cluster disk

После этого перейдём на Linux-сервер и вызовем выключение его ОС штатным способом. В ходе завершения работы ОС обращаем внимание на то, что таймаут остановки службы lio-config-controller используется именно тот, который мы указали в настройках юнита systemd - lio-config-controller.service:

systemd unit stop service timeout

После проверочного отключения снова включаем Linux-сервер и дожидаемся успешного запуска ОС, инициализации RAM-диска (с восстановлением данных из копии на SSD диске) и его последующей трансляции в конфигурацию LIO. После того, как всё "взлетело", можем снова проанализировать лог работы службы lio-config-controller и лог работы самого скрипта на предмет корректности этапов выключения/включения RAM-диска при выключении/включении ОС:

# journalctl --unit=lio-config-controller.service 
# cat /var/log/script_lio-config-controller.log

Все операции должны отрабатывать последовательно и без ошибок. И здесь лучше не жалеть времени на скрупулёзную проверку корректной и своевременной отработки каждого этапа. Только так можно рассчитывать на то, что данные с RAM-диска не будут в дальнейшем потеряны.

Когда все проверки на стороне Linux-сервера закончены, вернёмся в консоль управления кластером Failover Cluster Manager и убедимся в том, что кластерный RAM-диск работоспособен и успешно переводится в состояние Online. После успешного возобновления работы кластерного диска проверим его содержимое и убедимся в том, что на диске присутствуют скопированные нами ранее на этот диск файлы.

Проверка производительности RAM-диска

Сразу сделаем оговорку о том, что любые сравнительные тесты на проверку производительности всегда зависят от множества факторов. И в каждом отдельно взятом случае и отдельном рабочем окружении эти факторы могут иметь разную степень влияния на конечный результат. Поэтому в нашем конкретном случае никто не претендует на какую-то объективность. Мы лишь поделимся одним простым наблюдением.

На два рассматриваемых в нашем примере сервера с ОС Windows Server помимо RAM-диска через FC SAN (два линка FC 4G c MPIO) презентовано ещё несколько дисковых устройств, одно из которых представляет собой массив RAID10 из 12 SSD дисков Intel SATA 3G с СХД HP MSA P2000 G3. При тестировании такого дискового устройства на любом из узлов кластера получались примерно следующие пиковые показатели:

  • Запись ~499 MB/s или 3.9 Gbit/s
  • Чтение ~791 MB/s или 6.3 Gbit/s

ATTO Benchmark RAID10 12 SSD

При тестировании на этих же серверах нашего RAM-диска получались следующие пиковые показатели:

  • Запись ~687 MB/s или 5.5 Gbit/s
  • Чтение ~730 MB/s или 5.8 Gbit/s

ATTO Benchmark RAM-Disk from 4G FC SAN

Небольшое отклонение в показателях чтения в пользу СХД MSA можно попытаться объяснить опять же разными факторами, но не будем заострять на этом внимание. Внимание здесь стоит обратить на ощутимую разницу в показателях записи. При операциях с большими блоками, начиная с 512KB, на лицо выигрыш RAM-диска и по второму графику видно, что на каком-то уровне (возможно FC HBA на Linux-сервере, возможно на SAN …) просто срабатывает ограничение, и нельзя исключать того, что есть возможность улучшить полученные показатели чтения/записи. Кстати, обратите внимание также и на ощутимую разницу по показателям чтения/записи при работе с блоками 64K (рекомендуемый Microsoft размер блока при форматировании накопителей под файлы БД SQL Server).

Таким образом, привнесённый в кластер RAM-диск, в качестве места размещения файлов нагруженной системной базы данных tempdb кластеризованного экземпляра СУБД SQL Server, представляется вполне привлекательным решением.

Замечание о последовательности выключения и выключения серверов

Следует обратить внимание на то, что в случае возникновения нештатных ситуаций в ЦОД, например, в случае отключения электропитания, порядок автоматического отключения серверов должен быть настроен таким образом, чтобы физический Linux-сервер c RAM-диском выключался только после того, как завершат свою работу узлы кластера, которые используют этот RAM-диск в качестве кластерного ресурса.

Ну и, разумеется, обратного принципа следует придерживаться в процессе включения серверов. То есть Linux-сервер с RAM-диском должен запускаться, так же как и прочие СХД, раньше, чем стартуют серверы-узлы кластера Windows, использующие этот RAM-диск.

Заключение

Стоит отметить тот факт, что организацию RAM-диска описанным здесь методом можно выполнить не только на ОС Debian GNU/Linux 9, но и на других дистрибутивах Linux. А в качестве механизма трансляции RAM-диска в FC SAN можно использовать не только Linux-IO, но и такой замечательный инструмент, как SCST, пример использования которого мы уже рассматривали ранее.

Если же говорить о том, с чего мы начали, то, разумеется, можно поспорить о плюсах и минусах использования RAM-диска для системной базы данных tempdb СУБД SQL Server, равно как и об описанной здесь организации RAM-диска, как таковой. Здесь каждый для себя выводы делает сам исходя из своего практического опыта и степени "избалованности" Smile

Добавить комментарий