Статьи

Масштабирование до 100M: MySQL лучше NoSQL

MySQL лучше NoSQL. При рассмотрении варианта использования NoSQL, такого как хранилище ключей / значений, MySQL имеет больше смысла с точки зрения производительности, простоты использования и стабильности. MySQL — это надежный движок с большим количеством онлайн-материалов, от операций и случаев сбоев до репликации и различных моделей использования. По этой причине у него есть преимущество перед более новыми движками NoSQL, которые не были проверены в бою.

В последние годы движки NoSQL стали мейнстримом. Многие разработчики рассматривают движки NoSQL, такие как MongoDB, Cassandra, Redis или Hadoop, как свой первый выбор для создания приложений, считая их одним семейством продуктов, которое не поддерживает старые движки SQL.

Выбор использования базы данных NoSQL часто основан на обмане или неправильном предположении, что реляционные базы данных не могут работать так же хорошо, как база данных NoSQL. Операционные затраты, а также другие проблемы со стабильностью и зрелостью часто игнорируются инженерами при выборе базы данных. Дополнительную информацию об ограничениях и недостатках различных движков NoSQL (и SQL) можно найти в серии статей Jepsen от Aphyr .

В этом посте будет объяснено, почему мы обнаружили, что использование MySQL для варианта использования ключ / значение лучше, чем в большинстве специализированных механизмов NoSQL, и даются рекомендации, которым следует следовать при использовании MySQL таким образом.

Wix Site Resolution

Когда кто-то щелкает ссылку на сайт Wix, его браузер отправляет HTTP-запрос на сервер в Wix с адресом сайта. Это происходит независимо от того, является ли адрес премиум-сайтом Wix с пользовательским доменом (например, domain.com ) или бесплатным сайтом в поддомене домена Wix (например, user.wix.com/site ). Этот сервер должен разрешить запрошенный сайт по адресу сайта, выполнив URL поиска ключа / значения для сайта. Мы обозначаем URL как маршрут для следующего обсуждения.

Таблица маршрутов используется для разрешения адреса сайта к объекту сайта. Поскольку сайты могут быть выставлены на нескольких маршрутах, отношение много к одному. Как только сайт найден, приложение загружает его для использования. Сам объект сайта имеет сложную структуру, которая включает два списка дочерних объектов — разные сервисы, которые использует сайт. Вот пример модели наших объектов, предполагающий стандартную базу данных SQL и нормализованную схему:

MySQL-это-лучше-NoSQL-1

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

Тем не менее, есть ряд проблем с нормализованной схемой способа моделирования:

  • Блокировки ограничивают доступ к таблице, поэтому в случае использования с высокой пропускной способностью это может ограничивать нашу производительность.
  • Чтение объекта включает в себя либо несколько SQL-запросов (в нашем случае 4), либо объединения, что опять же сказывается на задержке.
  • Серийные ключи налагают блокировки и снова ограничивают пропускную способность записи.

Эти проблемы сводятся к ограничениям в пропускной способности и параллелизме, которые мы можем получить от MySQL (или любого другого механизма SQL). Из-за этих недостатков и того факта, что вариант использования фактически является ключом / значением, многие разработчики предпочитают искать решение NoSQL, которое обеспечивает лучшую пропускную способность и параллелизм даже за счет стабильности, согласованности или доступности.

В Wix мы обнаружили, что MySQL, творчески используемый в качестве хранилища ключей / значений, может выполнять лучшую работу по сравнению с MySQL с нормализованной моделью данных (как та, что описана выше) — и для большинства движков NoSQL. Просто используйте MySQL как движок NoSQL. Наша существующая система имеет показатели масштабирования / пропускной способности / параллелизма / задержки, которые впечатляют для любого движка NoSQL. Вот некоторые из наших данных:

  • Активно-активно-активная настройка в трех центрах обработки данных.
  • Пропускная способность составляет порядка 200 000 оборотов в минуту.
  • Таблица маршрутов имеет порядок 100 000 000 записей, 10 ГБ памяти.
  • Таблица сайтов имеет порядок 100 000 000 записей, 200 ГБ памяти.
  • Задержка чтения составляет в среднем 1,0-1,5 мсек (фактически 0,2-0,3 мсек в одном центре обработки данных).

Обратите внимание, что задержка около 1,0 мс считается впечатляющей с большинством механизмов ключ / значение, как с открытым исходным кодом, так и на основе облачных вычислений! И мы достигаем этого с MySQL (считается основным механизмом SQL).

Вот фактическая схема, которую мы используем:

MySQL-это-лучше-NoSQL-2

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
CREATE TABLE `routes` (
  `route` varchar(255) NOT NULL,
  `site_id` varchar(50) NOT NULL,
  `last_update_date` bigint NOT NULL,
  PRIMARY KEY (`key`),
  KEY (`site_id`)
)
 
CREATE TABLE `sites` (
  `site_id` varchar(50) NOT NULL,
  `owner_id` varchar(50) NOT NULL,
  `schema_version` varchar(10) NOT NULL DEFAULT '1.0',
  `site_data` text NOT NULL,
  `last_update_date` bigint NOT NULL,
  PRIMARY KEY (`site_id`)
) /*ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=16*/;

Любое поле, которое не используется в качестве условия в запросе, было свернуто в одно поле большого двоичного объекта (текстовое поле site_data). Это включает в себя таблицы sub-obj, а также любое поле в самой таблице объектов. Также обратите внимание, что мы не используем серийные ключи; вместо этого мы используем varchar (50), который хранит сгенерированные клиентом значения GUID — подробнее об этом в следующем разделе.

Ниже приведен используемый нами запрос с высокой пропускной способностью и низкой задержкой:

1
2
3
select * from sites where site_id = (
  select site_id from routes where route = ?
)

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

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

Рекомендации по использованию MySQL в качестве движка NoSQL

Используя опыт, полученный из приведенного выше примера (и других подобных случаев в Wix), мы составили краткий список рекомендаций по использованию MySQL в качестве движка NoSQL.

Главное, что следует иметь в виду при использовании MySQL в качестве движка NoSQL, это избегать использования блокировок БД или сложных запросов.

  • Не используйте транзакции, которые вводят блокировки. Вместо этого используйте аппликативные транзакции.
  • Не используйте серийные ключи. Серийные ключи вводят блокировки и усложняют активно-активные конфигурации.
  • Используйте сгенерированные клиентом уникальные ключи. Мы используем GUID.

При разработке схемы, которая будет оптимизирована для чтения, вот несколько дополнительных рекомендаций:

  • Не нормализуй.
  • Поля существуют только для индексации. Если поле для индекса не требуется, сохраните его в одном поле типа blob / text (например, JSON или XML).
  • Не используйте внешние ключи.
  • Разработайте свою схему, чтобы включить чтение одной строки по запросу.
  • Не выполняйте команды изменения таблицы. Команды изменения таблицы вводят блокировки и простои. Вместо этого используйте живые миграции.

При запросе данных:

  • Запрос на записи по первичному ключу или по индексу.
  • Не используйте соединения.
  • Не используйте агрегации.
  • Выполнять служебные запросы (BI, исследование данных и т. Д.) В реплике, а не в базе данных master.

Мы намерены написать еще одно сообщение в блоге с дополнительной информацией о реальных миграциях и аппликационных транзакциях.

Резюме

Самым важным выводом из этого поста является то, что вам позволено думать по-другому. Замечательно использовать MySQL как движок NoSQL, который не предназначен для работы. Как показано в этом посте, примером этого является использование MySQL вместо специализированных механизмов NoSQL, которые созданы для доступа ключ / значение. В Wix MySQL является предпочтительным двигателем для случаев ключ / значение (среди прочих), потому что он прост в использовании и эксплуатации, и это отличная экосистема. И в качестве бонуса, он предоставляет метрики задержки, пропускной способности и параллелизма, которые соответствуют, если не превосходят, большинству движков NoSQL.

Ссылка: Масштабирование до 100M: MySQL — лучшая NoSQL от нашего партнера по JCG Йоава Абрахами из блога Wix IO .