Master-Master репликация в MySQL/MariaDB

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


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

Сама по себе репликация бывает двух видов: «Master» и «Slave». В режиме «Master» сервер считается главным и отдает данные об изменениях в структуре и данных БД, режим же «Slave» заставляет сервер принимать данные от главного сервера и приводить БД в соответствие с журналами главного. Кстати, один и тот же сервер может быть одновременно и главным, и ведомым, такой режим называется «Master-Master» и именно о нем я буду говорить дальше.

Рассмотрим, какие исходные данные мы имеем. У нас есть головной сервер в Америке с IP-адресом (для примера) 123.45.67.89 и ведомый в Екатеринбурге по адресу 87.65.43.210. Записи в базу данных нужно будет вносить с обоих серверов, при этом записи должны синхронизироваться и то, что внесено в американскую базу, должно немедленно появляться в Екатеринбурге (и наоборот). Поскольку MySQL-сервер на ведомом сервере мы запускаем только ради одной базы данных, он будет доступен только из локальной сети, но при этом адрес 127.0.0.1 для него не подходит, так как головной сервер не сможет к нему подключиться для снятия данных обновлений. Открываем my.cnf на ведомом сервере и вместо хоста указываем в директиве «bind-address» значение 0.0.0.0. После перезагрузки наш ведомый сервер оказывается доступным из сети Интернет, но нас такое дело не устраивает, поэтому заходим в /etc/rc.local и добавляем правила iptables, которые предотвратят подключение к серверу тех, кому это не положено.

iptables -A INPUT -s 127.0.0.1 -p tcp --dport 6800 -j ACCEPT
iptables -A INPUT -s 123.45.67.89 -p tcp --dport 6800 -j ACCEPT
iptables -A INPUT -p tcp --dport 6800 -j DROP

Данное правило позволит подключаться к MySQL-серверу локально и с адреса головного сервера, но все остальные подключения будут сброшены. Кстати, в данном примере SQL-сервер работает на порту 6800, у вас же, вероятно, будет 3306 (но я не рекомендую использовать стандартные порты, поскольку они привлекают наибольшее внимание со стороны злоумышленников). Теперь переключимся на головной сервер. Для корректной работы репликации, нам понадобится немного подкорректировать файл /etc/my.cnf (/etc/mysql/my.cnf):

server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
max_binlog_size = 100M
replicate-do-db = clients_data
replicate-do-db = clients_orders

В первой строке мы объявляем номер сервера для порядка (может быть каким угодно, нумерация никем не проверяется), далее адрес файла, в который будут записываться действия на сервере, максимальный размер журнала (если у вас нет большой нагрузки на реплицируемые базы данных, нет смысла вести большой журнал) и базы данных, которые нужно будет синхронизировать. Обратите внимание на то, что базы данных указываются каждая отдельно, а не через запятую. В нашем случае это сделано для того, чтобы синхронизировать только нужные базы данных, ибо головной сервер занимает на диске более 200Гб пространства и гонять ненужную информацию по сети совершенно ни к чему. Существует еще директива «binlog_ignore_db», имеющая обратный эффект: синхронизации будут подлежать все базы данных на сервере, кроме заявленных при помощи данной директивы. На ведомом сервере делаем все то же самое, но меняем номер сервера.

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

create user 'rpl_user1'@'IP-адрес' identified by 'rpl_password1';
grant replication slave on *.* to 'rpl_user1'@'IP-адрес';

На примере выше «rpl_user1» — имя пользователя (1 и 2 — номера серверов для наглядности),
«rpl_password1» — пароль пользователя. Также я выделил «IP-адрес». Обратите внимание на то, что создавая пользователя на первом сервере, вам нужно указать IP-адрес второго и, соответственно, наоборот для второго. Также следует повторить те же действия, но вместо IP-адреса указать имя хоста, соответствующее IP-адресу (например, ip-89-67.my-office-network.net, или как там ваш провайдер свои хосты обзывает). Пароли и имена пользователей могут как различаться, так и быть одинаковыми — никакой роли это не играет, да и не вам под этими паролями заходить, а автоматике.

Вы ведь еще подключены к MySQL-серверам? Теперь заходите на них поочередно и вводите следующую команду:

SHOW MASTER STATUS;

Через phpMyAdmin это не выполнится, но зато есть вкладка «Репликация» и статус головного сервера. В ответ получаем текущую позицию в журнале. Нам нужно синхронизировать только актуальную информацию, поэтому запоминаем данные из столбцов «File» и «Position». Когда информация собрана, начинаем готовить сам процесс репликации. Для этого останавливаем режим «Slave»:

SLAVE STOP;

и набираем следующую команду:

CHANGE MASTER TO MASTER_HOST = '123.45.67.89', MASTER_PORT = 6800, MASTER_USER = 'rpl_user1', MASTER_PASSWORD = 'rpl_password1', MASTER_LOG_FILE = 'mysql-bin.000001', MASTER_LOG_POS = 100;

В данном примере «MASTER_HOST» — IP-адрес того сервера, с которого нужно копировать действия, «MASTER_PORT» — порт MySQL на этом сервере (если 3306, то директиву можно опустить), «MASTER_USER» и «MASTER_PASSWORD» — имя пользователя и пароль к учетной записи пользователя MySQL, которого мы создавали на том сервере, которому принадлежит IP-адрес из директивы «MASTER_HOST», «MASTER_LOG_FILE» и «MASTER_LOG_POS» — параметры, которые мы получили на предыдущем шаге с того сервера, которому принадлежит IP-адрес из директивы «MASTER_HOST». После этого запускаем режим «Slave»:

SLAVE START;

За ходом репликации вы можете следить при помощи команды

SHOW SLAVE STATUS;

В выводе этой директивы также будут отображаться все ошибки, которые будут происходить при попытках подключения к удаленному серверу. Эти данные можно также увидеть во вкладке «Репликация» в phpMyAdmin.

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


31.10.2015, 23:41
  SQL, MySQL, MariaDB, репликация.
Просмотров: 3001.