В это сложно поверить, но MySQL как продукт появился еще в 1995 году. Со временем название СУБД стало таким же нарицательным, как Xerox. Сегодня под этим термином могут понимать самые разные связки: от MySQL Native от компании Oracle до Percona XtraDB Cluster, а ведь есть еще MariaDB, Galera, Percona Server.

О том, как устроено генеалогическое древо MySQL можно снимать сериал с драконами, поэтому в материале мы сконцентрируемся на особенностях и ограничениях работы СУБД с разным типом репликации: MySQL sync и MySQL Semi-sync.

Истоки MySQL


Почему MySQL получил такое широкое распространение? Возможно, кому-то это покажется дискуссионным вопросом, но СУБД еще в 1995 году умела делать репликацию из коробки. Бизнес мог получить ручное отказоустойчивое решение, а для того времени это было революцией. Прежде чем форки научились делать так же, прошло несколько лет.

Тем не менее создатели СУБД MySQL понимали, что дефолтный тип таблиц MyISAM накладывает ряд ограничений. Например, MyISAM мог терять данные при отключении питания сервера.

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

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

Масштабировать базу данных можно при помощи двух основных паттернов: шардирования и репликации. Если в основе шардирования лежит принцип масштабирования операций на запись, то репликация отвечает за масштабирование операций чтения. Здесь мы остановимся подробнее.

Три основных типа репликации


Процесс репликации тесно связан с уровнем доступности IT-инфраструктуры. От базы данных мы ждем быстрой скорости записи, консистентности данных между master и репликами (slaves), а также организации множественного подключения на чтение.


Асинхронная репликация


В таких системах коммит уже считается «успешным», когда данные записаны в master. Это не значит, что на реплики данные попадут примерно никогда, просто система не гарантирует время, когда это случится, и предлагает отпустить ситуацию. Награда для сервиса — скорость записи.

Какие здесь есть подводные камни? Если у master какие-то проблемы, он сможет восстановить записи из логов — ничего страшного. Если у сервера в on-prem инфраструктуре проблемы, то, возможно, запись была сделана только на master и с ней можно попрощаться. При этом можно увидеть сообщение, что запись прошла успешно. Если бы банки работали с таким типом репликации, то мы могли бы наблюдать, как деньги списываются со счета у одного участника транзакции, затем они появляются у другого, а в конце оказывается, что деньги никуда не уходили.

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

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

Синхронная репликация


Если мы что-то пушим в базу данных с синхронной репликацией, то система сначала должна удостовериться, что данные были запушены в 50% реплик + еще одну (метод кворума). То есть пока мы не получим от трех из пяти реплик ответ, что все данные на месте, — коммит не произойдет.

Звучит надежно, но есть два момента. Первый – полноценная проблема, второй – выглядит как проблема.

  • Синхронная репликация — это всегда не быстро. Не во всех задачах удобно ждать, когда придет ответ от всех реплик, что запись случилась. Поэтому такое решение подходит не каждому типу бизнеса.
  • Встречаются реализации синхронной репликации, которые «подрабатывают» как бэкапы. Лаги в системе при записи на реплику могут неделю держать данные с master, поэтому иногда так можно откатить какие-то спорные решения.

Синхронная репликация часто обходится дороже. Почему так?

  • В синхронной репликации труднее поддерживать доступность записи. В такой системе доступность master не означает, что он готов выполнять новые транзакции. Если у master останется только две реплики, то кворум не сработает, поэтому сначала нужно поднять хотя бы еще одну реплику, чтобы собрать те самые 50%+1.
  • В синхронной репликации приходится учитывать на порядок больше сценариев работы сетей. Не всегда удобно настраивать таймауты на коммиты и вести мониторинг.


Полусинхронная репликация


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

Такой тип репликации часто используется в работе с бонусными баллами и картами лояльности.

Ограничения и возможности


В Selectel долгое время из семейства MySQL существовал только один вариант — MySQL sync с синхронной репликацией данных. Клиентам, которые хотели использовать именно этот тип облачных баз данных, приходилось мириться с некоторыми ограничениями, но об этом чуть позже. Поэтому сейчас появилась альтернатива в виде MySQL semi-sync. Кажется, что на базовом уровне, кроме типа репликации, не так много отличий.

MySQL sync (синхронная репликация) MySQL semi-sync (полусинхронная репликация)
Кластеризация и отказоустойчивость Можно создать инстанс только из мастера или отказоустойчивый кластер с мастером и двумя синхронными репликами Можно создать инстанс только из мастера или отказоустойчивый кластер с мастером, одной или двумя репликами
Ограничения работы БД в режиме кластера Для отказоустойчивых кластеров с репликами накладываются ограничения Нет ограничений
Подключение к кластеру Подключение к кластеру происходит через ProxySQL, используется порт 6033 Подключение напрямую к кластеру, используется порт 3306

Ограничения при работе с кластерами MySQL sync


  • Репликация работает только с подсистемой хранения InnoDB (MyISAM не поддерживается).
  • Не поддерживаются запросы LOCK/UNLOCK, GET_LOCK()/RELEASE_LOCK();
    все таблицы должны иметь первичный ключ — иначе нельзя будет совершить запись (INSERT). Например, такое решение не подойдет для систем, использующих Bitrix.
  • XA-транзакции не поддерживаются из-за возможного ROLLBACK на этапе коммитов.
  • Транзакция может откатиться даже после коммита — из двух транзакций, изменяющих одну и ту же запись на разных нодах, только одна будет успешно завершена, а другая будет прервана на уровне кластера.
  • При назначении имени временных таблиц не используйте имена, совпадающие с именами постоянных таблиц, — при подобном совпадении репликация постоянной таблицы остановится.
  • Рекомендовано не использовать рабочую нагрузку с применением ALTER TABLE… IMPORT/EXPORT, если MySQL sync работает в режиме кластера. Это может привести к несогласованности узлов, если они не выполняются синхронно на всех узлах.

Заключение


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

Комментарии (0)