Наши партнеры








Книги по Linux (с отзывами читателей)

Библиотека сайта rus-linux.net

Репликация MySQL

Оригинал: MySQL Replication
Автор: Michael Nugent
Дата публикации: 1 сентября 2010 г.
Перевод: Александр Тарасов aka oioki
Дата перевода: 14 марта 2011 г.

MySQL работает на Linux в датацентрах вот уже много-много лет, однако многие до сих пор не понимают сущности репликации MySQL. Будь то межрегиональная асинхронная система или локальный кластер, всегда в MySQL для вас найдется приемлемый тип репликации.

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

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

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

Разумеется, можно строить кластеры различными способами, в том числе комбинируя блочную репликацию и SAN-хранилища, однако официальным решением MySQL является репликация и кластеры NDB (Network DataBase). У каждого решения свои преимущества и недостатки, и при выборе решения для своего приложения вам следует разобраться, какое из них наиболее подойдет для вашего конкретного случая. Помимо выбора типа репликации, критически важным является версия MySQL. Программное обеспечние разрабатывается непрерывно, и для работы многих описанных здесь функций потребуется по крайней мере версия 5.1. Если версия вашей СУБД старее, строго рекомендуется ее обновить перед реализацией этих решений. Активная разработка версии 5.0 завершилась в декабре 2009 года, а версии 5.1 - в декабре 2010 года.

При репликации MySQL между парой серверов устанавливается связь master-slave или master-master. Эти сервера можно соединить в кольцо из множества серверов, либо использовать один master для нескольких slave - в любом случае, отношения устанавливаются только между двумя серверами. Один MySQL сервер может иметь только одного master-а. Репликация является более гибким решением, чем NDB, в том смысле, что можно использовать множество типов движков БД и дополнительных функций. NDB-кластеры ограничены использованием NDB-таблиц, в то время как репликация может работать практически на любых типах таблиц MySQL, в том числе на MyISAM и InnoDB.

Примеры репликации типа Multimaster обычно задаются только для двух серверов, однако ее можно настроить и на любом количестве серверов при циклической организации. Чтобы настроить циклический набор из трех серверов, секция [mysqld] конфигурационного файла my.cnf должна содержать следующие строки:
server-id=1                  # Это уникальный номер сервера.
auto_increment_offset=1      # Должно быть уникальным, но меньшим
                             # значения auto_increment_increment,
                             # описанного ниже.
auto_increment_increment=3   # Установите как минимум равным
                             # числу серверов в цикле

Значение auto_increment_offset определяет начальное значение для столбцов с атрибутом AUTO_INCREMENT и для каждого сервера должно быть уникальным и меньшим значения auto_increment_increment. Значение auto_increment_increment определяет интервал между значениями auto_increment на отдельном сервере. Для предотвращения конфликтов установите ему значение, как минимум равное числу серверов в цикле.

Таким образом, для определения следующего значения в столбце с атрибутом AUTO_INCREMENT, сервер перемножает следующее ожидаемое значение с auto_increment_increment и добавляет значение auto_increment_offset. Если N - следующее ожидаемое значение последовательности (к примеру, 1, 2, 3, 4, 5 и т.д.), тогда следующим значением для столбца с атрибутом AUTO_INCREMENT будет:
N x auto_increment_increment + auto_increment_offset

Также в конфигурационный файл можно добавить:

  • log_slave_updates: эта опция заставляет сервер записывать обновления, пришедшие с master-сервера в собственный журнал, таким образом машина может выступать как в роли master, так и slave.
  • slave_exec_mode=IDEMPOTENT: использование этой функции строго опционально. Она позволяет slave-серверу пропускать ошибки репликации. Хотя при ее использовании slave-репликация не остановится, однако она опасна десинхронизацией slave от master, что приведет к различным данным на серверах. Использование таблиц типа InnoDB, транзакций и откатов значительно уменьшит вероятность десинхронизации.
После изменения файла my.cnf, каждому серверу нужно назначить пользователя, которому будет разрешен доступ на репликацию, и установить master - источник данных:
server A mysql> GRANT REPLICATION CLIENT,
                      REPLICATION SLAVE,
                      SELECT, FILE, PROCESS,
                      SUPER RELOAD ON *.* TO 'replication'@'%s'
                      identified by 'replpass';
server A mysql> flush privileges;
server A mysql> change master to
                       MASTER_HOST="serverB.example.com",
                       MASTER_USER="replication",
                       MASTER_PASSWORD='replpass';
server A mysql> start slave;
server B mysql> GRANT REPLICATION CLIENT ... ;  (как и выше)
server B mysql> flush privileges;
server B mysql> change master to
                       MASTER_HOST="serverC.example.com",
                       MASTER_USER="replication",
                       MASTER_PASSWORD='replpass';
server B mysql> start slave;
server C mysql> GRANT REPLICATION CLIENT ... ;  (как и выше)
server C mysql> flush privileges;
server C mysql> change master to
                       MASTER_HOST="serverA.example.com",
                       MASTER_USER="replication",
                       MASTER_PASSWORD='replpass';
server C mysql> start slave;

В данном случае, сервер A получает данные с сервера B, который получает данные с сервера C, который в свою очередь циклически получает данные с сервера A. Данные могут быть добавлены на любом из трех серверов и будут реплицированы на оставшиеся два сервера. Скорость записи при этом не увеличится, но скорость чтения может быть заметно повышена, если ваше приложение переключается между серверами кластера. К тому же, в случае аппаратного сбоя, данные не потеряются, а сохранятся на остальных серверах кластера. Удаление отказавшего slave производится путем замены директивы change master, чтобы она указывала на master-сервер своего бывшего master-сервера. Второй вариант - установить взамен отказавшего сервера новый и скопировать на него снимок данных из кластера.

NDB-кластер

В отличие от слабо связанной схемы в multimaster-репликации, NDB-кластер можно рассматривать как единую сущность. На самом деле, сервера NDB-кластера настолько сильно связаны, что NDB-кластер можно использовать как отдельный сервер в схеме multimaster-репликации. Хотя NDB обладает огромными преимуществами в синхронизации и управлении кластера, однако движок NDB поддерживает не все функции других движков MySQL, и единственно возможным типом таблиц в NDB-кластере является тип NDB. Движок NDB не поддерживает создание точек восстановления внутри MySQL и поэтому не поддерживает транзакции и откаты. В результате, при выполнении запроса ALTER TABLE или CREATE TABLE, к изменяемой таблице не должно производиться запросов доступа. Блокировка выполняется на текущем узле, однако это всего лишь локальная блокировка, и поэтому возможны проблемы с целостностью данных и даже отказ системы в случае, если к таблице захотят получить доступ с другого узла.

Перед установкой программного обеспечения NDB-кластера, необходимо рассмотреть аппаратный состав. Кластер - это синхронизированная единица, в котором нет встроенного шифрования, поэтому лучше всего будет запускать его во внутренней сети или VLAN. Если же NDB требуется использовать в веб-приложении, тогда обязательно следует отделить внутренние связи СУБД от связей, по которым идут ваши прикладные запросы.

Сеть NDB-кластера может быть построена разными способами, но большинство пользователей предпочитают стандартную сеть TCP через Gigabit Ethernet. 100-мегабитные сети тоже будут работать, но, конечно, могут стать узким местом в производительности достаточно больших систем. 10-мегабитные сети не поддерживаются. Рассмотренное нами выше решение в виде репликации требует лишь MySQL-серверов, и ничего более. А NDB-кластер требует также наличия управляющих узлов (management nodes) и узлов данных (data nodes). У всех у них должно быть как можно меньшее время отклика. В гигабитных сетях хорошей идеей является использование Jumbo-кадров, ведь передача как можно большего объема данных в пакете снижает вероятность любых типов ошибок, прерывающих синхронную передачу данных между узлами NDB-кластера.

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

Перед тем, как настраивать узлы NDB-кластера, убедитесь, что ваша сборка MySQL его поддерживает. Введите в консоли MySQL команду show engines и найдите строку NDBCLUSTER, соответствующее значение в столбце Support должно быть равно Yes. Если это не так, вам нужно установить другой пакет, или собрать сервер самостоятельно из community-исходников, которые можно взять на сайте www.mysql.com.

Конфигурация NDB состоит из серверов трех типов. Управляющий сервер (management server) обеспечивает функции настройки и мониторинга кластера посредством демона ndb_mgmd. Узлы данных хранят данные с помощью демона ndbd, а на SQL-узлах работает непосредственно сервер mysqld. Хотя и возможно запустить разные демоны на одном и том же физическом сервере, однако делать этого в production-среде не рекомендуется. Лучше всего разнести их на разные физические серверы.

NDB-кластер описывается двумя конфигурационными файлами. Первый my.cnf - это стандартный конфигурационный файл MySQL. Второй файл config.ini читается только управляющим сервером. Файл config.ini содержит настройки узлов данных. Управляющий сервер сам передает эти настройки на узлы данных.

Правки в конфигурационный файл my.cnf довольно просты, приведены правки для каждого типа серверов:
# Сервер управления
[ndb_mgm]
ndb-connectstring=manage.example.com:1186
[ndb_mgmd]
config-file=/etc/config.ini

# Узел данных
[ndbd]
ndb-connectstring=manage.example.com:1186

# SQL-сервер
[mysqld]
ndbcluster                       # Этой директивой мы включаем кластер
ndb-force-send=1	         # Отправлять буферы немедленно
ndb-index-stat-enable=1          # Оптимизирует запросы с помощью
                                 # статистики индексов NDB
engine-condition-pushdown=1

[mysql_cluster]
ndb-connectstring=manage.example.com:1186

Опция engine-condition-pushdown заставляет MySQL отправлять запросы напрямую движку хранилища, минуя mysql-демон. В кластере NDB, это позволяет распределить запросы по нескольким узлам данных.

Файл config.ini также довольно прост. Его нужно сохранить в пути, указанном в параметре config-file файла my.cnf:
# Управляющий узел
[ndb_mgmd default]
DataDir=/var/lib/mysql-cluster   # Где сервер управления будет хранить данные

[ndb_mgmd]
HostName=manage.example.com      # Имя данной машины

[ndbd default]
NoOfReplicas=2                   # У нас 2 узла данных

[ndbd]
HostName=datanode.example.com    # Имя хоста узла данных

[mysqld]
HostName=datanode.example.com    # Имя хоста узла данных
DataDir=/var/lib/mysql           # Место, где узел данных хранит данные

В данном случае, мы имеем три сервера, по одному каждого типа: сервер управления, узел данных и SQL-узел. Запросы отправляются на SQL-сервер, который уже взаимодействует с узлами данных. По причине того, что SQL-сервер общается с несколькими узлами данных, по мере необходимости с оптимизатором NDB движка (устанавливается с помощью параметре engine-condition-push - см. выше), этот тип репликации на запросах типа SELECT может работать в разы быстрее, чем в multimaster-конфигурациях, описанных выше. С другой стороны, NDB использует синхронную репликацию, поэтому запросы записи, такие как INSERT и UPDATE, могут выполняться дольше, потому что данные должны быть записаны на каждый узел кластера.

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

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

Приемлемым способом разворачивания межрегионального NDB-кластера является установка двух отдельных NDB-кластеров (по одному в дата-центре) и настройка между ними multimaster-репликации (или master-slave только для отказоустойчивости). Чтобы получить такую конфигурацию, нужно настроить NDB-кластер как обычно, и добавить параметры auto_increment в файл my.cnf, добавить права репликации выделенному пользователю и выполнить команду "change master" в консоли MySQL.

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

Построение кластера MySQL, будь то с помощью репликации или в виде NDB-кластера - сложная задача, особенно для тех, кто делает это впервые. Построение такой системы в условиях ограниченности времени или наличии существующих данных делает эту задачу еще труднее. Разумеется, нужно попробовать настроить несколько систем в тестовой среде. Виртуальные машины - хорошая платформа для тестирования и отладки, однако конечную производительность можно оценить только на реальном железе. Нужно быть уверенным, что порядок работы приложения не пострадает от низкой производительноси базы данных. Итак, потребуются реальные машины, настоящие данные и, если возможно, файл с реальными SQL-запросами к системе. Межрегиональные системы еще сложнее настроить и поддерживать, имея маленький бюджет. Поэтому наверняка стоит сравнить операционные расходы с расходами, которые вы можете понести в случае простоя системы. В заключение, мне хотелось бы сказать, что как бы хороши ни были ваши репликации и кластеры, они никогда не заменят резервного копирования. Поэтому сохраняйтесь раньше и чаще.

Майкл Ньюгент (Michael Nugent) провел добрую часть своего времени, разрабатывая масштабируемые решения для средних бюджетов, применяя Linux в тех ситуациях, в которых обычно работают большие коммерческие устройства. Недавно Майкл работал над проектом межрегиональной базы данных для одного из стартапов Силиконовой долины. В свободное от построения кластеров время он занимается парусным спортом, MIG-сваркой и гуляет со своей кошкой, MIDI. Майклу можно написать на e-mail: michael@michaelnugent.org.