Репликация mysql


Настройка репликации

Мастер-сервер

  • Добавляем нужные опции в конфиге my.cnf на мастер-сервере:


  • Даем права слейв-серверу делать репликацию с этого. Для этого в консоли mysql даем команду:


где:

  • repluser — имя пользователя для подключения. Пользователь создается в момент выполнения команды.
  • replhost — IP-адрес или домен хоста слейв-сервера, который будет подключаться к этому мастеру и импортировать с него изменения.
  • replpass — пароль для подключения
 Ограничение на базу для репликации в grant replication вроде как не работает - т.е., разрешаем все, а в конфиге указываем только ту базу / базы, которые нужны 

Перезапускаем сервер, после чего в консоли можно выполнить команду



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

Slave-сервер

  • Добавляем нужные опции в конфиге my.cnf на slave-сервере:



Перезапускаем сервер для применения изменений

Запуск репликации

На мастере блокируем таблицы на запись для получения полностью корректного дампа:



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



После этого пускаем мастер в работу:



(хотя возникает мысль — а действительно ли нужно лочить базу при дампе? Как только начал делаться дамп с —master-data — в него кидается имя лога и позиция, а таблицы автоматически лочатся на запись — т.е. все то же самое, только в автоматическом режиме)

Далее заливаем дамп на слейв-сервер как обычно:



В данном случае slavedbname = masterdbname, хотя при желании можно сделать так, чтобы база реплицировалась уже под другим именем.

Указываем слейву адрес мастер-сервера:



где masterip — IP-адрес или домен мастер-сервера, а остальные опции — те, что указывались выше при настройке мастера. Имя лог-файла и позиция берется из дампа, но при желании их можно вручную указать через опции MASTER_LOG_FILE = «имя_лога», MASTER_LOG_POS = позиция

После этой команды информация о мастере сохраняется в файле master.info в каталоге баз данных mysql-сервера. При желании можно указать эти опции в конфиге слейв-сервера:



После этого запускаем slave-сервер через mysql-консоль:



Теперь можно проверить статус slave-сервера командой



Из интересной информации там могут быть поля:


  • Slave_IO_State: Waiting FOR master TO send event, Slave_IO_Running: Yes и Slave_SQL_Running: Yes — все работает хорошо :)
  • Seconds_Behind_Master — на сколько слейв отстал от мастера. В нормальном режиме должен быть 0, однако 0 при реальном отставании может быть и в том случае, если на мастере производится много изменений, а канал между мастером и слейвом узкий и последний не успевает скачивать бинлоги с мастера. В таком случае «0» корректен, но лишь для того, что успело скачаться из логов.

…и прочая текущая информация вроде отсутствия ошибок, текущей позиции и имени лога сервера, лога слейва и т.п.

Разное

Для mysqldump есть 2 опции для вписывания имени лога и позиции в файл дампа: —master-data и —dump-slave. Вторая есть не везде:



 --dump-slave[=value]  This option is similar to --master-data except that it is used to dump a replication slave server  to produce a dump file that can be used to set up another server as a slave that has the same master as the dumped server. It causes the dump output to include a CHANGE MASTER TO statement that indicates the binary log coordinates (file name and position) of the dumped slave's master (rather than the coordinates of the dumped server, as is done by the --master-data option). These are the master server coordinates from which the slave should start replicating. This option was added in MySQL 5.5.3.  

Соответственно, одна опция — для клонирования слейва, вторая — для создания субслейва. Иначе говоря, dump-slave позволяет в цепочке master-slave1-slave2 создать (с помощью slave1) еще один slave1 (в дамп запишется позиция в логе и файл лога относительно логов master), master-data позволяет создать slave2 — в дамп запишется позиция/лог относительно бинлогов slave1.

Ошибки репликации

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

Варианты решения:

1) Добавляем в конфиг слейв-сервера опцию для пропуска определенного типа ошибок, например:



Перезапускаем сервер, после этого ошибки указанных типов будут игнорироваться

2) задать счетчик числа ошибок через mysql-консоль:



Данный запрос установит счетчик пропуска ошибок равным единице (иными словами позволит пропустить одну ошибку).

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


В случае случайных ручных изменений данных на слейве можно добавить в конфиг опцию read-only

linuxoid.in

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

Небольшое введение

Репликация (от лат. replico -повторяю) — это тиражирование изменений данных с главного сервера БД на одном или нескольких зависимых серверах. Главный сервер будем называть мастером, а зависимые — репликами.
Изменения данных, происходящие на мастере, повторяются на репликах (но не наоборот). Поэтому запросы на изменение данных (INSERT, UPDATE, DELETE и т. д.) выполняются только на мастере, а запросы на чтение данных (проще говоря, SELECT) могут выполняться как на репликах, так и на мастере. Процесс репликации на одной из реплик не влияет на работу других реплик, и практически не влияет на работу мастера.
Репликация производится при помощи бинарных логов, ведущихся на мастере.


них сохраняются все запросы, приводящие (или потенциально приводящие) к изменениям в БД (запросы сохраняются не в явном виде, поэтому если захочется их посмотреть, придется воспользоваться утилитой mysqlbinlog). Бинлоги передаются на реплики (бинлог, скачанный с мастера, называется "relay binlog ") и сохраненные запросы выполняются, начиная с определенной позиции. Важно понимать, что при репликации передаются не сами измененные данные, а только запросы, вызывающие изменения.
При репликации содержимое БД дублируется на нескольких серверах. Зачем необходимо прибегать к дублированию? Есть несколько причин:

  • производительность и масштабируемость. Один сервер может не справляться с нагрузкой, вызываемой одновременными операциями чтения и записи в БД. Выгода от создания реплик будет тем больше, чем больше операций чтения приходится на одну операцию записи в вашей системе.
  • отказоустойчивость. В случае отказа реплики, все запросы чтения можно безопасно перевести на мастера. Если откажет мастер, запросы записи можно перевести на реплику (после того, как мастер будет восстановлен, он может принять на себя роль реплики).
  • резервирование данных. Реплику можно «тормознуть » на время, чтобы выполнить mysqldump, а мастер — нет.
  • отложенные вычисления. Тяжелые и медленные SQL-запросы можно выполнять на отдельной реплике, не боясь помешать нормальной работе всей системы.

Кроме того, есть некоторые другие интересные возможности. Поскольку на реплики передаются не сами данные, а запросы, вызывающие их изменения, мы можем использовать различную структуру таблиц на мастере и репликах. В частности, может отличаться тип таблицы (engine) или набор индексов. Например, для осуществления полнотекстового поиска мы можем на реплике использовать тип таблицы MyISAM, несмотря на то, что мастер будет использовать InnoDB.

Настройка репликации

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

  • IP-адрес мастера 192.168.1.101, реплики — 192.168.1.102.
  • MySQL установлен и настроен
  • требуется настроить репликацию БД testdb
  • мы можем приостановить работу мастера на некоторое время
  • у нас, разумеется, есть root на обеих машинах

Настройки мастера

Обязательно укажем уникальный ID сервера, путь для бинарных логов и имя БД для репликации в секции [mysqld]:
server-id = 1
log-bin = /var/lib/mysql/mysql-bin
replicate-do-db = testdb



Убедитесь, что у вас достаточно места на диске для бинарных логов.

Добавим пользователя replication, под правами которого будет производится репликация. Будет достаточно привилегии "replication slave ":
mysql@master> GRANT replication slave ON "testdb".* TO "replication"@"192.168.1.102" IDENTIFIED BY "password";

Перезагрузим MySQL, чтобы изменения в конфиге вступили в силу:
root@master# service mysqld restart

Если все прошло успешно, команда "show master status " должна показать примерно следующее:
mysql@master> SHOW MASTER STATUSG
File: mysql-bin.000003
Position: 98
Binlog_Do_DB:
Binlog_Ignore_DB:

Значение position должно увеличиваться по мере того, как вносятся изменения в БД на мастере.

Настройки реплики

Укажем ID сервера, имя БД для репликации и путь к relay-бинлогам в секции [mysqld] конфига, затем перезагрузим MySQL:
server-id = 2
relay-log = /var/lib/mysql/mysql-relay-bin
relay-log-index = /var/lib/mysql/mysql-relay-bin.index
replicate-do-db = testdb

root@replica# service mysqld restart


Переносим данные

Здесь нам придется заблокировать БД для записи. Для этого можно либо остановить работу приложений, либо воспользоваться установкой флажка read_only на мастере (внимание: на пользователей с привилегией SUPER этот флаг не действует). Если у нас есть таблицы MyISAM, сделаем также "flush tables":
mysql@master> FLUSH TABLES WITH READ LOCK;
mysql@master> SET GLOBAL read_only = ON;

Посмотрим состояние мастера командой «show master status» и запомним значения File и Position (после успешной блокировки мастера они не должны изменятся):
File: mysql-bin.000003
Position: 98

Делаем дамп БД, и после завершения операции снимаем блокировку мастера:
mysql@master> SET GLOBAL read_only = OFF;

Переносим дамп на реплику и восстанавливаем из него данные.
Наконец, запускаем репликацию командами "change master to" и "start slave" и посмотрим, все ли прошло хорошо:
mysql@replica> CHANGE MASTER TO MASTER_HOST = "192.168.1.101 ", MASTER_USER = "replication ", MASTER_PASSWORD = "password ", MASTER_LOG_FILE = "mysql-bin.000003 ", MASTER_LOG_POS = 98;
mysql@replica> start slave;

Значения MASTER_LOG_FILE и MASTER_LOG_POS мы берем с мастера.

Посмотрим, как идет репликация командой "show slave status ":


mysql@replica> SHOW SLAVE STATUSG
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.101
Master_User: replication
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 98
Relay_Log_File: mysql-relay-bin.001152
Relay_Log_Pos: 235
Relay_Master_Log_File: mysql-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB: testdb,testdb
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 98
Relay_Log_Space: 235
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 5

Наиболее интересные сейчас значения я выделил. При успешном начале репликации их значения должны быть примерно такими, как в листинге (см. описание команды "show slave status " в документации). Значение Seconds_Behind_Master может быть любым целым числом.
Если репликация идет нормально, реплика будет следовать за мастером (номер лога в Master_Log_File и позиция Exec_Master_Log_Pos будут расти).


емя отставания реплики от мастера (Seconds_Behind_Master), в идеале, должно быть равно нулю. Если оно не сокращается или растет, возможно, что нагрузка на реплику слишком высока — она просто не успевает повторять изменения, происходящие на мастере.
Если же значение Slave_IO_State пусто, а Seconds_Behind_Master равно NULL, репликация не началась. Смотрите лог MySQL для выяснения причины, устраняйте её и заново запускайте репликацию:
mysql@replica> start slave;

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

  • заблокировать запись в мастер флагом read_only, запомнить позицию и остановить MySQL.
  • после этого скопировать файлы БД на реплику и включить мастер.
  • начать репликацию обычным способом.

Существует несколько способов создать реплику без остановки мастера вообще, но они срабатывают не всегда.

Добавляем реплики

Пусть у нас уже есть работающие мастер и реплика, и нам нужно добавить к ним еще одну. Сделать это даже проще, чем добавить первую реплику к мастеру. И гораздо приятнее то, что нет необходимости останавливать для этого мастер.
Для начала настроим MySQL на второй реплике и убедимся, что мы внесли нужные параметры в конфиг:
server-id = 3
replicate-do-db = testdb

Теперь остановим репликацию на первой реплике:
mysql@replica-1> stop slave;

Реплика продолжит работать нормально, однако данные на ней уже не будут актуальными. Посмотрим статус и запомним позицию мастера, до которой реплика дошла перед остановкой репликации:
mysql@replica-1> SHOW SLAVE STATUSG

Нам нужные будет значения Master_Log_File и Exec_Master_Log_Pos:
Master_Log_File: mysql-bin.000004
Exec_Master_Log_Pos: 155

Создадим дамп БД и продолжим репликацию на первой реплике:
mysql@replica-1> START SLAVE;

Восстановим данные из дампа на второй реплике. Затем включим репликацию:
mysql@replica-2> CHANGE MASTER TO MASTER_HOST = "192.168.1.101 ", MASTER_USER = "replication ", MASTER_PASSWORD = "password ", MASTER_LOG_FILE = "mysql-bin.000004 ", MASTER_LOG_POS = 155;
mysql@replica-2> START SLAVE;

Значения MASTER_LOG_FILE и MASTER_LOG_POS — это соответственно значения Master_Log_File и Exec_Master_Log_Pos из результата команды «show slave status » на первой реплике.
Репликация должна начаться с той позиции, на которой была остановлена первая реплика (и соответственно, создан дамп). Таким образом, у нас будет две реплики с идентичными данными.

Объединяем реплики

Иногда возникает такая ситуация: на мастере существует две БД, одна из которых реплицируется на одной реплике, а вторая — на другой. Как настроить репликацию двух БД на обеих репликах, не делая их дампы на мастере и не выключая его из работы? Достаточно просто, с использованием команды "start slave until ".
Итак, у нас имеется master с базами данных testdb1 и testdb2, которые реплицируются соответственно на репликах replica-1 и replica-2. Настроим репликацию обеих БД на replica-1 без остановки мастера.
Остановим репликацию на replica-2 командой и запомним позицию мастера:
mysql@replica-2> STOP SLAVE;
mysql@replica-2> SHOW SLAVE STATUSG
Master_Log_File: mysql-bin.000015
Exec_Master_Log_Pos: 231

Создадим дамп БД testdb2 и возобновим репликацию (на этом манипуляции с replica-2 закончились). Дамп восстановим на replica-1.

Ситуация на replica-1 такая: БД testdb1 находится на одной позиции мастера и продолжает реплицироваться, БД testdb2 восстановлена из дампа с другой позиции. Синхронизируем их.

Остановим репликацию и запомним позицию мастера:
mysql@replica-1> STOP SLAVE;
mysql@replica-1> SHOW SLAVE STATUSG
Master_Log_File: mysql-bin.000016

Exec_Master_Log_Pos: 501

Убедимся, что в конфиге на replica-1 в секции [mysqld] указано имя второй БД:
replicate-do-db = testdb2

Перезагрузим MySQL, чтобы изменения в конфиге вступили в силу. Кстати, можно было просто перезагрузить MySQL, не останавливая репликацию — из лога мы бы узнали, на какой позиции мастера репликация остановилась.

Теперь проведем репликацию с позиции, на которой была приостановлена replica-2 до позиции, на которой мы только что приостановили репликацию:
mysql@replica-1> CHANGE MASTER TO MASTER_HOST = "192.168.1.101 ", MASTER_USER = "replication ", MASTER_PASSWORD = "password ", MASTER_LOG_FILE = "mysql-bin.000015 ", MASTER_LOG_POS = 231;
mysql@replica-1> start slave until MASTER_LOG_FILE = "mysql-bin.000016 ", MASTER_LOG_POS = 501;

Репликация закончится, как только реплика дойдет до указанной позиции в секции until, после чего обе наши БД будут соответствовать одной и той же позиции мастера (на которой мы остановили репликацию на replica-1). Убедимся в этом:
mysql@replica-1> SHOW SLAVE STATUSG
mysql@replica-1> START SLAVE;
Master_Log_File: mysql-bin.000016
Exec_Master_Log_Pos: 501

Добавим в конфиг на replica-1 в секции [mysqld] имена обеих БД:
replicate-do-db = testdb1
replicate-do-db = testdb2

Важно: каждая БД должна быть указана на отдельной строке.
Перезагрузим MySQL и продолжим репликацию:
mysql@replica-1> CHANGE MASTER TO MASTER_HOST = "192.168.1.101 ", MASTER_USER = "replication ", MASTER_PASSWORD = "password ", MASTER_LOG_FILE = "mysql-bin.000016 ", MASTER_LOG_POS = 501;
После того, как replica-1 догонит мастер, содержание их БД будет идентично. Объединить БД на replica-2 можно или подобным образом, или сделав полный дамп replica-1.

Рокировка мастера и реплики

Переключить реплику в режим мастера бывает необходимо, например, в случае отказа мастера или при проведении на нем технических работ. Для возможности такого переключения необходимо настроить реплику подобно мастеру, или сделать её пассивным мастером.

Включим ведение бинарных логов (дополнительно к relay-бинлогам) в конфиге в секции [mysqld]:
log-bin = /var/lib/mysql/mysql-bin

И добавим пользователя для ведения репликации:
mysql@master> GRANT replication slave ON ’testdb’.* TO ’replication’@’192.168.1.101′ IDENTIFIED BY "password ";

Пассивный мастер ведет репликацию как и обычная реплика, но кроме этого создает бинарные логии — то есть, мы можем начать репликацию с него. Убедимся в этом командой "show master status ":
mysql@replica> SHOW MASTER STATUSG
File: mysql-bin.000001
Position: 61
Binlog_Do_DB:
Binlog_Ignore_DB:

Теперь, чтобы перевести пассивный мастер в активный режим, необходимо остановить репликацию на нем и включить репликацию на бывшем активном мастере. Чтобы в момент переключения данные не были утеряны, активный мастер необходимо заблокировать на запись.
mysql@master> FLUSH TABLES WITH READ LOCK
mysql@master> SET GLOBAL read_only = ON;
mysql@replica> STOP SLAVE;
mysql@replica> SHOW MASTER STATUS;
File: mysql-bin.000001
Position: 61
mysql@master> CHANGE MASTER TO MASTER_HOST = "192.168.1.102 ", MASTER_USER = "replication ", MASTER_PASSWORD = "password ", MASTER_LOG_FILE = "mysql-bin.000001 ", MASTER_LOG_POS = 61;
mysql@master> start slave;

Все, так мы поменяли активный мастер. Можно снять с бывшего мастера блокировку.

Заключение

Мы немного разобрались в том, как настраивать репликацию в MySQL и выполнять некоторые основные операции. К сожалению, за рамками статьи остались следующие важные вопросы:

  • устранение единичных точек отказа (SPF, Single Points of Failure). При использовании единственного сервера MySQL, его отказ приводил к отказу всей системы. При использовании нескольких серверов, отказ любого из них приведет к отказу системы, если только мы специально не позаботимся об этом. Нам нужно предусмотреть обработку ситуации с отказом мастера и реплики. Одно из существующих средств — MMM, однако, требует доработки напильником.
  • балансировка нагрузки. При использовании нескольких реплик нам было бы удобно использовать прозрачный механизм балансировки, особенно если производительность реплик неодинакова. Под Linux возможно использовать стандартное решение — LVS.
  • изменение логики работы приложения. В идеальной ситуации, запросы на чтение данных надо направлять на реплики, а на изменение — на мастер. Однако, из-за возможного отставания реплик, такая схема часто неработоспособна и необходимо выявлять такие запросы на чтение, которые все же должны выполнятся на мастере.

Надеюсь осветить эти вопросы в дальнейших статьях.
Спасибо за внимание!

habr.com

1. Как работает репликация MySQL

Процесс репликации состоит из трех основных фаз:

  1. происходит добавление записи в бинарный лог на мастере;
  2. добавленные записи копируются из лога мастера слэйв-сервером в свой лог;
  3. слэйв реплицирует свой лог в свою базу данных.

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

2. Как конфигурировать master/slave

Для настройки репликации необходимо:

  1. на каждом сервере настроить репликационный аккаунт;
  2. сконфигурировать мастер и слэйв;
  3. настроить на слэйве коннект и репликацию.

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

mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.*  -> TO repl@'192.168.0.%' IDENTIFIED BY 'p4ssword';

На мастере нужно сделать изменения в конфиге my.cnf:

 log_bin = mysql-bin  server_id = 10

Перезапускаем мастера и выполняем команду SHOW MASTER STATUS:

mysql> SHOW MASTER STATUS; +------------------+----------+ | File | Position | +------------------+----------+ | mysql-bin.000001 | 98 | ...

На слэйве делаем аналогичные настройки в конфиге:

log_bin = mysql-bin server_id = 2 relay_log = mysql-relay-bin log_slave_updates = 1 read_only = 1

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

3. Запуск slave

Для запуска процесса репликации на слэйве нужно запустить команду:

mysql> CHANGE MASTER TO MASTER_HOST='server1',  -> MASTER_USER='repl',  -> MASTER_PASSWORD='p4ssword',  -> MASTER_LOG_FILE='mysql-bin.000001',  -> MASTER_LOG_POS=0;

После этого нужно сделать проверку:

mysql> SHOW SLAVE STATUSG ********************* 1. row *******************  Slave_IO_State:  Master_Host: server1  Master_User: repl  Master_Port: 3306  Connect_Retry: 60  Master_Log_File: mysql-bin.000001  Read_Master_Log_Pos: 4  Relay_Log_File: mysql-relay-bin.000001  Relay_Log_Pos: 4 Relay_Master_Log_File: mysql-bin.000001

Теперь запускаем репликацию:

mysql> START SLAVE;

Проверка:

mysql> SHOW SLAVE STATUSG *************************** 1. row ***************************  Slave_IO_State: Waiting for master to send event  Master_Host: server1  Master_User: repl  Master_Port: 3306  Connect_Retry: 60  Master_Log_File: mysql-bin.000001  Read_Master_Log_Pos: 164  Relay_Log_File: mysql-relay-bin.000001  Relay_Log_Pos: 164  Relay_Master_Log_File: mysql-bin.000001  Slave_IO_Running: Yes  Slave_SQL_Running: Yes

Запущен реплицирующий тред, который ждет сообщений от мастера. Если на мастере произойдут изменения, мы это увидим, запустив повторно команду SHOW SLAVE STATUS.

На мастере и на слэйве можно запустить команду, которая покажет информацию о тредах:

mysql> SHOW PROCESSLISTG

Для мастера рекомендуется в конфиге поставить параметр:

 sync_binlog=1

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

В качестве основного движка базы данных рекомендуется InnoDB. Что касается MyISAM, то он может вести себя некорректно при остановках на слэйве. Для InnoDB рекомендуются следующие конфигурационные настройки мастера:

innodb_flush_logs_at_trx_commit=1 # синхронизация всех коммитов на диск innodb_support_xa=1 # начиная с версии MySQL 5.0 innodb_safe_binlog # только для версии MySQL 4.1

Для слэйва рекомендуется установить следующие конфигурационные параметры: первая опция предотвращает автоматический рестарт слэйва после остановки, вторая не дает возможности обычным пользователям делать изменения на слэйве:

skip_slave_start read_only

4. Различия в репликации

MySQL, включая версию 5.0, поддерживает только логическую (statement-based) репликацию. Когда слэйв реплицирует данные, фактически он выполняет тот же самый SQL-запрос, который выполнял мастер. У этого метода есть свои преимущества – он прост в реализации, размер лога при этом компактен. Но есть и недостатки: время выполнения запросов на мастере и на слэйве может сильно различаться. Некоторые выражения не реплицируются корректно, например функция CURRENT_USER(). Есть также проблемы с триггерами и хранимыми процедурами.

В версии 5.1 появится поддержка построчной (row-based) репликации. Преимущество этого варианта в том, что каждое выражение может быть реплицировано корректно и эффективно. При этом может возрасти размер лога, который уже нельзя будет инспектировать с помощью утилиты mysqlbinlog.

Почему построчная репликация эффективней? Возьмем пример для инсерта, который выбирает суммарный итог из очень большой таблицы:

mysql> INSERT INTO global_table(col1, col2, sum_col3)  -> SELECT col1, col2, sum(col3)  -> FROM my_table  -> GROUP BY col1, col2;

Будет просканировано огромное количество строк в исходной таблице, а результат уместится всего в три строки. Логический репликатор запустит на слэйве эту команду целиком, а построчный просто добавит результат.

Зато, с другой стороны, если взять выражение:

 mysql> UPDATE enormous_table SET col1 = 0;

то в этом случае для очень большой таблицы построчная репликация приведет к очень большому росту лога и будет неэффективной.

В версии 5.1 будет динамическое переключение между логической и построчной репликациями. По умолчанию будет применяться логическая репликация, это можно настраивать с помощью параметра binlog_format.

5. Топологии репликации

В MySQL для репликации есть несколько правил, независимо от их топологии: мастер может иметь несколько слэйвов; у каждого слэйва может быть только один мастер, т.е. multimaster не поддерживается.

Существует несколько топологических вариантов.

  1. Мастер и несколько слэйвов.
  2. Мастер-мастер в режиме active-active.
  3. Мастер-мастер в режиме active-passive.
  4. Мастер-мастер и несколько слэйвов.
  5. Кольцо.
  6. Дерево или пирамида.

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

Тут можно реализовать следующие идеи:

  • – каждый слэйв исполняет свою роль – например, выборочное индексирование;
  • использовать слэйв для аварийного восстановления;
  • использовать слэйв для бэкапа или разработки.

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

Мастер-мастер и несколько слэйвов: здесь можно назначить один или более слэйвов на каждый мастер. Эта схема уменьшает трафик между мастером и слэйвом.

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

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

Заключение

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

Последнюю статью цикла мы посвятим обобщению предыдущих материалов и подведению итогов.

www.ibm.com

Проблемы восстановления

Восстановление баз данных MySQL в режиме репликации Master-to-Slave может представлять известные трудности. Эта операция отличается от типичного восстановления MySQL тем, что работает с множеством БД вместо одной.

Если Slave-сервер подвергся аварийной остановке, вам необходимо просто повторить на нём настройку БД в Slave-режиме, описанную ранее. Сделайте бэкап базы данных на Master-сервере, смените механизм хранения, восстановите БД на Slave-сервере и разрешите репликацию; этого будет достаточно.

Гораздо сложнее восстановление в случае аварии или падения Master-сервера. Во многих случаях вы не сможете использовать ваши БД в режиме “только для чтения”, поэтому просто переключите один из Slave-серверов в режим Master. Чтобы сделать это, выполните следующие операции:

  1. Выберите Slave-сервер MySQL для перевода в Master-режим.
  2. Используйте операторы STOP SLAVE и RESET MASTER, чтобы запустить выбранную базу данных в автономном режиме.
  3. На всех остальных Slave-серверах используйте оператор STOP SLAVE IO_THREAD, чтобы завершить необработанные операции синхронизации с предыдущим Master-сервером.
  4. Далее используйте оператор CHANGE MASTER TO с верными параметрами, и выполните операцию START SLAVE, чтобы запустить процесс репликации с нового Master-сервера на Slave-серверы.

Использование Slave-сервера в качестве Master-сервера является временной мерой, так как механизм хранения данных MyISAM оптимизирован для чтения и очень медленно исполняет операции изменения и добавления данных. Поэтому рекомендуется восстановить функциональность предыдущего Master-сервера так быстро, как только возможно.

  1. Сделайте заново бэкап одного из Slave-серверов MySQL. По соображениям производительности, не следует использовать для этого временный Master-сервер (но если он остался единственным работающим сервером, такое падение производительности всё же лучше, чем остановка операций системы).

Внимание: Для эффективного бэкапа MySQL попробуйте наше ПО – скачайте Handy Backup прямо сейчас!

  1. Модифицируйте дамп-файл, созданный программой бэкапа, изменив механизм хранения данных в таблицах на тот, что использовался в базе данных Master-сервера.
  2. Выполните процедуру восстановления.
  3. Повторите шаги 1-4, как если бы Master-сервер (предыдущий Slave) упал и у вас возникла бы необходимость установить восстановленную БД в качестве новой Master.

www.handybackup.ru

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

Для чего можно использовать репликацию:
1. Распределение нагрузки между хостами для повышения производительности.
В такой схеме главный узел будет выполнять операции чтения и записи, узлы имеющие подписку на главном узле будут предоставлять базу для чтения, таким образом, мы разгрузим мастер сервер от операций чтения
2. Безопасность данных и удобство обслуживания, поскольку подчиненный узел содержит данные только для чтения, то изменение данных на подписчике будет ограничено, удобство обслуживания – возможность запускать процессы обслуживающие базу не прерывая работу приложений
3. Распределение данных на большие расстояния. Можно создать копию данных  на любом хосте в независимости от его местоположения
Mysql поддерживает следующие методы репликации:
Традиционный — метод основан на тиражировании событий из бинарного файла лога мастера и требует файлы логов. Позиции между ведущим и ведомым серверами должны быть синхронизированы.
Метод с использованием глобальных идентификаторов транзакций GTIDs (транзакционный метод)
Mysql поддерживает следующие типы синхронизации:
асинхронную (односторонняя синхронизация)
полусинхронную (частичный контроль подписчиков)
синхронную (полный контроль подписчиков)

Настройка репликации баз данных Mysql традиционный метод

Принцип работы
Мастер сервер содержит bin файлы логов, в которые записываются все изменения, происходящие в базе данных мастера, файл описывающий имена bin файлов, а также позицию в журнале где были записаны последние данные мастера
Подчиненный узел получает данные, с мастера имея информацию об именах bin файлов и позиции в файле лога.

Настройка Мастера
my.ini должен содержать уникальный идентификатор – число от 1 до 2 в 32 степени – 1, server-id.
По умолчанию server-id=0, что означает не принимать подписки от подчиненных серверов
[mysqld]
log-bin=mysql-bin
server-id=1

Этих двух строк достаточно для запуска
Примечание: однако если используется InnoDB, то дополнительно рекомендуется внести
innodb_flush_log_at_trx_commit=1
sync_binlog=1

И нужно проверить, что не отключена возможность работать с сетью не выставлен параметр skip-networking
Ведомый сервер подключается к главному, используя имя пользователя и пароль, поэтому на мастер сервере предварительно создаем пользователя
CREATE USER repl@%.mydomain.com IDENTIFIED BY slavepass;
GRANT REPLICATION SLAVE ON *.* TO repl@%.mydomain.com;

Смотрим состояние
SHOW MASTER STATUS
Если ранее уже была запущена процедура создания бинарных журналов, то для таблиц InnoDB, предварительно в одном из сеансов нужно залочить таблицы
FLUSH TABLES WITH READ LOCK;
Если выйти из сеанса, то блокировка таблиц автоматически снимается
В другом сеансе получаем значения имени bin лога и позицию
Оба значения представляют собой координаты репликации при которых ведомый сервер должен начать чтение из файла в нужном месте, чтобы начать репликацию.
Следующий шаг зависит от того есть ли данные на ведомом сервере, данные от мастера
Если они есть, то оставляем таблицы залоченными, создаем dump (это рекомендуемый способ при использовании InnoDB)
Узнать тип базы можно командой
mysqlshow -u mysql_user -p -i database-name
Если база хранится в бинарных файлах, то допускается их копирование с ведущего на ведомый сервер
Делаем dump
mysqldump —all-databases —master-data dbdump.db
для выбора баз mysqldump —databases —master-data dbdump.db
Параметр master-data, автоматически добавляет CHANGE MASTER TO на подчиненном узле, если параметр не добавлять, то необходимо блокировать все таблицы в сессии в ручную
Снять блокировку
UNLOCK TABLES;

Настройка ведомого узла
Добавляем в my.ini server-id от личный от мастера и от других узлов
[mysqld]
server-id=2

Создаем подписку
CHANGE MASTER TO
MASTER_HOST=master_host_name,
MASTER_USER=replication_user_name,
MASTER_PASSWORD=replication_password,
MASTER_LOG_FILE=recorded_log_file_name,
MASTER_LOG_POS=recorded_log_position;

При настройке репликации с существующими данными нужно передать снимок от ведущего к ведомому перед началом репликации
Используем mysqldump
1.Запускаем подчиненный узел используя —skip-slave-start параметр, чтобы репликация не запускалась
2.Импортируем файл дампа
mysql fulldb.dump
3. Запускаем процесс подписки
START SLAVE;
Проверка состояния репликации
SHOW SLAVE STATUSG
Slave_IO_State: — текущее состояние ведомого устройства
Slave_IO_Running: — читается ли поток данных с мастера
Slave_SQL_Running: — работают ли sql запросы , должно быть yes

Пример Настроим Мастер (ведущий) сервер – ip 11.11.11.10 В my.ini
[
mysqld] log-bin=mysql-bin server-id=1
Создаем пользователя mysql -u root -p GRANT REPLICATION SLAVE ON *.* TO replica@% IDENTIFIED BY password; FLUSH PRIVILEGES;
Далее блокируем все таблицы в базе данных FLUSH TABLES WITH READ LOCK;
Смотрим статус SHOW MASTER STATUS; Запоминаем имя файла и позицию, их будем мы будем использовать на Ведомом сервере для подписки

На Слейве В my.ini
[mysqld] log-bin=mysql-bin server-id=2

Создаем подписку CHANGE MASTER TO MASTER_HOST=11.11.11.10, MASTER_PORT=3306,
MASTER_USER=replica, MASTER_PASSWORD=password,
MASTER_LOG_FILE=server-mysql-bin.000002,
MASTER_LOG_POS=1151664, MASTER_CONNECT_RETRY=10;
START SLAVE;
Статус репликации SHOW SLAVE STATUSG

Репликация Mysql в режиме Master-Master настраиваем аналогично только в обе стороны, каждый сервер будет Slave и Master  

CHANGE MASTER TO MASTER_LOG_FILE=’‘, MASTER_LOG_POS=;

www.shkerka.ru

ЧТО ТАКОЕ MARIADB GALERA?

MariaDB Galera — это кластерная система для MariaDB типа master-master. Начиная с MariaDB 10.1 программное обеспечение Galera Server и MariaDB Server поставляются в одном пакете, так что вы получаете все необходимое программное обеспечение сразу. На данный момент MariaDB Galera может работать только с движками баз данных InnoDB и XtraDB. Из преимуществ использования репликации можно отметить добавление избыточности для базы данных сайта. Если одна из баз данных, даст сбой, то вы сразу же сможете переключиться на другой. Все сервера поддерживают синхронизированное состояние между собой и гарантируют отсутствие потерянных транзакций.

Основные возможности MariaDB Galera:

  • Репликация с постоянной синхронизацией;
  • Автоматическое объединение узлов;
  • Возможность подключения нескольких узлов master;
  • Поддержка записи на любой из узлов;
  • Прозрачная параллельная репликация;
  • Масштабируемость чтения и записи, минимальные задержки;
  • Давшие сбой ноды автоматически отключаются от кластера;
  • Нельзя блокировать доступ к таблицам.

Дальше перейдем ближе к настройке MariaDB Galera.

НАСТРОЙКА РЕПЛИКАЦИИ MYSQL

В этой инструкции мы будем использовать для примера Ubuntu 16.04 и MariaDB версии 10.1. Перед тем, как начать полностью обновите систему:

sudo apt-get update -y
sudo apt-get upgrade -y

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

sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8

sudo add-apt-repository 'deb [arch=amd64,i386,ppc64el] http://ftp.utexas.edu/mariadb/repo/10.1/ubuntu xenial main'

sudo apt-get update -y

Репликация mysql

Когда обновление списка пакетов завершено, установите MariaDB командой:

sudo apt install mariadb-server rsync -y

Репликация mysql

Пакет rsync нам понадобится для выполнения непосредственно синхронизации. Когда установка будет завершена, вам необходимо защитить базу данных с помощью скрипта mysql_secure_installation:

sudo mysql_secure_installation

Репликация mysql

По умолчанию разрешен гостевой вход, есть тестовая база данных, а для пользователя root не задан пароль. Все это надо исправить. Читайте подробнее в статье установка MariaDB в Ubuntu. Если кратко, то вам нужно будет ответить на несколько вопросов:

Enter current password for root (enter for none):
Change the root password? [Y/n] n
Remove anonymous users? [Y/n] Y
Disallow root login remotely? [Y/n] Y
Remove test database and access to it? [Y/n] Y
Reload privilege tables now? [Y/n] Y

Когда все будет готово, можно переходить к настройке нод, между которыми будет выполняться репликация баз данных mysql. Сначала рассмотрим настройку первой ноды. Можно поместить все настройки в my.cnf, но лучше будет создать отдельный файл для этих целей в папке /etc/mysql/conf.d/.

sudo vi /etc/mysql/conf.d/galera.cnf

Добавьте такие строки:

[mysqld]
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
bind-address=0.0.0.0
# Galera Provider Configuration
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
# Galera Cluster Configuration
wsrep_cluster_name="galera_cluster"
wsrep_cluster_address="gcomm://192.168.56.101,192.168.56.102"
# Galera Synchronization Configuration
wsrep_sst_method=rsync
# Galera Node Configuration
wsrep_node_address="192.168.56.101"
wsrep_node_name="Node1"

Репликация mysql

Здесь адрес 192.168.56.101 — это адрес текущей ноды. Дальше перейдите на другой сервер и создайте там такой же файл:

sudo vi /etc/mysql/conf.d/galera.cnf

[mysqld]
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
bind-address=0.0.0.0
# Galera Provider Configuration
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
# Galera Cluster Configuration
wsrep_cluster_name="galera_cluster"
wsrep_cluster_address="gcomm://192.168.56.101,192.168.56.102"
# Galera Synchronization Configuration
wsrep_sst_method=rsync
# Galera Node Configuration
wsrep_node_address="192.168.56.102"
wsrep_node_name="Node2"

Репликация mysql

Аналогично тут адрес ноды — 192.168.0.103. Остановимся на примере с двумя серверами, так как этого достаточно чтобы продемонстрировать работу системы, а добавить еще один сервер вы можете, прописав дополнительный IP адрес в поле wsrep_cluster_address. Теперь рассмотрим что означают значения основных параметров и перейдем к запуску:

  • binlog_format — формат лога, в котором будут сохраняться запросы, значение row сообщает, что там будут храниться двоичные данные;
  • default-storage-engine — движок SQL таблиц, который мы будем использовать;
  • innodb_autoinc_lock_mode — режим работы генератора значений AUTO_INCREMENT;
  • bind-address — ip адрес, на котором программа будет слушать соединения, в нашем случае все ip адреса;
  • wsrep_on — включает репликацию;
  • wsrep_provider — библиотека, с помощью которой будет выполняться репликация;
  • wsrep_cluster_name — имя кластера, должно соответствовать на всех нодах;
  • wsrep_cluster_address — список адресов серверов, между которыми будет выполняться репликация баз данных mysql, через запятую;
  • wsrep_sst_method — транспорт, который будет использоваться для передачи данных;
  • wsrep_node_address — ip адрес текущей ноды;
  • wsrep_node_name — имя текущей ноды.

Настройка репликации MySQL почти завершена. Остался последний штрих перед запуском — это настройка брандмауэра. Сначала включите инструмент управления правилами iptables в Ubuntu — UFW:

sudo ufw enable

Репликация mysql

Затем откройте такие порты:

sudo ufw allow 3306/tcp
sudo ufw allow 4444/tcp
sudo ufw allow 4567/tcp
sudo ufw allow 4568/tcp
sudo ufw allow 4567/udp

Репликация mysql

ЗАПУСК MARIADB GALERA

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

sudo systemctl stop mysql

Дальше запустите скрипт создания нового кластера:

sudo galera_new_cluster

Репликация mysql

Проверить запущен ли кластер и сколько к нему подключено машин можно командой:

mysql -u root -p -e "show status like 'wsrep_cluster_size'"

Репликация mysql

Сейчас там только одна машина, теперь перейдите на другой сервер и запустите ноду там:

sudo systemctl start mysql

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

sudo systemctl status mysql

Репликация mysql

Затем, выполнив ту же команду, вы убедитесь, что новая нода была автоматически добавлена к кластеру:

mysql -u root -p -e "show status like 'wsrep_cluster_size'"

Репликация mysql

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

mysql -u root -p

MariaDB [(none)]> create database test_db;
MariaDB [(none)]> show databases;

Репликация mysql

mysql -u root -p

MariaDB [(none)]> show databases;

Репликация mysql

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

ВЫВОДЫ

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

losst.ru

Андрей Аксенов (Sphinx)

Мой доклад предназначен для тех людей, которые знают слово «репликация», даже знают, что в MySQL она есть, и, возможно, один раз ее настроили, 15 минут потратили и забыли. Больше про нее они не знают ничего.

В докладе не будет:

Все это есть в Интернете, синтаксис разбирать смысла нет.

Мы немного пройдемся по теории, попытаемся объяснить, как это все работает внутри, а после этого вы с утроенными силами сможете сами нырнуть в документацию.

Что такое репликация, в принципе? Это копирование изменений. У нас есть одна копия БД, мы хотим с какой-то целью еще одну копию.

Репликация бывает разных видов. Разные оси сравнения:

  • степень синхронизации изменений (sync, async, semisync);
  • количество серверов записи (M/S, M/M);
  • формат изменений (statement-based (SBR), row-based (RBR), mixed);
  • теоретически, модель передачи изменений (push, pull).

Забавный факт – если немного задуматься, репликация нам теоретически помогает из принципиальных соображений скейлить только чтение. Вот такой несколько неочевидный вывод. Это потому что, если у нас на одну и ту же копию данных надо налить определенное количество изменений, и эта определенная копия данных обслуживается одним и тем же сервером, то этот сервер способен выдержать определенное количество апдейтов в секунду, и больше туда не залить. Способен сервер обновить 1000 записей в секунду, а 2000 – не способен. Что изменится от того, что ты поставишь к этому серверу реплику, неважно, в режиме мастер-слэйв или мастер-мастер? Сумеешь ты на эту реплику налить вторую тысячу апдейтов? Правильный ответ – нет.

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

Т.е. репликация – это больше про чтение.

Про синхронизацию.

Синхронизация – гарантия наличия и доступности. Доступности в том смысле, что у нас commit прошел, транзакция зафиксировалась, все хорошо, эти данные видно одной или нескольким нодам в кластере, они могут участвовать в следующих запросах. Наличие – это то, что данные, в принципе, есть более чем на одном сервере, но, возможно, транзакция не проигралась и не доступна.

Здесь нет рефрена «commit закончился успешно, что это значит?». Синхронный commit означает, что у нас локальный и удаленный (хотя бы на одной реплике) закончился, т.е. мы что-то закоммитили на машину, если у нас синхронный режим репликации, то эти изменения успешно закоммитились, они видны для последующих запросов на локальной машине, на удаленной машине (хотя бы на одной) тоже видны. Это означает, что если случилась стандартная внештатная ситуация, т.е. в один и серверов прилетел лом и пробил все насквозь – от процессора до самого винта, то, несмотря на это, данные не только скопированы на некий удаленный сервер, но еще, вдобавок, могут мгновенно, без каких-то дополнительных задержек, участвовать в последующих транзакциях.

Это все общая терминология, никак совершенно не связанная с MySQL. В любой распределенной системе оно будет устроено так.

Асинхронный commit – никаких дополнительных гарантий, как повезет.

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

Про сервера для записи. Какие бывают виды репликации.

Master-slave classic, изменения все льются на один сервер, после этого копируются на массу реплик.

Master-master true – когда изменения льются на кучу мастеров одновременно и каким-то образом с одного на другой, с другого на третий и между ними всеми, что порождает и ряд радостей, и ряд автоматических проблем. Понятно, что когда у тебя есть одна «золотая копия» и с нее несколько реплик, которые должны (в идеале – мгновенно) повторять эту «золотую копию», то все сравнительно просто с точки зрения того, как данные туда-сюда гонять и что делать на каждой конкретной копии. С master-master начинается интересная «головная боль», причем, подчеркиваю, не конкретно в случае MySQL, а сугубо теоретическая. Как же быть, если на двух нодах одновременно попытались прогнать одну и ту же транзакцию, которая меняет одни и те же данные, причем, меняет их, для простоты примера, по-разному. Понятно, что одновременно эти два изменения мы применить не можем. На момент, когда мы на одной ноде начинаем что-то изменять, на второй ноде еще пока ничего нет. Конфликт. Одну из транзакций придется откатывать. Вдобавок начинаются отдельные «пляски» со сверкой часов и т.п.

Любопытный момент – даже вариант, когда у вас в конечном итоге все изменения со всех мастеров должны постепенно распространиться везде, все равно не поможет тому самому write bandwidth. Обидно, но вот так.

Приятный вариант – под названием»Master-slave + routing запросов». Приятен он тем, что внутри программировать просто, у тебя есть одна основная копия, ты ее реплицируешь на кучу машин. Это намного проще, чем в мастер-мастер среде, когда все равноправны и т.д., но с точки зрения приложения все равно выглядит так, будто у тебя точек записи много. Ты приходишь на любую ноду, она знает, куда тебя зароутить, и успешно роутит. Ну, и чтения масштабируются – вот оно счастье репликации. Читать можно со всех точек все и всегда.

Теперь ближе к базам данных, «волшебным» форматам statement-based, row-based и т.д. Про формат изменений.

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

Еще один пункт про то, какие бывают репликации. Про модель распространения. Наверное, где-то до сих пор еще не полностью вымерла модель Push-based, когда та нода, которая внесла изменения, та и обязана их рассылать по всем остальным нодам. С точки зрения программирования и отслеживания state’ов это та еще морока. Поэтому рулит Pull-based. Забирать апдейты с той или иной ноды – это намного проще запрограммировать, чем на одной ноде следить за хаотичным кластером своих реплик.

Некие общие термины ввели. Переходим к тому, как сделали в MySQL.

MySQL, сам по себе, это некий обман. Есть логический слой под названием MySQL, который занимается всяким общими и изолированными от хранения данных делами – сеть, оптимизатор, кэши и т.д. Конкретный физический слой, который отвечает за хранение данных, лежит на этаж ниже. Есть несколько встроенных, есть ставящиеся плагинами. Но даже встроенные MyISAM, InnoDB и т.д. живут на физическом слое. Плагинная архитектура – это клево, можно подцепить новый движок, но мгновенно возникает некая неоптимальность. В принципе, транзакционные write-ahead log’и (WAL), которые физический слой хранения все равно пишет, было бы хорошо использовать для репликации, и если система знает о том, что есть некий физический уровень, или достаточно хорошо сопряжена с этим физическим уровнем, то можно было бы отдельный лог на логическом уровне не писать, а использовать тот же самый WAL. Но у MySQL это невозможно концептуально, либо, если поменять интерфейс в PSE так, чтобы стало возможно концептуально, то будет очень много работы.

Репликация реализована на уровне самого MySQL. В этом есть и хорошее – помимо одного лога в виде глубоко внутренних данных движка хранения, есть более-менее логический лог, возможно, на уровне statement’ов, который ведется отдельно от этого движка. А это «лишняя» безопасность и т.д. плюс, поскольку никаких ограничений внутри нет, можно делать всякий креатив типа подмены движка «на лету».

В веденных терминах в MySQL 4.1 было реализовано: master-slave, pull-based, строго async и строго SBR. Если вы застряли в древней эпохе 4.х, то, наверное, у вас все плохо. Версиям 5.х уже чуть ли не 10 лет – пора бы и обновиться.

Забавно прослеживать по версиям, как люди наступали на всяческие грабли и, когда сделать уже ничего было нельзя, прикручивали к этим граблям новые грабли, чтобы жизнь была не такая болезненная. Так, в версии 5.1 прикрутили RBR, чтобы компенсировать неизбежные проблемы с SBR, и прикрутили mixed режим. В версии 5.6 прикрутили еще приятных штук: semi-sync, delayed slave, GTID.

Еще один момент. Поскольку MySQL – это некий общий слой, с одной стороны, и куча pluggable движков, с другой стороны, в том числе, встроенных, там есть с определенного момента божественный NDB cluster, про который рассказывают крутое. Там полностью синхронная мастер-мастер репликация, очень доступная in-memory БД… Но есть один нюанс – как только начинаешь искать людей, которые в продакшене используют NDB cluster, то таких людей находится крайне мало.

Чем занимается мастер в тот момент, когда вы решили включить репликацию? На мастере происходит довольно мало дополнительных движений. Как обычно, мы по сети принимаем запросы, парсим их, гоняем транзакции, фиксируем их и т.д. Вдобавок к этому, на логическом уровне MySQL мастер начинает вести binary log – файл, не совсем текстовый, в который сыплются все подряд изменения. Также мастер умеет рассылать эти логи по сети. Все это очень просто и, вроде как, работает.

Чем занимается слэйв? Изменения на слэйв лучше не слать, потому что можно попасть в непонятное. У слэйва чуть больше работы. Помимо того, чтобы вести один дополнительный лог и по запросу его рассылать, еще есть тред, который ходит к удаленному мастеру, возможно, даже не к одному, и качает оттуда binary log’и. Решение «давайте ходить к нескольким удаленным мастерам и с них качать разные логи» неоднозначно. С одной стороны неплохо, а с другой получается мгновенное расхождение. Просто физически копировать файлы по SCP нельзя, уже получается на сервере один лог, в нем свои позиции, локально мы их по сетке тянем, складываем в отдельный лог, еще отдельный тред бегает и пытается проигрывать эти локальные логи. Самое адское, на мой взгляд, заключается в том, что вплоть до версии 5.6 идентификация той или иной транзакции в логе происходила по имени файла и позиции на мастере. Интересное решение.

Вот путь записи, который простенький insert проходит без репликации:

Приложение сконнектилось к серверу, положило в таблицу и отбой.

С репликацией получается несколько дополнительных шагов:

Приложение-писатель точно так же идет к мастеру, но вдобавок эти данные попадают в том или ином виде в binary log, потом качаются по сети в relay log, потом из relay log’а постепенно реплеются (если нам повезло, и слэйв не лагает, реплеются сразу) в таблицу на слэйве, после этого все доступно в читателе.

Что конкретно попадает в binary log, зависит от настроек SBR/RBR/mixed. Откуда это все растет? Представим себя базой данных. Нам прилетел простой запрос «обнови одну конкретную запись» – UPDATE users SET x=123 WHERE id=456

Что записать в binary log? В принципе, все равно, на самом деле. Можем коротенький запрос записать, либо (а он обновил одну запись) можем записать изменение каким-то образом в том или ином формате.

Другая ситуация. Представим, что нам прилетел тот самый запрос, который сам по себе маленький, а данных меняет много – UPDATE users SET bonus=bonus+100

Тут эффективный вариант один – писать сам запрос, потому что запрос – ровно 32 байта, а записей он может обновить произвольное количество – 1000, 100 000, 1 000 000, сколько угодно… Неэффективно писать измененные записи в лог.

А что произойдет, если мы в лог поместим такой нехитрый запрос «давайте отключим всех юзеров, которые не логинились давно» – UPDATE users SET disabled=1 WHERE last_login < UNIX_TIMESTAMP(NOW())-100*86400

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

Вообще говоря, для таких запросов, вне зависимости от количества измененных данных, в идеале надо бы копировать сами строчки. В данном конкретном случае можно сами строчки не копировать, а зафиксировать константу и в лог написать не «NOW», а конкретный timestamp, который был использован мастером на момент репликации.

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

  • мастер многопоточен, а слэйв – нет. Понятно, что если мастер наливает нагрузку в четыре ядра, слэйв эту нагрузку в одно ядро наливать не успевает. Все довольно плохо;
  • состояние слэйва определяется именем позиции в файле мастера. Вдумайтесь – состояние одной ноды в кластере определяется именем файла и позицией в этом файле на другой ноде кластера, с которой может по любым причинам произойти что угодно!
  • «спасительный» RBR. Оказывается, по умолчанию туда пишутся полные before/after row image, т.е. мы изменили одну колонку в пяти-килобайтной строке, оп! – 10 Кб трафика и байтов 20-40 оверхедов на эту строку, потом оп! – едет такая жирная строка предыдущей версии, оп! – едет после этого версия с новыми значениями. Администраторы воют хором! Тем не менее, это просто офигенно с точки зрения некоторых извращенных приложений, например, внешних читалок, которые пытаются подцепиться к серверу MySQL, с него вытягивать данные и делать с ними что-нибудь, например, совать их в полнотекстовый индекс. Насколько это плохо с точки зрения администрирования базы, в которой одно изменение на три байта порождает 10 Кб трафика на винте, а потом 10 Кб трафика по сети на каждого слэйва, настолько же это хорошо для всяких систем типа полнотекстового поиска, как Sphinx, у которых нет локальной копии данных, а MySQL с нуля имплементировать нет никакого желания. В MySQL 5.6 спохватились и сделали binlog_row_image (но по дефолту full, а не minimal или noblob).

Короче говоря, устроено все не хитро – палка, веревка, один лог, второй лог. И даже в этом логе «детские» болезни довольно забавные:

Для человека, который использует репликацию два дня, все это страшно и тяжело. Но, зная, насколько она нехитро устроена, в принципе, понятно, как с ней жить:

  • прежде всего, не верим дефолтам;
  • внимательно смотрим на настройки, думаем, чего хотим – SBR, RBR и т.д.

И лучше сразу настроить, чтобы потом не разбирать странный фарш.

В ситуации «протух лог, разошлась позиция, неизвестно, что происходит» есть определенный инструментарий – смотрим event’ы, пытаемся понять, какая транзакция уже проскочила, какая – нет, можно ли все это дело спасти или восстановить и т.д. Если GTID»ы заранее сумели включить, то жизнь становится проще.

Другой момент наблюдения за репликацией. Интересно посмотреть, как внутреннее кривое устройство провоцирует не то, что конкуренцию, а создание дополнительных продуктов. «Волшебный» Tungsten Replicator, говорят, хорошо решает задачу под названием «однопоточный слэйв – это плохо», а если бы не врожденные сложности, не было бы дополнительного продукта, который позволяет пользоваться этим механизмом, переливать данные в другие системы, с одной стороны, и заодно решать ряд проблем, встроенных в существующую систему, с другой стороны.

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

Что делать, если вы зачем-то использовали реплики как бэкап? Я считаю, надо биться головой об стену, потому что реплика и бэкап – это две разные штуки. Тем не менее, если вы креативные пацаны и используете достаточно новую версию, delayed replication вас спасает, с одной стороны, но с другой стороны, если вы не делаете полноценных бэкапов, вас все равно ничего не спасет.

Далее еще один элемент креатива. Нетрудно представить ситуацию, когда мастер забил логами весь 10 PB облачный диск или забил рассылкой этих логов всю сеть, при этом 90% этих обновлений нам не нужны, потому что нам интересно реплицировать, например, одну таблицу прицельно или одну базу прицельно, а по умолчанию все валится валом в бинарный лог – все изменения по всем базам, по всем таблицам, по всему. Решение опять поражает своей креативностью. С одной стороны, есть четыре настройки – {binlog|replicate}_{do|ignore}_db, которые позволяют фильтровать на мастере – что запишется в лог, а что проигнорируется. На слэйве, соответственно, позволяет делать то же самое. Т.е. на мастере мы можем отфильтровать то, что попадает в binary log – в эту воронку, которая потом сливается в сеть, а на слэйве, соответственно, мы можем поставить входящий фильтр на то, что прилетает из сети. Или писать на диск только часть данных, а потом на слэйве реплеить, опять же, только часть данных. Внезапно даже в этой нехитрой истории наступает ужас, потому что комбинация – используем одну БД, а апдейтим таблицу в другой БД через интересный синтаксис – она ведет себя как-то… А как конкретно она себя поведет – неизвестно, т.к. разные фильтры срабатывают в разные моменты.

Встроенных приятных штук под названием «перевыборы мастера, если он внезапно сдох» нет, надо поднимать руками. Отсутствие инструментов для менеджмента кластера – это, по моему мнению, хорошо – порождает конкуренцию, порождает создание дополнительных продуктов. В самом деле, если бы в обычном MySQL идеально работала очень клевая мастер-мастер репликация, или хотя бы автоматическое поднятие после сбоев, то зачем бы была нужна всякая Galera, Рercona/MariaDB Cluster и т.д.?

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

Конфигурация №1. Мастер-мастер «на коленке» в стиле MySQL делается вот так:

Что пугает – сколько в мире идиотов! Погуглите «Мастер-мастер MySQL репликация» – каждая вторая ссылка вот такая. Ад и холокост.

Фокус №2 – catch-all slave – поприятнее. Никаких ненужных проверок нет – что с кого прилетает, кому попадает, и что с этим делать. За счет этого можно сделать забавные штуки типа слэйва, на который либо прицельно сливается часть данных с кучи серверов, либо прицельно сливаются все данные со всех серверов – сервер со всеми-всеми бэкапами. Но, повторюсь, репликация есть, т.е. есть некий базовый инструмент, который копирует таблицу А вместо В и все.

Ну и, наконец, фокус №3 – подменяем всякое. Вспоминаем, что репликация живет на логическом уровне, никак не связанном с физическим уровнем хранения. За счет этого можно крайне интересно чудить. Можно менять движок «на лету» с непонятными целями – вот true story, что, дескать, репликация из InnoDB баз в MyISAM таблицы просто ради того, чтобы полнотекстовый поиск работал хоть как-то. Есть креативный финт под названием «изменение схемы через репликацию». В чем жир, понимать отказываюсь, но бывают и такие фокусы. Ну и, есть понятный и интересный режим работы под названием «параноидальный апгрейд версии через репликацию».

В ходе доклада мы узнали:

Тем не менее, с этим адом можно жить, если хотя бы примерно понимать, как он устроен.

Основной посыл в том, что:

highload.guide


You May Also Like

About the Author: admind

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.