Мы — долго запрягаем, быстро ездим, и сильно тормозим.
www.lissyara.su —> статьи —> FreeBSD —> программы —> MySQL Master+Master

MySQL Master+Master

Автор: fox.


Примечание, есть улучшенная версия статьи на моей вики:
MySQL Master+Master

Эта статья написана на быструю руку и не претендует на что-либо. Я её написал, чтобы не забыть, как я это сделал, на случай если понадобится повторить или, может быть, ещё кому-то она будет полезной. Прошу зараннее не искать у меня орфографических ошибок, ибо их там тьма! :-)

             *************************************************************
Пролог:
Вы только представьте, появилась необходимость в ***Донецком национальном академическом украинском музыкально-драматическом театре*** (говоря эти слова, аж слёзы на глазах выступают). Ладно, пропустим эпиграф патриотизма и стёба, ближе к делу - делаем MySQL сервер в режиме Master Master… Зачем? Не скажу - военная тайна!

                                       Акт первый:

   Итак, приступим, у нас имеется два сервера. Давайте, к примеру, их назовём BSD1 и BSD2. У каждого из них есть энное количество интерфейсов. Желательно между серверами сделать кроссовер с карточками эквивалентом 1Gbit, это приблизительно 128 MB/s, что приблизительно приравнивается к скорости работы винта! В случае репликации больших баз данных это значительно облегчит ситуацию…
Первый сервер (BSD1) объеденим со вторым сервером (BSD2) кроссовером через интерфейсы:

BSD1 re0 ip: 10.10.10.10
BSD2 re0 ip: 10.10.10.20

Теперь приступим к установке MySQL, я выбрал версию 5.1, кто-то может выбрать другую, более новую, но меня устраивает такая! Для начала обновим порты, как это сделать? Вы наверняка знаете, если не знаете, то найдёте уйму материала, на данном замечательном ресурсе…
  1. Устанавливаем на обоих серверах, MySQL сервер, я делал это так:

# cd /usr/ports/databases/mysql51-server/
# make BUILD_OPTIMIZED=yes WITH_OPENSSL=yes WITH_CHARSET=koi8r
# make install clean
#rehash
а у кого bash, тот делает:
#hash -r

Я выбрал кодировку koi8r, вы можете указать другую, например, cp1251, но я сторонник koi8r!
Создаём MySQL базу:
# mysql_install_db

Присваиваем правильные права:
# chown -R mysql:mysql /var/db/mysql/

Создаём файл для логов с нужными правами:

# touch /var/log/mysql.log
# chown mysql:mysql /var/log/mysql.log

Копируем конфиг:
# cp /usr/local/share/mysql/my-huge.cnf /etc/my.cnf

2. Когда вы дошли до этого этапа, можно приступить к настройке первой фазы репликации Master + Slave (Ведущий + Ведомый), в нашем случае Master будет (BSD1), а Slave будет (BSD2).
Начнём редактировать конфиг Master (BSD1).

my.cnf:

[mysqld]
...
log=/var/log/mysql.log
default-character-set=koi8r
character-set-server=koi8r
collation-server=koi8r_general_ci
init-connect="SET NAMES koi8r"
skip-character-set-client-handshake
language=/usr/local/share/mysql/russian/
skip-name-resolve

datadir=/var/db/mysql
socket=/tmp/mysql.sock
old_passwords=1
log-bin=/var/db/mysql/mysql-bin
binlog-do-db=testdb
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
server-id=1
...

Обратите внимание – это очень важно, чтобы у вас в конфиге не повторялись строки, такие как:

old_passwords=
log-bin=
server-id=

Иначе может ничего не получится, в лучшем случае будет работать с косяками, если строки где-то повторяются, закомментируйте их!
Также обратите внимание на такие строки, как:

#Та база(ы), которая будет подвергаться репликации
binlog-do-db=testdb
#Та база(ы), которая, наоборот, будет игнорировать репликацию
binlog-ignore-db=mysql
binlog-ignore-db=information_schema

3. Поработаем с конфигом Slave(BSD2).
my.cnf:

[mysqld]
...
log=/var/log/mysql.log
default-character-set=koi8r
character-set-server=koi8r
collation-server=koi8r_general_ci
init-connect="SET NAMES koi8r"
skip-character-set-client-handshake
language=/usr/local/share/mysql/russian/
skip-name-resolve

datadir=/var/db/mysql
socket=/tmp/mysql.sock
old_passwords=2
server-id=2
master-host = 10.10.10.10
master-user = replication
master-password = slavepass1
master-port = 3306
...

Ещё раз напоминаю, чтобы проверяли, не повторяются ли строки в конфигах!!!

old_passwords=
log-bin=
server-id=

4. На обоих серверах добавляем автозагрузку MySQL в rc.conf:
mysql_enable="YES"

Запускаем на обоих серверах MySQL:
# /usr/local/etc/rc.d/mysql-server start

Проверяем работает ли:

# sockstat | grep mysql
mysql    mysqld     75184 13 tcp4   *:3306                *:*
mysql    mysqld     75184 15 stream /tmp/mysql.sock

Обратите внимание, чтобы MySQL слушал во всех направлениях и чтобы не получилось так, что он будет слушать localhost или какой-то отдельный ip. Нам нужна будет репликация, поэтому MySQL должен слушать как минимум в сторону кроссовера или лучше во всех направлениях, а кто боится о безопасности, то заткните при помощи FireWall те места!

5. Настраиваем root пользователя на обоих серверах:
# mysqladmin -u root  password 'root_password'

Заходим:

# mysql -u root -p
Enter password:

На сервере Master (BSD1) добавляем пользователя для репликации Slave:

mysql> grant replication slave on *.* to 
'replication'@10.10.10.20 identified by 'slavepass1';

Перезапускаем привилегии:
mysql> flush privileges;

На сервере Slave (BSD2) стартуем Slave режим:

mysql> slave start;

Проверяем стал Slave(BSD2) сервер, в режим Slave?

show slave status\G;

Если строки:

...
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...

Показывает состояние Yes, значит всё получилось!
Режим Master + Slave работает!
6. Тестируем:
На сервере Master (BSD1), проверяем состояние Master:
mysql> show master status;

Должно быть примерно так:

+------------------+----------+--------------+--------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB         |
+------------------+----------+--------------+--------------------------+
| mysql-bin.000001 |      106 | testdb       | mysql,information_schema |
+------------------+----------+--------------+--------------------------+
1 row in set (0.00 sec)

Отсюда мы видим, что две базы игнорируют репликацию, а одна подвергается!
Создаём базу на сервере Master:
mysql> create database testdb;

Проверяем на сервере Slave:

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| test               |
| testdb             |
+--------------------+
3 rows in set (0.01 sec)

Видим, что на втором сервере Slave также появилась база testdb!
7. Этот пункт можно пропустить, но я бы сделал так - вносим полезные изменения в MySQL сервера, причем это нужно сделать на обоих серверах!
Удаляем test базу:

mysql> drop database test;
Query OK, 0 rows affected (0.01 sec)

Теперь редактируем mysql базу:

mysql> use mysql;
Database changed

Смотрим, что в таблице пользователей:
mysql> select Host,User,Password from user;

У Master будет так:

+-----------------+-------------+------------------+
| Host            | user        | Password         |
+-----------------+-------------+------------------+
| localhost       | root        | 352c4a5701107150 |
| BSD1            | root        |                  |
| 127.0.0.1       | root        |                  |
| localhost       |             |                  |
| BSD1            |             |                  |
| 10.10.10.20     | replication | 48ea58092bbc51a3 |
+-----------------+-------------+------------------+
6 rows in set (0.01 sec)

А у Slave вот так:
+-----------+------+-------------------------------------------+
| Host      | User | Password                                  |
+-----------+------+-------------------------------------------+
| localhost | root | *28B7B09A25EC723332B51CF8FD7286F9BD8CFB44 |
| BSD2      | root |                                           |
| 127.0.0.1 | root |                                           |
| localhost |      |                                           |
| BSD2      |      |                                           |
+-----------+------+-------------------------------------------+
Такой вид - это не есть гуд!
Грохаем ненужных пользователей:

mysql> delete from user where Host='BSD1';
Query OK, 2 rows affected (0.01 sec)

Разумеется, что для сервера BSD2, мы BSD1 заменим на BSD2!

mysql> delete from user where Host='127.0.0.1';
Query OK, 1 row affected (0.00 sec)
mysql> delete from user where Host='localhost' and User='';
Query OK, 1 row affected (0.00 sec)

Вот теперь есть гуд для Master:

mysql> select Host,user,Password from user;
+-----------------+-------------+------------------+
| Host            | user        | Password         |
+-----------------+-------------+------------------+
| localhost       | root        | 352c4a5701107150 |
| 10.10.10.20     | replication | 48ea58092bbc51a3 |
+-----------------+-------------+------------------+
2 rows in set (0.00 sec)

И для Slave:

mysql> select Host,User,Password from user;
+-----------+------+-------------------------------------------+
| Host      | User | Password                                  |
+-----------+------+-------------------------------------------+
| localhost | root | *28B7B09A25EC723332B51CF8FD7286F9BD8CFB44 |
+-----------+------+-------------------------------------------+
1 row in set (0.01 sec)

Для чистоты можно и в таблице db навести марофет:

mysql> delete from db;
Query OK, 2 rows affected (0.02 sec)

Перезапускаем привилегии:

mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)

Ну вот мы и справились с первой фазой, с настройкой и оптимизацией!
Конец первого акта, антракт, идём пить чай, кофе, капучино, приставать к нетрезвым женщинам!
                       
                              *********** АНТРАКТ ***********

                                        Акт второй:
  Master (BSD1) + Slave (BSD2) мы осуществили, теперь нужно организовать симметрично
Master (BSD2) + Slave (BSD1) для полного режима Master + Master!
1. Приступим! Правим конфиг Slave (BSD1).
Добавляем в my.cnf:

[mysqld]
...
master-host = 10.10.10.20
master-user = replication
master-password = slavepass2
master-port = 3306
...

2. Затем правим конфиг Master(BSD2).
Добавляем в my.cnf:

log-bin=/var/db/mysql/mysql-bin
binlog-do-db=testdb
binlog-ignore-db=mysql
binlog-ignore-db=information_schema

А также добавляем на Master (BSD2) учётную запись репликации:

mysql> grant replication slave on *.* to 'replication'@10.10.10.10 
identified by 'slavepass2';
Query OK, 0 rows affected (0.00 sec)

А теперь перезапускаем оба сервера:

# /usr/local/etc/rc.d/mysql-server restart

Итак, теперь помолимся пару секунд богам FreeBSD, можно в жертву принести компашку с Windows! :-)
Проверяем, на обоих серверах делаем:

mysql> show slave status\G;

И если мы правильно молились, то увидим на обоих серверах:

Slave_IO_Running: Yes
Slave_SQL_Running: Yes

Если у вас также, то боги вас услышали!

3. Тестируем:
На сервере Master (BSD2) добавляем таблицу в базе testdb:

mysql> use testdb;
Database changed
mysql> create table test (id int(11) auto_increment,name varchar(255), 
primary key(id));
Query OK, 0 rows affected (0.02 sec)

Проверяем на сервере Master (BSD1), добавилась ли таблица?

mysql> show tables;
+------------------+
| Tables_in_testdb |
+------------------+
| test             |
+------------------+
1 row in set (0.01 sec)

Теперь останавливаем любой из серверов, к примеру, Master (BSD1), а на сервере Master (BSD2) добавляем данные:
# /usr/local/etc/rc.d/mysql-server stop


mysql> insert into test (name) values('fox');
mysql> insert into test (name) values('fortero');

Запускаем остановленный сервер:
# /usr/local/etc/rc.d/mysql-server start

Проверяем, добавилась ли новая информация?

mysql> select * from test;
+----+---------+
| id | name    |
+----+---------+
|  1 | fox     |
|  2 | fortero |
+----+---------+
2 rows in set (0.00 sec)

Работает! Можно ещё долго тестировать… Ну, это вы сами сможете сделать.

Примечания!
0. Будьте внимательны с нетрезвыми женщинами!
1. Будьте внимательны с конфигами, проверяйте, чтобы строки не повторялись!
2. Если вы переделываете уже существующий MySQL сервер, вам придётся лучше забекапить базы, грохнуть все файлы в директории /var/db/mysql/, разумеется папки с базами можно не трогать! Иначе могут быть косяки с репликацией!
3. Если вдруг ошиблись или поменяли ip адреса серверов, когда поменяете в конфиге ip репликации, то ещё надо будет грохнуть файл:
# rm /var/db/mysql/master.info

4. И обязательно нужно настроить правильно время на обоих серверах! Время должно чётко работать согласно временным поясам, лучше всего это организовать через ntpd демона, на данном ресурсе имеются статьи о том, как это сделать!

                              *************** КОНЕЦ ***************



размещено: 2010-04-14,
последнее обновление: 2015-04-07,
автор: fox


pythonchik, 2010-04-13 в 23:39:17

пардон, но эпилог в начале статьи....
может все-таки эфиграф?

fox, 2010-04-14 в 1:31:53

Сори, ачипятка "Пролог"... Пофиксел!

Vosi, 2010-04-14 в 15:45:58

не забудь
auto-increment-offset = 2 на одном и
auto-increment-offset = 1 на другом (или наоборот)
для того чтоб проблем с правймари небыло

а еще, чтоб поднять мастер-мастер с сингла достаточно:
1. остановить синг
2. настроить май.кнф на сингле для слейв
3. удалить все бинлоги итп, кроме ибдата, май.кнф, и диров с таблицами на сингле
4. настроить мак.кнф на новом для слейв
5. скопировать ибдата+диры с таблицами с сингла на новый
6. стартануть сингл
7. стартануть новый
смотреть еррор логи там и там

mgyk, 2010-04-19 в 2:32:29

koi8-r это круто

h, 2010-04-19 в 13:56:48

master-host = 10.10.10.10
master-user = replication
master-password = slavepass1
master-port = 3306

вот это в конфиге не нужно. один раз стартуете репликацию из mysql и данные о подключении сохраняются в master.info.
плюс в том, что для того чтобы сменить настройки подключения не нужно править my.cnf и не нужно перезапускать mysqld.

смотрите high performance mysql.

playnet, 2010-04-23 в 19:34:20

Если кто смотрел "папский городок": все фразы с "!" на конце должны звучать как у Рихтера. :)

Использовать сейчас в основе что кои8, что цп1251... это некрофилия.
А ошибок действительно много, в тч. логических...

5chme1, 2010-08-27 в 16:19:31

хорошая статья. в phpmyadmin3 тоже по моему можно репликацию делать

fox, 2010-08-27 в 18:52:02

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

MK, 2011-01-02 в 11:34:13

Статья хороша, но есть вопрос, как будет вести себя репликация мастер-мастер на нагруженой бд? при балансировки нагрузки? в случае если сам добавил одну запись на одном сервере и она реплицировалась на второй это одно, но когда в единицу времени добавляется запись на 1м сервере и на 2м сервере, как будет себя вести данная связка? на сколько я понимаю блокировки нету? (пробовали сделать так, отключить один сервер добавить в него запись, отключить второй сервер, в него добавить другую запись в туже таблицу и включить их для синхронизации).

fox, 2011-01-04 в 5:37:02

Я думаю будет всё нормально, точнее всё будет упираться в железо!
У меня в таком режиме постоянно два сервера одновременно бросают записи с прокси, база за год выросла на 18 миллионов строк, пока не наблюдал проблем занимает 8 гиг…
Ну нужно пробовать в Вашем случае, дело может быть индивидуальным…

Dmitri, 2011-05-31 в 0:32:26

Спасибо, помогли.

Mox, 2011-08-26 в 14:56:52

А еще втыкаем в http://dev.mysql.com/doc/refman/5.5/en/replication-rules.html

Не стоит пользоваться binlog-ignore-db и binlog-do-db в качестве фильтра. Только replicate-* на стороне слэйва

Mox, 2011-08-26 в 17:23:15

+ читаем о вреде binlog-ignore-db и binlog-do-db http://www.mysqlperformanceblog.com/2009/05/14/why-mysqls-binlog-do-db-option-is-dangerous/

ttys, 2011-08-28 в 16:30:29

сейчас столкнулся с тем что даже RAC Oracle не может нормально отработать падение одного из серверов, тоесть те транзакции которые были открыты отваливаются.
ИМХО из бесплатных решений вряд ли, что подойдёт для продакшн
выход базу располагать на сторадже с платным решением

суперадмин, 2013-03-13 в 15:27:16

ttys,
про оракл: а разве так не должно разве и быть? он оставляет закомиченные сессии, а все не закомиченно откатывается.

ttys, 2013-03-13 в 16:19:23

суперадмин,
не должно
он должен передать всё второму, что то типа рейд 1
и в платных вариантах это так и работает



 

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

© lissyara 2006-10-24 08:47 MSK

Время генерации страницы 0.0485 секунд
Из них PHP: 39%; SQL: 61%; Число SQL-запросов: 77 шт.
Исходный размер: 62576; Сжатая: 12186