Изучая разные методы повышения производительности работы СУБД SQL Server, добрался до такой интересной темы, как использование RAM-диска для размещения файлов нагруженной системной базы данных tempdb. Выяснил для себя то, что из работоспособных свободно-распространяемых инструментов для организации RAM-диска под ОС Windows Server на текущий момент многие выделяют утилиту imDisk Toolkit. Однако этот инструмент, как и прочие его аналоги, не получится использовать в кластерных конфигурациях SQL Server, где использование ресурсов оперативной памяти (далее ОЗУ) в любой момент времени может быть переключено с одного кластерного узла на другой. То есть, если и использовать в кластере RAM-диск, то он должен быть одинаково доступен всем узлам кластера, как и любой другой кластерный диск, участвующий в конфигурации кластеризованного экземпляра SQL Server.
Напрашивающимся в таком случае решением может стать использование в качестве RAM-диска ОЗУ не самих узлов кластера, а ОЗУ стороннего хоста, подключенного к узлам кластера в качестве дискового устройства через транспорт Fiber Channel SAN (как отличающийся приемлемыми показателями задержки). То есть на выделенном хосте используются локальные ресурсы ОЗУ для создания RAM-диска, после чего RAM-диск транслируется на узлы кластера через FC SAN, как блочное устройство, и может использоваться в качестве кластерного диска.
Далее я опишу пример создания такого 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
В конец системного конфигурационного файла /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
При описании директивы создания 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
Как видим, в нашем случае юниты имеют имена "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 успешно загружена и созданы цели FC Target.
После этого настраиваем зонирование на оптических коммутаторах SAN, чтобы на серверах на базе Windows Server стал доступен соответствующий FC Target.
В нашем случае презентованный LUN доступен на обоих узлах кластера Windows Server по двум путям, обеспечивая тем самым повышенную доступность и производительность. Получившееся общее для двух Windows-систем дисковое устройство форматируем в NTFS и добавляем в кластер в качестве общего кластерного диска.
Теперь настало время убедиться в том, что в случае возникновения необходимости отключения Linux-сервера, предоставляющего свою оперативную память, всё содержимое кластерного диска будет сохранено.
Проверка сохранения содержимого RAM-диска
Для проверки создаём на кластерном диске Windows Server какие-то файлы и запоминаем их содержание, то есть копируем туда какой-то осмысленный контент. После этого выводим в кластере диск в режим обслуживания или просто переводим в состояние Offline, чтобы избежать кластерных попыток активировать диск на соседнем узле кластера в тот момент, когда мы отключим для проверки Linux-сервер.
После этого перейдём на Linux-сервер и вызовем выключение его ОС штатным способом. В ходе завершения работы ОС обращаем внимание на то, что таймаут остановки службы lio-config-controller используется именно тот, который мы указали в настройках юнита systemd - lio-config-controller.service:
После проверочного отключения снова включаем 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
При тестировании на этих же серверах нашего RAM-диска получались следующие пиковые показатели:
- Запись ~687 MB/s или 5.5 Gbit/s
- Чтение ~730 MB/s или 5.8 Gbit/s
Небольшое отклонение в показателях чтения в пользу СХД 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-диска, как таковой. Здесь каждый для себя выводы делает сам исходя из своего практического опыта и степени "избалованности"
Обратная ссылка: Ошибка targetcli "WWN not valid as: naa" при попытке добавления в ACL конфигурации Linux-IO FC Target хостов FC Initiator с WWPN от виртуальных машин Hyper-V Gen2 – Блог IT-KB /
Подскажите , а что должно быть на инициаторе после того как создал таргет и объявил lun в разделе qla2xxx
, как подключить bloсk через данный lun (если что простите за глупый вопрос)