Данная статья призвана собрать воедино проверенные советы профессионалов как подготовить хранилище из множества дисков, собранное с помощью ZFS, под серьёзные нагрузки на запись в MySQL с движком InnoDB, к примеру под мощный поток данных системы мониторинга Zabbix.
ARC расположен в ОЗУ и ускоряет лишь операции чтения. Поэтому стоит вдумчиво отдать нужное количество памяти.
sudo -e /etc/modprobe.d/zfs.conf
options zfs zfs_arc_max=2147483648
Максимальное количество ОЗУ в байтах, отданное под ARC. В примере отдано 2 Гб.
options zfs zfs_arc_min=1073741824
Минимальное количество ОЗУ в байтах, отданное под ARC. В примере отдано 1 Гб.
options zfs zfs_async_block_max_blocks=5000
options zfs zfs_delete_blocks=1000
Данные параметры снижают "агрессивность" ZFS при операциях удаления, делая удаление больших объёмов асинхронными.
options zfs zfs_prefetch_disable=1
Поскольку движок InnoDB сам выполняет предварительную выборку, можно отключить собственную предварительную выборку ZFS (поскольку она избыточна в данном конкретном использовании). Разработчики указывают что если рабочая нагрузка в основном состоит из случайного чтения, а с базами данных ситуация именно такая, то zfs_prefetch_disable=1 может улучшить общую производительность.
При любых изменениях файла zfs.conf необходимо пересобрать образ initramfs - sudo update-initramfs -u
и перезагрузка сервера. После перезагрузки убедиться что параметр принял ваше значение можно командой типа cat /sys/module/zfs/parameters/zfs_prefetch_disable
Мониторить метрики используемости ARC можно через команду arcstat
Пример с одним диском
zpool create zfsmysql -o ashift=9 -O mountpoint=/mysqldbzfs -O recordsize=16k -O primarycache=metadata /dev/sdX
Пример RAID5 (в ZFS raidz)
zpool create zfsmysql -o ashift=9 -O mountpoint=/mysqldbzfs -O recordsize=16k -O primarycache=metadata raidz /dev/sdX /dev/sdY /dev/sdZ
ashift=9 Параметр ashift - это показатель степени, в которую нужно возвести число 2, чтобы получилось итоговое значение размера сектора.
Для примера,
ashift = 9 и размер сектора 2 ^ 9 = 512
ashift = 12, 2 ^ 12 = 4096
ashift = 13, 2 ^ 13 = 8192
Большинство современных дисков имеют аппаратные сектора размером 4 КБ, но данную информацию следует точно узнать из различных источников:
и указать, так как есть устройства, которые ложно сообщают о размере своих секторов! Самая сильная деградация производительности может быть получена, если ashift указан неверно и он меньше реального. Возникает ситуация когда при каждой записи "ложного сектора", для примера 512 байт, возникает необходимость считать реальный сектор в 4 КБ. Изменить его и записать обратно все 4 КБ. Итак при каждой операции записи.
recordsize=16k InnoDB использует страницы размером 16 КБ. Параметром recordsize указываем ZFS так же ограничить размер блока в 16 КБ, чтобы изменение страницы вынуждало прочесть и изменить равный ей блок у ZFS. Если оставить дефолтный размер блока ZFS в 128 КБ, то изменение в странице 16 КБ требовало бы чтения всего блока в 128 КБ.
primarycache=metadata Поскольку InnoDB уже выполняет собственное кэширование через пул буферов, нет никакой пользы дополнительно кэшировать данные в ОЗУ на стороне ZFS в Adaptive Replacement Cache (ARC). Поскольку O_DIRECT не отключает кэширование в ZFS, можно отключить кэширование всех данных в ARC, оставив только для метаданных (значение primarycache по умолчанию all).
zfs set atime=off compression=lz4 logbias=throughput sync=disabled zfsmysql
atime=off Отключаем Access Time. Что не так с atime? Atime вынуждает обновлять её при каждом доступе к файлу, а это означает, что inode файла нужно изменять на медленном дисковом устройстве. Другими словами, каждое чтение файла базы данных и операция превращается из чтения в запись файлов базы данных.
compression=lz4 Рекомендуется включить сжатие через алгоритм lz4. Это даст сокращение дискового ввода-вывода и приведёт к увеличению общей производительности. Алгоритмы умны и несжимаемые данные будут храниться как есть.
Мой пример из практики zfs get compressratio zfsmysql
NAME PROPERTY VALUE SOURCE zfsmysql compressratio 2.49x -
logbias=throughput В документации разработчиков ZFS сказано что смена значения logbias с latency (задержка) на throughput (пропускная способность) может улучшить производительность при записи файлов баз данных.
sync=disabled Если кратко, то параметр "заставляет врать" базе данных что якобы был сделан реальный sync() и данные действительно зафиксированы в хранилище. Другими словами, sync=disabled это если бы база данных никогда сама не просила делать sync для своих записей или у дисков включён кэш записи. Как вы понимаете это некоторый риск и нужен точно источник бесперебойного питания (ИБП), резервные копии базы данных и т.д. С другой стороны, по-прежнему записанные данные будут сбрасываться каждые 5 секунд. Но фиксация данных в хранилище (flush) один раз в 5 секунд вместо каждой транзакции даёт огромный прирост производительности, поскольку ZFS имеет возможность объединения или переупорядочивания операций записи.
Итоговые настройки можно посмотреть командой zfs get all zfsmysql
innodb_log_write_ahead_size=16384
InnoDB по умолчанию имеет размер страницы 16 КБ для табличных пространств, 8 КБ для журнала транзакций, а двоичные журналы не имеют фиксированного размера страницы. Есть масса советов как средствами ZFS отделить журналы MySQL от собственно файлов базы данных с различными настройками, но для упрощения сопровождения в данной статье подразумевается что журналы и данные хранятся в одном месте. Это поведение MySQL по умолчанию. Так как мы ранее выставляли 16 КБ размер блока данных в ZFS ради InnoDB, то журналам нужно указать использовать так же 16 КБ размер блока данных.
innodb_flush_method=fsync
ZFS не поддерживает O_DIRECT, но он игнорируется с сообщением в журнале ошибок, что заполняет его и засоряет не нужным выводом. Лучше выставить flush метод значение fsync, которое будет молчаливо игнорироваться из-за параметра sync=disabled у ZFS.
innodb_doublewrite=0
Двойная запись используется InnoDB для предотвращения повреждения данных частично записанными страницами при сбоях приложения. Так как ZFS по природе своей транзакционна, то блок данных или записывается целиком или теряется. Невозможна частичная запись страницы, поэтому можно выключить двойную запись.
innodb_checksum_algorithm=none
InnoDB подсчитывает контрольную сумму каждой страницы для обнаружения повреждения данных. ZFS делает тоже самое для каждого блока. Чтобы убрать избыточность, можно отключить для небольшой экономии тактов процессора.
innodb_flush_neighbors=0
Когда приходит время сбросить страницу на диск, InnoDB также сбрасывает все близлежащие страницы. Это выгодно для классических жёстких дисков и традиционных файловых систем, но для ZFS, где логически соседние блоки не обязательно являются физически соседними блоками, это обычно просто приводит к потере дискового ввода-вывода. Лучше отключить данный параметр InnoDB при размещении файлов базы данных на ZFS.
innodb_use_native_aio=0
В Linux реализация AIO драйвера для ZFS является слоем совместимости.
innodb_read_io_threads=10
innodb_write_io_threads=10
Увеличиваем количество потоков ввода-вывода.
innodb_flush_log_at_trx_commit=0
sync_binlog=0
Эти параметры InnoDB делают абсолютно тоже что и sync=disabled на стороне ZFS. Игнорируется синхронизация (sync) при каждом сбросе данных (flush) в следствии выполнения транзакций, изменяющие данные. Чудес не бывает и выставляя значение в 0 вместо 1, мы отказываемся от большей надёжности в пользу быстродействия.
disable_log_bin
С версии MySQL 8.0 по умолчанию включено ведение бинарных журналов, которые служат двум целям: в процессе репликации slave следует за master, проматывая и воспроизведя события изменения данных с помощью бинарного журнала ИЛИ в определённых ситуациях кто-то захочет восстановить базу на определённую дату, что в документации проекта называется Point-in-Time (Incremental) Recovery Using the Binary Log. Мощный поток INSERT в базу Zabbix генерирует не менее мощную запись в файлы бинарного лога. Нужно или отключать их или выносить на отдельное быстрое хранилище, если вы используете кластер серверов MySQL и вам нужна репликация через бинарный журнал.
Данный кэш располагается на высокопроизводительных дисковых устройствах, чаще всего на SATA или NVMe накопителях типа SSD. SSD диски медленнее ОЗУ, но всё же намного быстрее, чем жёсткие диски (HDD), которые используются для фактического хранения данных. Стоит помнить что ни ARC, ни L2ARC никак не влияют на производительность операций записи.
L2ARC "не бесплатен"! Его обслуживание требует ОЗУ, которое лучше отдать под ARC. Есть различные варианты использования Zabbix и, возможно, в какой-нибудь из вселенной L2ARC кому-то да и пригодится.
sudo zpool add zfsmysql cache /dev/sdX
В статье многое написано под углом получения максимального быстродействия для данных системы мониторинга Zabbix. Если вы готовите ZFS для важных данных, то вам не следует жертвовать надёжностью хранения и ослаблять требования ACID.
Для надёжности оставляйте в InnoDB
innodb_flush_log_at_trx_commit=1
sync_binlog=1
а в ZFS не используйте sync=disabled
Не забудьте сменить владельца на каталог с базой данных sudo chown -R mysql:mysql /mysqldbzfs/
Можно для MySQL в его настройках указать новое расположение файлов базы данных в переменной datadir или просто сделайте символическую ссылку ln -s /mysqldbzfs/mysql /var/lib/mysql
Для мониторинга загрузки ваших дисков под мощными операциями записи используйте zpool iostat -vly 2
Дополнительные материалы:
Дата последней правки: 2024-07-04 15:10:58