Статьи

MySQL как хранилище значений ключей (KVS) — некоторые общие сведения и некоторые другие тесты


Возможно, вы видели мои попытки протестировать MySQL как хранилище значений ключей (KVS) (
здесь и
здесь ), то есть использовать как MongoDB, и у меня были некоторые комментарии к ним. Прежде всего, многие хотели узнать подробности моей тестовой среды. Если честно, это началось как очень простая вещь, но оказалось больше, чем я думал, поэтому я думаю, что было бы разумно дать некоторую предысторию. Я прошу прощения за то, что не предоставил вам этот опыт раньше, но, как я уже сказал, мое первоначальное намерение состояло в том, чтобы просто запустить стандартную версию MongoDB в сравнении с MySQL и посмотреть, что произошло.

Фон


Здесь, в
Recorded Future , когда я присоединился около 2 лет назад, мы использовали много MySQL, и это вызывало у нас серьезные проблемы. У нас была довольно стандартная реляционная схема в стиле школьных учебников, и производительность действительно причиняла нам боль. Из-за количества и типа данных, которыми мы управляем, потому что мы работаем на Amazon и потому что мы все еще разрабатываем и изменяем, эта схема не соответствовала нашим потребностям вообще.

Чтение — масштабируемость тоже не была хорошим вариантом, так как мы массируем так много данных, что у нас были большие проблемы с тем, чтобы подчиненные подчинялись ведущему.
Изменения схемы, так как мы разрабатывали наше приложение, также были сложными.

То, что мы в итоге сделали, было переделкой многих вещей, в результате чего появилось что-то, что могло бы использовать KVS, так как их легче масштабировать с помощью шардинга. Это также имело некоторые негативные последствия, так как больше не было возможности заходить в MySQL и выдавать запрос на данные просто так. И нет, используя
для этого оболочку
mongo , поскольку мы не только использовали MongoDB, но и распространили данные по нескольким хранилищам MongoDB. С другой стороны, все было не намного производительнее и проще для масштабирования, масштабируемость записи с MongoDB хороша и проста в использовании и настройке. Это не значит, что MongoDB решает все проблемы в мире.

Итак, внедрив MongoDB и привыкнув к нему, и даже начав ему нравиться, я также начал видеть некоторые другие вещи. Мол, почему MySQL не может быть использован для этого? Я имею в виду, что MySQL немного более зрелый, чем MongoDB, и должен лучше обрабатывать, скажем, дисковый ввод-вывод. С другой стороны, MongoDB новее. Я уже знал одну вещь: MongoDB действительно должен быть в большой степени в памяти, когда он попадает на диск, производительность быстро падает, поэтому MySQL лучше. Но когда у нас достаточно ОЗУ (и когда мы используем несколько хранилищ данных MongoDB для разных целей, и мы находимся на Amazon, где вы можете получить приличное количество ОЗУ, это обычно так), что происходит? Если я позволю MySQL использовать оперативную память, она может быть получена, поэтому я вообще не получу дисковый ввод-вывод для чтения, будет ли он так же быстр, как MongoDB? Или, может быть, даже быстрее.

И среди хранилищ данных MySQL самым главным объектом хранилища ключей является NDB?
Как это будет работать?

Тестовая среда


Итак, чтобы проверить все это, но чтобы убедиться, что на меня не повлияли взлеты и падения Amazons, я вытащил один из наших хранилищ данных MongoDB, около 105 000 000 строк реальных данных.
Изначально я планировал использовать полное хранилище данных MongoDB, но мне пришлось исключить некоторые поля, так как это были VARCHAR, а размещение их на диске с NDB приводило к слишком большому количеству дискового ввода-вывода, так как NDB хранит данные на диске фиксированной длины ( поэтому поле UTF-8 VARCHAR (256) занимает около 768 байт). Я закончил со схемой таблицы, как это:
 CREATE TABLE `keyvalue` (
  `id` bigint(20) NOT NULL,
  `value1` int(11) DEFAULT NULL,
  `value2` double DEFAULT NULL,
  PRIMARY KEY (`id`)
)

В случае MongoDB,
столбец
id использовался как
_id , что является способом MongoDBs сказать «ПЕРВИЧНЫЙ КЛЮЧ».

 Сделав все это, мне нужны инструменты для моего тестового стенда:
  • Доморощенный сервер с 8-ядерным процессором AMD FX-8120 и 16 ГБ оперативной памяти на ASUS M5A88-V Mobo. Это действительно аккуратный сервер MoBo, поддерживающий SATA 6, USB 3.0 и другие тонкости, но я использую сетевую карту Lite-On LNE100TX вместо встроенного дерьма Realtek, которым, похоже, оснащены многие MoBos, в частности AMD.
  • Группа дисков, на которых находится база данных, — это LVM Stripe из двух дисков Seagate Barracuda 7200.11 500 Gb с использованием xfs. Но это довольно незначительно, так как при тестировании не должно быть никакого дискового ввода-вывода или, по крайней мере, крайне ограниченного.
  • Ubuntu 10.10 (у меня есть несколько причин для этой немного древней версии. И да, я исправил проблему с памятью 16 Гб в Linux с некоторыми AMD MoBos).
  • MySQL 5.6.5 64-битная (для всех тестов MySQL, кроме NDB)
  • MySQL Cluster 7.2.6 64-bit (для тестов MySQL NDB) 
  • MongoDB 2.0.5 64-битная

Имея все это готовое, теперь у меня была немного меньшая таблица, занимающая около 4,2 Гб при экспорте в JSON. Таким образом, эти данные были импортированы в MongoDB и MySQL с несколькими различными механизмами хранения, и я был готов провести некоторое тестирование. Я использую тестовую программу, которая запускает запросы SQL с более чем определенным T потоков, каждый SQL (с Mongo это, конечно, не SQL, но тестовая программа та же самая) содержит переменную часть, которая является идентификатором строки чтобы искать, программа начинается с чтения файла с несколькими случайными идентификаторами, идентификаторы распределяются по потокам, а затем каждый поток просматривает строки N раз.

В этом случае я выбрал несколько чисел для своего теста, поэтому число потоков, которые я использую, равно 100, а не необоснованному числу, но достаточно велико, чтобы сделать видимыми любые проблемы параллелизма, и число раундов равно 10. Итак, чтобы быть понятным, 1.000 .000 идентификаторов распределены по потокам, поэтому каждый поток обрабатывает по 10.000 идентификаторов каждый, затем выполняется 10 раз, что означает, что я выполняю около 10.000.000 случайных чтений параллельно.
Я знаю, что это не самый захватывающий ориентир на планете, но он все равно был интересным и в некоторой степени испытанием в реальном мире.

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

Текущее состояние испытаний


До сих пор я тестировал MongoDB, MySQL Cluster и MySQL InnoDB, и с тех пор я также тестировал движок MySQL MEMORY и MySQL с MyISAM.
Пока что результаты выглядят так:
  • MongoDB — 110 000 строк, читаемых в секунду
  • MySQL Cluster — 32.000 строк, читаемых в секунду
  • MySQL с InnoDB — 39 000 строк, читаемых в секунду
  • MySQL с MEMORY / HEAP — 43 000 строк, читаемых в секунду
  • MySQL с MyISAM — 28 000 считываний строк в секунду

Последние два были очень разочаровывающими для меня, и поверьте мне, я хочу, чтобы они были хорошими. Я действительно хотел, чтобы MySQL побеждал MongoDB, и я действительно хотел посмотреть, как намного меньшие издержки MyISAM заставят его вращаться вокруг InnoDB, но нет.

Поскольку MyISAM кэширует только сами ключи, а не фактические данные, это было проблемой, но, тем не менее, файл данных MyISAM должен быть хорошо кэширован Linux для меня, и правильно, что не было дискового ввода-вывода. Может ли быть проблемой переключение контекста при переходе на Linux для данных? Я решил попробовать что-нибудь веселое. Я создал новый уникальный индекс для таблицы, охватывающий все столбцы, что означало, что, если бы я использовал этот индекс покрытия, все данные были бы выполнены индексом (но сам индекс, конечно, был бы больше). Это совсем не помогло, совсем наоборот. Игра с именованными клавишами и прочим ничем не помогла, равно как и использование mmap. Это не означает, что эти парни не помогают улучшить производительность, все это означает, что, когда все данные уже находятся в памяти, они, похоже, не помогают. Я понял одну вещь, которая сработала, хотя,который использовал tcmalloc. Включение tcmalloc при запуске сервера mysql, что легко в наши дни, поскольку MySQL поставляется с включенной библиотекой tcmalloc, а mysqld_safe имеет параметр командной строки для этого. Очень просто, это действительно должно быть по умолчанию.

С этим на месте мне удалось получить:

  • MySQL с MyISAM — 37 000 строк, читаемых в секунду

Я попробую использовать tcmalloc с другими движками, и посмотрю, что произойдет.

В заключение пока

Не поймите меня неправильно, я не собираюсь доказывать, что MySQL или MongoDB отстой. И я не собираюсь делать какие-то точные тесты. Что мне нужно сделать, так это проверить, может ли заявить, что СУБД может работать так же, как и стандартное хранилище значений ключей, в среде, оптимизированной для хранилища значений ключей (т. Е. Все данные в памяти). И такая среда не настолько специализирована на самом деле. базы данных размером в несколько десятков гигабайт действительно распространены и легко помещаются в памяти. И хотя я предпочитаю более строгую модель данных СУБД, чем довольно бесструктурный дизайн альтернативы NoSQL, такой как MongoDB (MongoDB действительно имеет некоторую зависимость от схемы, но, по сути, она не требует схем), я должен признать, что иногда вам нужно больше производительности, а распределение нагрузки по нескольким серверам намного проще, когда вы нене нужно беспокоиться о глобальных транзакциях или глобальной согласованности, и, честно говоря, во многих случаях вы можете жить без этого, в некоторой степени,

Остается попробовать MySQL с NDB, использующим несколько серверов mysqld, InnoDB с использованием tcmalloc и tarantool и интерфейс MySQL HANDLER (на самом деле я уже тестировал последний, но не уверен, что тесты выполнены правильно).

/ Карлссон,

который приносит извинения за упущение настройки теста перед публикацией первых результатов