Pull to refresh

A look at MySQL on ZFS

Reading time 11 min
Views 6.7K
Original author: John David Duncan
image

Представляю вниманию общественности перевод достаточно большой статьи об использовании MySQL на ZFS, а так же сравнительное тестирование ZFS и UFS.


Заранее прошу прощения за, вероятно, не самое высокое качество перевода — английский язык никогда не изучал. С благодарность приму поправки.

О ZFS



Когда Sun Microsystems выпустила в 2004 году файловую систему ZFS, она взялась снять все практические ограничения файловых хранилищ и сделать таинство управления файловым хранилищем делом прошлого. ZFS это 128-битная файловая система с — назовем лишь некоторые свойства – транзакционной семантикой «копирование при записи», быстрыми снимками и опциональной компрессией.

Наиболее значительный выигрыш от использования ZFS это простота администрирования. В ZFS традиционные задачи, такие как форматирование диска или редактирование /etc/fstab полностью упраздняются, а построение зеркал или RAID-массивов могут быть выполнены с помошью осмысленных команд, которые легко запоминаются и имеют интерактивную подсказку. ZFS для управления хранилищами выполняет то, что MySQL выполняет для баз данных, в добавок так же как MySQL она имеет открытый код. ZFS изначально выпущена под Solaris, но порт под Linux в процессе, Aplpe ставит ее в OS X 10.5, и она включена во FreeBSD 7. Подробнее на странице the ZFS Community page at opensolaris.org

Администрирование ZFS больше всего полагается на две команды: zpool, для управления пулами хранения и zfs, для файловых систем. Пул хранения – ключевая абстракция: пул может состоять из нескольких физических устройств, и может вмещать несколько файловых систем. Всякий раз, когда вы добавляете хранилище в пул, оно становится доступным для любой файловой системы, которая нуждается в нем. Для того чтобы подключенный диск целиком использовать как ZFS-хранилище, вы можете выполнить команду:

# zpool create zp1 c2t0d0

Здесь zp1 представляет собой имя пула, а c2t0d0 дисковое устройство. Если именование устройств в стиле Solaris выглядит незнакомым, учтите что на Linux и других OS нужно использовать их родное наименование.

Если ваш диск уже отформатирован, например с UFS на одной партиции – вы можете создать пул на другой свободной.

# zpool create zp1 c2t0d0s2

Так же вы можете использовать файл, как хранилище:

# zpool create zp1 ~/storage/myzfile

Если вы уже имеете пул, вы можете построить файловую систему на нем:

# zfs create zp1/data
# zfs create zp1/logs

Не думайте, что вам придется ожидать создания файловой системы после запуска этой команды, он выполняется мгновенно. В дальнейшем, если наступит нехватка свободного места, просто добавьте устройство к пулу и файловые системы увеличатся.

# zpool add zp1 c3t0d0

ZFS and табличное пространство



Чтобы оценить, что эта мощь означает для MySQL, рассмотрим проблему управления хранилищем под InnoDB

innodb_data_file_path = /disk1/ibdata1:10G;/disk2/ibdata2:10G;/disk3/ibdata3:10G:autoextend

В этом примере пространство InnoDB распределено на три физических диска, возможно из за того, что каждый диск имеет только 10 GB, или возможно это попытка разнести нагрузку. Третий диск помечен как autoextend, значит он может быть увеличен при необходимости.

К сожалению, попытка балансировать нагрузку на трех дисках на практике не работает. InnoDB должен заполнить первый диск, прежде чем начать использовать следующий и заполнить второй прежде чем начать третий. Другая проблема состоит в невозможности он-лайн расширения табличного пространства. Если вы столкнулись с нехваткой дискового пространства на диске №3 и добавили файл с другого диска, вы должны рестартовать сервер, чтобы изменения вступили в силу. (Вы так же будете вынуждены выполнить некоторые хитрые действа с autoextend в этом примере, но эти детали выходят за рамки данной дискуссии).

Ситуацию можно исправить, если полностью вынести управление хранилищем из сферы влияния базы данных. Для этого достаточно в innodb_data_file_path использовать ZFS.

innodb_data_file_path = /dbzpool/data/ibdatafile:10G:autoextend

Вы можете разбить это хранилище на столько угодно устройств, и ZFS будет разумно балансировать нагрузку. Вы можете объединять устройства, зеркалировать их, добавлять пространство когда нужно его увеличить, добавлять на лету резервные диски, и исключать битые диски без рестарта базы данных. Вы можете позволить базе данных быть базой данных, и –для вас от mysql — мы можем сконцентрироваться на том, что сохранить базу данных простой, недорогой и легкой в использовании.

В движке MySQL Falcon табличное пространство может быть создано и удалено он-лайн, но оно может содержать только один файл данных. В будущих версиях обещают поддержку множественных файлов данных, но пользователи ZFS не нуждаются в этой функии.

Файловые системы, буферизация и предчтение



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

Следующее — предчтение (read-ahead): если приложение запрашивает большой блок файла, файловая система должна прочитать еще больший блок, в предчувствии, что приложение продолжит чтение дальше.

Сервер базы данных, в этом отношении, не является типичным предложением. Хотя, база данных, MyISAM, которая для кеширования записей полагается на буфер файловой системы, следовательно не подвержена проблеме описываемой в этой секции, многие другие используют собственный слой буферизации. Производительность базы данных всесторонне зависит от эффективности использования этого кеша: каждый раз, когда происходит промах мимо кеша, и происходит чтение с физического диска, эффективность уменьшается.

Проблема возникает когда данные закешированы в памяти дважды – на сервере базы данных, и второй раз в файловой системе. Хранение двух копий данных уменьшает эффективность использования памяти в два раза. Когда память заполнена, она содержит только половину данных из возможных, таким образом уменьшает количество попаданий в кеш, увеличивается количество чтений и уменьшается эффективность. Вот что мы называем проблемой двойного буфера (double buffer problem).

Следующая оптимизация — предчтение — так же может быть вредной для сервера баз данных. Чтения производимые базой данных не укладываются в предсказуемый шаблон, следовательно, файловая система читает данные которые никогда не будут использованы. Roch Bourbonnais, инженер и блоггер из компании Sun, исследовал это — когда традиционная файловая система UFS «видит доступ к 2 последовательным страницам, она читает полный кластер, который сегодня обычно имеет размер 1MB». Время, которое головка диска тратит на чтение ненужных данных, нужно тратить несколько более продуктивно.

Многие пользователи MySQL, особенно на Solaris, отвечают, что эти две проблемы решаются простым отключением настроек. Доступ к фаловой системе без буфферинга и предчтения известен Direct I/O, и он может быть разрешен в my.cnf установкой innodb_flush_method в O_DIRECT:

innodb_flush_method = O_DIRECT

До выхода MySQL 5.0.42 и 5.1.18, в апреле 2007 для этого было необходимо в Solaris монтировать разделы содержащие файлы данных с опцией forcedirectio. К счастью сейчас это не так, и InnoDB может использовать прямой доступ не принуждая все приложения использовать прямой доступ ко всему разделу.

ZFS и I/O планировщик



Когда InnoDB используется на ZFS, проблема двойного буфера несомненно возникает, и ее эффект легко увидеть на тестах ниже. Что касается предчтения, хотя ранние релизы ZFS страдали от предчтения, но текущие(с OpenSolaris Nevada build 70 и позже) избавлены от этого. Другой инженер SUN и блоггер, Neelakanth Nadgir, проделал некоторые тесты ZFS с базами данных в 2006 году, и сообщил, что бывшие проблемы с производительностью были исправлены в новых сборках.

ZFS привносит третье интересное усовершенствование эффективности в I/O планировщик. ZFS планировщик работает согласно следующему плану:

• Когда запрос ввода-вывода поступает в ядро, он помещается в очередь и ему присваиваются приоритет и дедлайн (выше приоритет – скорее дедлайн)
• Запросы чтения имеют больший приоритет, чем запросы на запись. Потому что запросы на чтение в действительности синхронные (приложение заблокировано, ожидает ответа). Запрос на чтение попадает в начала очереди.
• Планировщик просматривает все ожидающие запросы и принимает решение который будет выполняться следующим. Он делает это объединив самые срочные запросы в «дедлайн группу» и разносит их на диск в порядке Logical Block Address.

Еще один блоггер из SUN, имеет по крайне мере один тест, в котором ZFS I/O планироващик
(прим.пер. тут мой мозг сломался)
To bring in yet another Sun blogger, there is at least one benchmark where the ZFS I/O scheduler has been shown to make a big difference in performance.

Развертывание MySQL на ZFS: Детали



Связка ZFS и MySQL выглядит как подающая надежды комбинация, но как они сочетаются друг с другом? Достаточно часто, сервер базы данных и файловая система должны решать одинаковый набор проблем, и каждый предлагает решение. Два решения могут хорошо сочетаться друг с другом, или неудачно перекрывать друг друга. Ниже несколько важных моментов.

Установите ZFS Recordsize равным размеру блока



ZFS пытается эвристически определить размер блока для каждого файла основываясь на размере файла и типе его использования. Небольшие файлы управляются крохотными кусочками, а огромные файлы большими кусками. Разработчики ZFS знают, что такая схема должна быть оптимальной в общем случае, но это может быть совершенно не подходящим для баз данных, и поэтому они разрешили пользователю устанавливать фиксированый размер записи когда файловая система используется базой данных. Некоторые рассуждения позже в этой статье верны только если размер страницы базы данных равен размеру записи ZFS.

InnoDB работает с файлом данных страницами по 16KB, пока вы не перекомпилируете его с другим размером страницы. Falcon использует по умолчанию страницы размером 4KB, но допускает установку а my.cnf. В обоих случаях важно установить ZFS recordsize равным размеру страницы. Это нужно сделать прежде чем будут созданы какие либо файлы в разделе, команда должна выглядеть похоже на это:

# zfs set recordsize=16K zp1/data

Буфер двойной записи InnoDB и транзакционное хранилище



Некоторые транзакционные системы (не InnoDB) записывают целиком страницы данных в лог транзакций. InnoDB однако логирует только номер страницы и измененную запись, так как это критический момент, когда пользователь ждет завершения транзакции, InnoDB посылает меньше данных на диск и это позволяет улучшить производительность.

Если те, другие, базы данных рушатся, затем рестартуют и выполняют восстановление используя лог, они могут вытягивать целые страницы данных из лога и записывать их в файл данных.

С InnoDB восстановление не настолько простое. Только малая часть информации логируется, следовательно страница данных должна быть корректной на диске. И InnoDB пытается гарантировать это используя специальную область файла данных, называемую буфер двойной записи(doublewrite buffer), который содержит вторую копию последних записанных страниц. После крушения имеются две копии изменяющихся данных – одна в нормальном файле, вторая в буфере двойной записи, по крайне мере одна из этих копий должна быть неповрежденной. Буфер двойной записи не нужен на ZFS, и отключив его, можно получить небольшой прирост эффективности.

От чего прежде всего защищает буфер двойной записи при частичной записи: В случае, когда база данных послала 16KB страницу на диск, но только 4KB или 8KB реально было записано до пропадания электроэнергии. В нашем случае транзакционность приходит не от базы данных, а от файловой системы: ZFS гарантирует, что частичная запись данных никогда не случится.

Чтобы составить полное представление о частичной записи, представьте себе отдельный блок диска, например блок 82, который перезаписывался в традицонной юниксовой файловой системе в момент, когда питание прервалось. Когда система перегрузилась, начало блока 82 содержит в себе частично записанные новые данные, следующий кусок содержит мусор, и концовка блока содержит старые данные, которые никогда не будут перезаписаны. Если случилось так, что блок содержит страницу InnoDB, то в конце страницы содержится контрольная сумма, которая при проверке укажет на сбой в содержимом страницы.

В ZFS, до пропадания питания, когда база данных перезаписывает блок 82, происходит нечто совершенно отличное. Блок 82 никогда не будет перезаписываться фактически, вместо этого новый блок целиком будет записан где-нибудь в другом месте. Соответственно, если питание пропадет в процессе записи, блок 82 останется нетронутым. Если с питанием будет все нормально, то данных сохранятся где-то в другом месте и новый блок будет включен в файл(во всяком случае в текущую версию файла) вместо старого.(тут может быть снимок предыдущей версии файла, в таком случае в файле останется старый блок. Народ близкий к базам данных может вспомнить конкурентный доступ с помощью многоверсионности, но на уровне файловой системы, и это свойство существует много лет в FreeBSD, NetApp и Veritas filesystems).

Сравнение производительности MySQL ZFS vs. UFS на Open Solaris



Я провел два отдельных теста для сравнения UFS и ZFS на Solaris. Машина используемая для тестов x86 desktop, 2 GB RAM, под OpenSolaris Nevada build 74 и MySQL 5.0.50. Первый тест это однопоточная «утилита» предназначена отобразить общие операции, такие как массовая вставка и «ALTER TABLE». Этот тест не показал заметных различий между двумя файловыми системами, хотя некоторые индивидуальные операции на 5% медленнее на ZFS чем на UFS.

Следующий тест оказался более интересным. Этот тест включал 6 клиентских потоков обращающихся к базе данных размером 3.2GB, по шаблону 85% запросов SELECT, разделенных запросами INSERT и UPDATE. База данных размером 3.2 GB слишком велика чтобы разместиться в памяти, т.е. тест показывает ограничения ввода вывода, так же тест симулирует поведение большинства реальных приложений: отдельный набор записей (около 5% от всех) выбираются значительно чаще остальных.

Этот тест особенно чувствителен к поведению кеша, каждый тест включал в себя некоторое время прогрева для заполнения кеша, и тесты не могут легитимно сравниваться если время прогрева разное. Для сброса времени прогрева в нуль иногда нужно перемонтировать файловую систему, при этом буферы кеша сбрасываются.

ZFS vs. UFS после 5 минут прогрева. Более высокие цифры означают более высокую производительность. База данных 3.2 GB на сервер с 2 GB RAM.
InnoDB Buffer Pool Size UFS Direct I/O ZFS
100 MB 36.84 96.21
250 MB 45.70 80.69
350 MB 50.68 102.75
500 MB 57.32 94.99
700 MB 61.92 85.95
1000 MB 82.41 98.35
1200 MB 95.01 88.98
1400 MB 101.32 117.83


Тест с пятиминутным прогревом показывает, что производительность баз данных на UFS неуклонно растет с увеличением размера буфера. На ZFS результаты неустойчивые и не линейные. Если время прогрева увеличить до 10 минут, картина вырисовывается более четкая.

ZFS vs. UFS после 10 минут прогрева.

InnoDB Buffer Pool Size UFS Direct I/O ZFS
100 MB 35.71 179.18
250 MB 44.25 154.26
350 MB 50.60 110.14
500 MB 57.10 93.29
700 MB 66.57 101.35
1000 MB 103.47 114.18
1200 MB 168.66 156.04
1400 MB 325.05 290.14


image

Снова производительность на UFS неуклонно растет с увеличением размера буфера, и очень сильно к самому концу. Последние два точки на 1200 и 1400 MB означают 60 и 70% машинной памяти, этого достаточно для хранения половины данных.

Когда размер буфера небольшой, ZFS в значительной степени лучше UFS. Кеш ZFS очень эффективен. ZFS на буфере 100MB эффективнее чем UFS даже на 1200MB. Но если размер пула увеличивается, производительность ZFS падает

Такое поведение вызвано двойной буферизацией. Поскольку некоторые данные находятся в обоих кешах, меньше данных помещаются в памяти, и чаще необходим доступ к физическому диску. Этот эффект оказывает наихуждее влияние когда размер буфера установлен в 500 MB.

После 500MB, две файловые системы начинают действовать более похожими путями. Сервер баз данных нуждается в большей части физической памяти, оставляя очень мало для ZFS, в результате минимизируется внос ZFS в производительность и уменьшается проблема двойного буфферинга.

Заключение



ZFS позволяет очень простое и гибкое администрирование, без каких-либо реальных потерь в производительности. В худшем случае в этих тестах ZFS работает почти так же как UFS с Direct I/O. В случае с InnoDB график производительности подсказывает использовать новую стратегию «установите inndb буфер меньше и позвольте ZFS управлять буферизацией.» Я не тестировал Falcon посколько он еще не был в бета-версии, когда я запускал тесты, аналогично для Falcon на ZFS можно сосредоточиться на кеше строк и уменьшении кеша страниц. И хотя проблема двойной буферизации ясно видна на графике производительности ZFS, даже с этой проблемой в худшем случае ZFS отсатеся производительнее чем UFS.

(прим. Пер. На последнем абзаце я сломал мозг)

The real reason for the good performance on this benchmark is not clear — indeed, every workload will be different — but the ZFS I/O scheduler, the Sun engineers paying attention to database performance, and the ZFS bug fixes contributed in recent (late 2007) releases of Open Solaris seem to be adding up to something good.

ps: Еще раз приношу извинения за качество, текст объемный и вылизывать его нет возможности и без того уже потратил на это непозволительное количество времени. Перевод делался не столько для публикации сколько для более полного проникновения в тему. Сам я вроде проникся, надеюсь пригодится еще кому-нибудь. В ближайшем будущем я планирую провести свои тесты, если сообществу интересно, то опубликую их.
Tags:
Hubs:
+39
Comments 29
Comments Comments 29

Articles