Мы собрали форк MySQL от Facebook с движком RocksDB вместо InnoDB и потестировали его с реальными приложениями: Drupal, Wordpress, Redmine.
Это офигенная штука. При низкой нагрузке выигрыш маленький, десятки процентов. Зато при высокой нагрузке выигрыш в разы. Когда RocksDB добавят в стабильный релиз в MariaDB, я уверен, что в течение полугода половина народа перейдет с InnoDB на RocksDB. Особенно, небольшие сайты на cloud/VPS и выделенных серверах.
Что такого хорошего в MyRocks? Линейная запись вместо случайной и снижение числа дисковых операций вообще. То есть транзакции базы данных порождают меньше дисковых операций, меньше занимают очередь диска, и пишутся намного быстрее.
Я собрал в статью результаты тестирования реальных сценариев Redmine, добавил анализ результатов и выводы. Redmine на MySQL с RocksDB оказался быстрее, чем с InnoDB — от 20% при минимальной нагрузке до 3 раз при максимальной. Позже подготовлю материалы по Drupal и другим PHP-приложениям.
Вы сможете проверить работу MyRocks и самостоятельно — в конце статьи есть ссылки на инсталляторы и виртуальные машины с LAMP/LEMP/Ruby стеками, собранные с MyRocks вместо MySQL.
Введение
Facebook на базе своего хранилища RocksDB создал storage engine для MySQL — MyRocks. Работающая реализация MyRocks в виде MySQL 5.6 с патчами от Facebook передана в open source и размещается на GitHub — http://ift.tt/1amdJDp. MyRocks является альтернативой InnoDB и дает несколько преимуществ:
- Снижение объема записи
- Лучшая компрессия
- Уменьшения случайных чтений
Все это в сумме существенно повышает скорость транзакций на HDD и уменьшают изнашиваемость SSD, а также ускоряют репликацию.
MariaDB и Percona уже ведут работы по интеграции MyRocks в свои форки MySQL: Facebook MyRocks at MariaDB, Announcing MyRocks in Percona Server for MySQL. MariaDB объявила, что MyRocks будет доступен в release candidate 10.2 этой зимой. На Jetware в число альтернатив MySQL добавлена оригинальная реализация MyRocks от Facebook на базе MySQL 5.6.
Тестирование производительности на синтетических тестах показывает впечатляющие результаты. В зависимости от типа устройства хранения, выигрыш по скорости составляет от 20% до 10x. Результаты тестирования LinkBench можно посмотреть в публикации Yoshinori Matsunobu MyRocks: A space- and write-optimized MySQL database и в блоге Mark Callaghan, например, MyRocks: use less IO on writes to have more IO for reads. Эти тесты во многом ориентируются на большие объемы баз данных (десятки и сотни гигабайт) и мощные машины.
В дополнение к синтетическим тестам и тестам на больших объемах данных, мы решили протестировать и оценить выигрыш в производительности для типовых веб-приложений и сайтов небольшого размера.
Первым мы тестируем Redmine. Мы знаем как он устроен, активно используем его в разработке и поэтому тестирование имеет для нас также практическую ценность — если результат окажется хорошим, мы переходим на MyRocks.
Условия тестирования
Программное обеспечения
Мы используем Redmine 3.3.1 с Ruby 2.3.1, в конфигурации по умолчанию, без дополнительных плагинов.
В качестве серверов баз данных используем:
- MyRocks MySQL 5.6.27.75 из репозитория Facebook, коммит bc17d30 (show variables)
- MySQL 5.6.31 (show variables)
- MariaDB 10.1.16 (show variables)
Все бинарники собраны одним компилятором GCC 4.9.3, с рекомендуемыми параметрами сборки и оптимизации.
Операционная система — Ubuntu 14.04 x86_64, Linux kernel 3.13.0. Файловая система — ext4.
Наборы данных
Перед выполнением тестов база данных наполняется сгенерированными заранее проектами, пользователями и задачами. Таких вариантов тоже три:
- Малый набор
- 30 пользователей
- 3 проекта и 10 подпроектов второго уровня, в каждом проекте по 10 пользователей
- 1000 задач с 10 комментариями каждая
- Большой набор
- 1000 пользователей
- 10 проектов первого, 100 подпроектов второго и 10 подпроектов третьего уровня, в каждом проекте по 10 пользователей
- 10000 задач с 10 комментариями каждая
- Гигантский набор
- 10000 пользователей
- 100 проектов первого, 1000 подпроектов второго и 100 подпроектов третьего уровня, в каждом проекте по 10 пользователей
- 100000 задач с 10 комментариями каждая
Большинство реальных случаев использования Redmine приходятся на размеры между Малым и Большим. Объемы уровня Гигантского бывают значительно реже.
Объем занятого пространства
Столбцы показывают объемы занятого пространства для разных баз данных и разных наборов данных (меньше — лучше)
Оборудование
- Процессор: 4-core Xeon E31220 3.10GHz
- Память: 16 Gb RAM, DDR3 1333
- HDD: RAID mirror, 2 x Western Digital RE4 1 Tb
Виртуальная машина
Мы имитируем работу Redmine в условиях, близких работе у облачного провайдера или на офисном сервере. Для этого мы выделяем не весь физический сервер, а размещаем его в виртуальной машине с гораздо меньшим количеством ресурсов и имитируем различную нагрузку на дисковую систему со стороны соседей. В качестве платформы виртуализации используется Xen 4.6, в dom0 — Linux kernel 3.16.7. Устройство хранения разбивается с помощью LVM, обычное linear, без thin provision и снэпшотов. Том размещается посередине HDD.
Использовались три конфигурации виртуальных машин:
- 1 Gb RAM, 4 CPU, HDD 16 Gb
- 2 Gb RAM, 4 CPU, HDD 16 Gb
- 8 Gb RAM, 4 CPU, HDD 16 Gb
Тестируемые операции
Мы проверяем скорость работы наиболее часто используемых в Redmine операций — создание задач, добавление комментариев к задачам, изменение статуса и ответственного лица задачи. Из этих операций мы создали два теста, два рабочих цикла задачи:
-
Создание задачи
Создание задачи в проекте одним участником проекта, назначение ее на другого участника проекта и добавление в нее 10 комментариев от лица других участников проекта.
-
Обработка 10 задач
Получение пользователем 10 назначенных на него задач, переведение их всех в In Progress, и затем поочередное переведение задачи в Resolved и назначение ее на создателя задачи.
Тесты проводятся на 1, 2 и 4 параллельных процессах Redmine.
Сторонняя нагрузка на диск
Нагрузка создается с помощью утилиты fio
, которая читает и пишет 50/50 случайные блоки в оставшуюся часть диска. Мы имитировали несколько уровней нагрузки на диск, которые характерны для типовых случаев работы виртуальных машин — у провайдеров публичных облаков и VPS, или при запуске на собственном сервере нескольких виртуальных машин под VMWare, Hyper-V, KVM или XenServer.
Для имитации неполной загрузки мы запускаем fio с ограничением IOPS с помощью ключа --rate_iops
и замеряем утилизацию диска. При 100% однопоточной нагрузке это около 80 IOPS. Утилизация 25% создается нагрузкой 14 IOPS. Большая нагрузка имитируется увеличением числа потоков ключем --iodepth
.
В зависимости от количества соседних виртуальных машин, характера их работы и пиков нагрузки, загруженность диска может серьезно отличаться как у облачных провайдеров и VPS, так и на собственном сервере. Поэтому мы проводили тестирование при отсутствии сторонней нагрузки, при незначительной однопоточной нагрузке (14 IOPS, 25%), так и при и полных сторонних нагрузках в 1, 2 и 4 потока.
Измеряемые значения
Мы измеряем полное время выполнения каждой операции Redmine на большом числе операций и сравниваем среднее время выполнения. Первые 10% результатов игнорируются — на них мы разогреваем систему. Последние 10% результатов игнорируются для того, чтобы исключить хвостовое искажение из-за разного времени завершения параллельных процессов.
Измерения проводятся в разных комбинациях условий:
- для разных конфигураций виртуальных машин и разных наборов данных
- для разного числа параллельных процессов Redmine (основная нагрузка) и разных сторонних нагрузок на диск
Время выполнения замеряется для всех трех баз — MyRocks MySQL, MySQL и MariaDB. Мы также вычисляем разницу в скорости MyRocks MySQL по отношению к MySQL и MariaDB. Собранные данные представлены в виде графиков.
Результаты тестирования
Малый набор данных и малая виртуальная машина
- Виртуальная машина: 1 Gb RAM, 4 CPU, HDD 16 Gb
- Набор данных: 30 пользователей, 13 проектов и подпроектов, 1000 задач
Графики времени выполнения операций
1) создание задачи; 2) обработка 10 задач
Столбцы показывают время выполнения операции (меньше — лучше). Линии показывают во сколько раз сервер MySQL или MariaDB был медленнее сервера MyRocks MySQL.
Минимальная нагрузка — один процесс Redmine и отсутствует сторонняя нагрузка. Максимальная нагрузка — 4 процесса Redmine и 4 полных потока сторонней нагрузки на диск.
Мы видим, что время создания задачи для MyRocks при увеличении нагрузки до максимума меняется незначительно, и возрастает от 0.018 сек до 0.023 сек, на 23%. Для MySQL и MariaDB минимальное время создания задачи составляет 0.022 сек и возрастает в десять раз до 0.23 сек при максимальной нагрузке. При минимальной нагрузке MySQL и MariaDB оказываются медленнее на 24%, чем MyRocks; при максимальной нагрузке они оказываются медленнее в 9.5 раз.
Время обработки задач для MyRocks вырастает от 0.245 сек при минимальной нагрузке до 0.327 сек при максимальной, на 33%. Для MySQL и MariaDB минимальное время обработки задач возрастает примерно в 7 раз — с 0.283 сек при минимальной нагрузке до 2.245 сек при максимальной.
Объема оперативной памяти не хватает для эффективного кэширования чтения, и это очень сказывается на скорости InnoDB.
Большой набор данных и средняя виртуальная машина
- Виртуальная машина: 2 Gb RAM, 4 CPU, HDD 16 Gb
- Набор данных: 1000 пользователей, 120 проектов и подпроектов, 10000 задач
Графики времени выполнения операций
1) создание задачи; 2) обработка 10 задач
Столбцы показывают время выполнения операции (меньше — лучше). Линии показывают во сколько раз сервер MySQL или MariaDB был медленнее сервера MyRocks MySQL.
Минимальная нагрузка — один процесс Redmine и отсутствует сторонняя нагрузка. Максимальная нагрузка — 4 процесса Redmine и 4 полных потока сторонней нагрузки на диск.
В данной конфигурации ресурсы виртуальной машины лучше соответствуют объему данных и нагрузке. Для MyRocks время создания задачи остается прежним — от 0.018 сек до 0.023 сек, вырастая на 23%. Для MySQL и MariaDB минимальное время становится чуть больше — 0.023 сек и вырастает только в два раза — до 0.056 сек при максимальной нагрузке. Они оказываются медленнее, чем MyRocks, на 30% при минимальной нагрузке, и в 2.3 раза при максимальной.
Для обработки задач ситуация похожая. Время выполнения у MyRocks при увеличении нагрузки слабо растет от 0.248 сек до 0.331 сек. Для MySQL и MariaDB минимальное время уже на 10% больше, чем для Малого набора данных и составляет 0.296 сек. При максимуме нагрузки время увеличивается почти в два раза — до 0.595 сек. MySQL и MariaDB оказываются медленнее, чем MyRocks, на 18% при минимальной нагрузке и на 80% при максимальной.
Гигантский набор данных и большая виртуальная машина
- Виртуальная машина: 8 Gb RAM, 4 CPU, HDD 16 Gb
- Набор данных: 10000 пользователей, 1200 проектов и подпроектов, 100000 задач
Графики времени выполнения операций
1) создание задачи; 2) обработка 10 задач
Столбцы показывают время выполнения операции (меньше — лучше). Линии показывают во сколько раз сервер MySQL или MariaDB был медленнее сервера MyRocks MySQL.
Минимальная нагрузка — один процесс Redmine и отсутствует сторонняя нагрузка. Максимальная нагрузка — 4 процесса Redmine и 4 полных потока сторонней нагрузки на диск.
Десятикратное увеличение объема данных немного увеличило время создания задачи для всех баз: 0.020 сек для MyRocks, 0.026-0.029 для MySQL и MariaDB. Увеличение нагрузки замедляет MyRocks на 35% до 0.027 сек. Для MySQL и MariaDB рост нагрузки сказывается на скорости больше — при максимальной нагрузке время увеличивается в 3 раза — до 0.088 сек, и они оказываются медленнее, чем MyRocks, в 3.2 раза.
При обработке задач время выполнения MyRocks увеличивается на 32%, от 0.255 до 0.33 сек. У MySQL и MariaDB время увеличивается в 4 раза — с 0.309 до 1.242 сек. И они отстают от MyRocks в 3.8 раз.
Объем данных уже вырос до таких размеров, что начинают сказываться задержки случайной записи при обновлении индексов InnoDB и разница в скорости между RocksDB и InnoDB при максимальных нагрузках снова выросла.
Анализ результатов
Объем памяти
Для работы Redmine объем 1 Gb является минимальным рекомендуемым. Для эффективного кэширования данных в page cache размер памяти уже недостаточен, поэтому скорость работы очень чуствительна к нагрузке на диск. Задержки возникают уже на SELECT-запросах, так как для них приходится считывать данные с диска. Меньший объем хранимых данных у RocksDB привел к более эффективному кэшированию чтения, чем для InnoDB. Поэтому даже при большой нагрузке скорость операций у MyRocks изменилась совсем незначительно.
При увеличении памяти до 2 Gb основные используемые данные уже вмещаются в page cache и серверу БД уже не нужно постоянно их считывать с диска. В этом случае диск является узким горлышком только при изменениях в базе. Транзакции записываются на диск без writeback cache и интенсивная дисковая нагрузка увеличивает время ожидания завершения записи.
Организация хранения данных в RocksDB, способствующая линейной записи, и уменьшенный объем записываемых данных, уменьшают количество операций записи. Поэтому мы наблюдаем, что даже при высокой дисковой нагрузке, скорость выполнения транзакций в RocksDB лишь немного уменьшается и значительно превышает скорость при использовании InnoDB.
Скорость RocksDB vs InnoDB
Исходя из принципа работы RocksDB, мы ожидали ускорения при выполнении транзакций. На синтетических тестах производительности разработчики получали 10-кратный прирост скорости в работе СУБД. Для приложений, таких как Redmine, время выполнения операции состоит из времени выполнения Ruby-скрипта и времени выполнения запроса в БД. Разумеется, замена storage engine на RocksDB никак не увеличит скорость работы Ruby, и эта составляющая остается неизменной. Но и с учетом этого прирост в скорости за счет ускорения БД оказался впечатляющим.
Здесь мы приводим краевые результаты тестирования для виртуальной машины 2 Gb и Большого набора данных, и для виртуальной машины 8 Gb и Гигантского набора данных. Мы не учитываем здесь тестирование на высокой нагрузке для виртуальной машины 1 Gb, так как это случай экстремальной нехватки ресурсов.
Графики времени выполнения операций
1) создание задачи; 2) обработка 10 задач
Столбцы показывают время выполнения операции (меньше — лучше)
Минимальная (1 процесс Redmine без сторонней дисковой нагрузки) и максимальная нагрузка (4 процесса Redmine и 4 потока полной сторонней нагрузки на диск)
При низкой нагрузке Redmine на MyRocks оказался на 15%-25%, быстрее, чем на MySQL и MariaDB. Размер хранимых данных мало влияет на эту скорость и у RocksDB, и у InnoDB — увеличение числа задач Redmine в 10 раз увеличило время выполнения примерно на 10%.
При высокой нагрузке (увеличении числа параллельных процессов и повышении сторонней дисковой нагрузки) поведение полностью меняется. Отрыв MyRocks стал больше — от 2-кратного до почти 4-кратного. Размер хранимых данных также стал существенно влиять на скорость — 10-кратное увеличение числа задач Redmine заметно (в 1.5-2 раза) замедлило скорость выполнения на серверах с InnoDB, и менее заметно замедлило выполнение на RocksDB (0-15%).
Одновременное увеличение объема данных и высокая нагрузка замедлили работу Redmine с MyRocks в 1.5 раза, в то время как Redmine на MySQL и MariaDB стал медленнее в 4 раза.
Стабильность работы
При тестировании мы обнаружили нюанс поведения одного из SQL-запросов Redmine при поиске с учетом parent issues. Из-за него некоторые виды поиска оказывались медленнее в MyRocks. Но это небольшое упущение со стороны Redmine — parent_id
не имел в таблице индекс. Также мы столкнулись с небольшим багом, приводящим к расходу CPU после некоторых конфликтных транзакций в MyRocks.
Мы не сталкивались с другими проблемами. По словам разработчиков, Facebook использует MyRocks в production уже давно.
Вы можете использовать MyRocks уже сейчас или дождаться более широкого тестирования после появления MyRocks в MariaDB release candidate 10.2 или в Percona Server for MySQL. Пакет MyRocks доступен в репозитории Jetware как одна из альтернатив mysqld
в конструкторах стеков, например, PHP LAMP/LEMP), Ruby RAMP/REMP, или приложений, например, Redmine.
Несколько недель назад мы перевели свой внутренний Redmine-сервер на MyRocks и успешно в нем работаем.
Заключение
- Redmine с RocksDB оказался быстрее, чем с InnoDB — от 20% при минимальной нагрузке до 3 раз при максимальной.
- Увеличение объема данных и нагрузки, замедлившее Redmine с InnoDB в 4 раза, всего лишь в 1.5 раза замедлило Redmine с RocksDB.
P.S. Тестирование MyRocks с другими приложениями
В данном тесте мы проверили производительность MyRocks для приложения Redmine. В следующих тестах мы собираемся проверить производительность MyRocks с PHP-приложениями. Скорее всего, первым будет Drupal.
Комментарии (0)