MySQL
Distributed systems
October 2011 24

MySQL репликация one-slave-multi-master

From Sandbox

Предисловие.


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

Собственно, решение.
Мастер-серверы настраиваются как при обычной репликации. Все колдовство со слэйвом.
Репликация с каждого мастера производится отдельными вспомогательными процессами mysqld. Таблицы в целевой базе работают на движке FEDERATED и подключены к базам основного процесса mysqld.
Если вы знакомы с mysql_multi и federated, то на этом, в общем-то, все. Далее немного тонкостей реализации и полезностей.

Настраивался слэйв с ubuntu-server 10.04.

mysqld_multi

Не буду описывать основную настройку mysqld_multi, да ее и нет таковой. В /usr/share/mysql/mysqld_multi.server есть init.d скрипт.
Настройки mysqld_multi лучше делать в отдельном файле, так как для управления демонами скрипту нужны имя пользователя и пароля для доступа к серверам.
Так же чтобы иметь общии настройки для всех процессов репликации оставляем секцию mysqld.
Для каждой реплицируемой базы создаем секцию mysqldN с настройками сервера и репликации. И нужно не забыть включить federated.

$sudo cp /etc/mysql/my.cnf /etc/mysql/my_multi.cnf
$sudo chmod 600 /etc/mysql/my_multi.cnf

редактируем:
[mysqld_multi]
log = /var/log/mysql/mysqld_multi.log
mysqld = /usr/sbin/mysqld
mysqladmin = /usr/bin/mysqladmin
user = root
password = pass

[mysqld1]
datadir = /var/lib/mysql_multi/mysql1
#datadir = /var/lib/mysql_multi
socket = /var/run/mysqld/mysqld1.sock
port = 33061
tmpdir = /var/tmp/mysql/mysqld1
pid-file = /var/run/mysqld/mysqld1.pid
log_error = /var/log/mysql/error1.log
federated
#skip-innodb

server-id = 101
replicate-do-db = db
#replicate-do-db = my_db1
#replicate-rewrite-db = db->my_db1
master-info-file = mysql1-master.info
relay-log = mysql1-relay-bin
relay-log-index = mysql1-relay-bin.index
relay-log-info-file = mysql1-relay-log.info
replicate-wild-ignore-table = mysql.%

[mysqld2]
....


Есть 2 варианта как хранить базы: все вместе в одном каталоге (раскоментить строки) или для каждого сервера указывать свою datadir.
При первом будет меньше каталогов и общие системные схемы mysql (пароли в ней), но не работает innodb.
2й способ более гибкий, устойчивый и работает с innodb. Я остановился на нем. Да и query-browser, как оказалось, дописывает полные имена таблицам в любом случае, а репликация с реврайтом этого не поймет.

Запускать mysqld_multi надо теперь с параметром --defaults-extra-file=/etc/mysql/my_multi.cnf
В init.d скрипте тоже добавляем.

Если работает apparmor, то и его настройки нужно подправить:
/etc/apparmor.d/usr.sbin.mysqld:
....
/usr/share/mysql/** r,
/var/log/mysql.log rw,
/var/log/mysql.err rw,
/var/lib/mysql/ r,
/var/lib/mysql/** rwk,
/var/lib/mysql_multi/ r,
/var/lib/mysql_multi/** rwk,
/var/log/mysql/ r,
/var/log/mysql/* rw,
/var/run/mysqld/mysqld.pid w,
/var/run/mysqld/mysqld.sock w,
/var/run/mysqld/mysqld?.pid w,
/var/run/mysqld/mysqld?.sock w,
/var/run/mysqld/mysqld??.pid w,
/var/run/mysqld/mysqld??.sock w,
....

$sudo service apparmor reload


Создаем директории под базы. Если основная база чистая еще, то можно ее копировать, иначе используем mysql_install_db
$sudo mkdir -pm700 /var/lib/mysql_multi/mysqlN
$sudo chown -R mysql:mysql /var/lib/mysql_multi
$sudo mysql_install_db --user=mysql --basedir=/usr --datadir=/var/lib/mysql_multi/mysqlN

Запускаем и проверяем.
$sudo service mysqld_multi start
$mysql -uroot -p -h127.0.0.1 -P33061

federated.

На основном сервере создаем пользователя для подключения к таблицам по federated:
mysql>CREATE USER 'fdrt_local'@'localhost';
mysql>GRANT SELECT, UPDATE, DELETE ON 'rpl_%' TO 'fdrt_local'@'localhost';

Перед запуском.

Развернуть текущую базу на основном сервере.

На мастере
$mysqldump --opt bd | gzip > dbN_full.sql.gz
$mysqldump --opt -d bd | gzip > dbN_nodata.sql.gz

Переносим архивы на сервер, затем
$zcat bd_full.sql.gz | mysql repl_dbN
Я еще добавлял триггеры на некоторые таблицы в целевых базах, для создания обобщающих таблиц.

Создать базу с federated таблицами на слэйв-сервере.

С помощью следующей регулярки создаем файл dbN_fdrt.sql и заливаем его в на слэйв-сервер.
#(CREATE[\s\w]*)`(\w*)`((.|[\n\r])*?ENGINE\s*=\s*)(\w)+((.|[\n\r])*?;)#iu
меняем на
$1`$2`$3FEDERATED CONNECTION=\'mysql://fdrt_local@localhost/%db_name%/$2\'$6


Можно в регулярку поставлять имя базы, либо sed'ом поменять перед рестором.
$sed 's/%db_name%/repl_dbN/g' bd_fdrt.sql | mysql -h127.0.0.1 -P33061 dbN


Или даже лучше и проще использовать команду CREATE SERVER одну на базу.

UPD: с CREATE SERVER не заработало в mysqld 5.1.41-3ubuntu12.7.

Далее настраиваем слэйв и запускаем репликацию. Готово.

Поправил: несколько небольших скриптов помогают мне управляться с репликациями, проверять статус и прочее. Если кому интересно, с радостью поделюсь.

+28
11.2k 119
Comments 14