В данной статье я бы хотел показать как настроить MySQL для дальнейшего использования gem'a octopus, который используется для шардинга и репликации в Rails — приложениях.
Итак, представим, что перед нами стоит задача развернуть три сервера(на первом крутится Rails — приложение, второй нужен для Master'a, третий будет выступать в качестве Slave'a), настроить репликацию между серверами и сделать так, чтобы octopus работал.
Шаг первый — предварительная настройка серверов
Действия, описанные в данном шаге, необходимо проделать как на Master — машине, так и на Slave.
Установим MySQL.
sudo apt-get install mysql-server
Теперь зайдем в MySQL консоль:
mysql -u root -p
Создадим базу данных, а также пользователя, у которого будут все права на работу с данной базой:
create database rails_myapp;
GRANT ALL ON rails_myapp.* TO 'rails_myapp_user'@'localhost';
GRANT ALL ON rails_myapp.* TO 'rails_myapp_user'@'%';
FLUSH PRIVILEGES;
EXIT;
Шаг второй — настроим Master
Откроем файл конфигурации MySQL на Master — сервере.
sudo nano /etc/mysql/my.cnf
Внутри этого файла мы сделаем несколько изменений. Во — первых, найдем следующую строчку:
bind-address = 127.0.0.1
Заменим стандартный IP адрес на 0.0.0.0, для того, чтобы Rails — приложение могло достучаться до сервера:
bind-address = 0.0.0.0
Следующим нашим шагом будет изменение значения server-id, ищем server-id в [mysqld] секции файла конфига. Вы можете выбрать любое число в качестве server-id, но для простоты лучше указать 1, нужно лишь помнить, что данное число должно быть уникально для группы серверов, которые будут участвовать в репликации.
Еще раз убедитесь, что данная строка откомментирована.
server-id = 1
Теперь перейдите на строку со значением log_bin. Slave будет копировать все изменения, которые будут регистрироваться в логе. Опять же, лучше просто откомментировать строчку с log_bin:
log_bin = /var/log/mysql/mysql-bin.log
В конце Вы должны указать имя базы данных, которая будет реплицирована Slave — сервером. Вы можете указать несколько баз, повторяя данную строку для всех баз, которые хотите репллицировать.
binlog_do_db = rails_myapp
Все изменения сделаны! Можно сохранить и закрыть файл.
Перезапустим MySQL.
sudo service mysql restart
Откроем MySQL — шелл.
mysql -u root -p
Вы должны предоставить привилегии для Slave. Для этого используем следующую команду:
GRANT REPLICATION SLAVE ON *.* TO 'slave_user'@'%' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;
Далее Вы должны переключиться на свою базу:
USE rails_myapp;
Заблокируем базу данных, чтобы посмотреть данные, которые пригодятся нам на следующих этапах:
FLUSH TABLES WITH READ LOCK;
Далее наберем:
SHOW MASTER STATUS;
Вы увидите примерно такую табличку, если наберете описанную ниже команду:
mysql> SHOW MASTER STATUS;
File | Position | Binlog_Do_DB |
---|---|---|
mysql-bin.000001 | 107 | rails_myapp |
1 row in set (0.00 sec)
Важно! Запишите или запомните название файла и номер позиции, данные значения будут использоваться позже.
Пока ваши базы данных заблокированы, нужно экспортировать базу rails_myapp. Откройте второй терминал в новом окне, убедитесь, что набираете данную команду в bash — шеле, а не в консоле MySQL.
mysqldump -u root -p --opt rails_myapp > rails_myapp.sql
Перейдите обратно в MySQL консоль, разблокируйте базы данных(разрешим запись).
UNLOCK TABLES;
QUIT;
Все! Мы закончили настройку Master'a.
Шаг третий — настроим Slave.
Зайдите на MySQL сервер, откройте MySQL и создайте базу данных(имя точно такое, как и на мастере):
CREATE DATABASE rails_myapp;
EXIT;
Перенесите файл с SQL — командами, который вы экспортировали на мастере и сделайте импорт.
mysql -u root -p rails_myapp< /path/to/rails_myapp.sql
Затем необходимо немного поправить файл конфигурации MySQL:
sudo nano /etc/mysql/my.cnf
Первое, что изменим будет server-id. Как Вы помните, номер должен быть уникальным в пределах группы(в конфиге Master'a мы указали 1).
server-id = 2
Теперь допишем(или откомментируем) следующие три строки:
relay-log = /var/log/mysql/mysql-relay-bin.log
log_bin = /var/log/mysql/mysql-bin.log
binlog_do_db = newdatabase
Зададим новое значение bind-address:
bind-address = 0.0.0.0
Перезапустим MySQL:
sudo service mysql restart
Следующим шагом будет непосредственно запуск репликации. Помните! Вместо MASTER_LOG_FILE и MASTER_LOG_POS Вы должны вписать те значения, которые записали до этого.
CHANGE MASTER TO MASTER_HOST='12.34.56.789',MASTER_USER='slave_user', MASTER_PASSWORD='password', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS= 107;
START SLAVE;
Как проверить, удачно ли прошел запуск Slave'a? Необходимо ввести комманду, описанную ниже и просмотреть лог:
SHOW SLAVE STATUS\G
Шаг четвертый — настроим octopus.
В Rails — приложении нужно добавить следующую строчку в Gemfile:
gem 'ar-octopus'
Внутри директории config/ нужно создать файл shards.yml, который будет отвечать за конфигурирование Slave — сервера. Помните! Файл database.yml отвечает за конфигурацию Master'a, а только что созданный shards.yml за конфигурацию Slave'ов, не забываем, что в YML пробелы и табуляции имеют значение.
Файл shards.yml, после заполнения должен выглядеть примерно так:
octopus:
replicated: true
fully_replicated: true
environments:
- development
- test
development:
slave:
adapter: mysql2
encoding: utf8
database: rails_myapp
username: rails_myapp_user
password: qwerty
host: 130.111.11.111
port: 3306
pool: 10
test:
slave:
adapter: mysql2
encoding: utf8
database: rails_myapp
username: rails_myapp_user
password: qwerty
host: 130.111.111.111
port: 3306
pool: 10
Все! Осталось прописать в Ваших моделях, что они являются replicated_model(), и запустить Rails — приложение. Отправив POST — запрос, в консоли Вы должны увидеть примерно следующее:
[Shard: slave] OurModel Load (1.0ms) SELECT `model`.* FROM `model` WHERE `chats`.`id` = 'gkjhgfhd' LIMIT 1
Удачной настройки!
Комментарии (10)
Dreyk
27.06.2015 13:38У меня всегда первый вопрос по master/slave: есть ли возможность сделать «залипание» мастера для конкретного пользователя на некоторое время после write?
Replication lag хоть какой-нибудь да будет. Нужен какой-то знак (кука?), который говорит о том, что покачто даже чтение надо проводить с мастера.
У кого бы я ни спрашивал, почему-то людей этот вопрос мало волнуетRapter Автор
27.06.2015 18:04Такого рода задачи можно достаточно легко решать с помощью octopus. Вы можете делать примерно вот так:
order = Octopus.using(:master) do current_user.orders.last end
Dreyk
27.06.2015 20:09мне нужно, чтоб один и тот же запрос работал с мастера или слейва в зависимости от того, была ли у юзера запись в мастер
Gendalph
27.06.2015 22:34Делать лок всех таблиц для дампа совсем не обязательно.
mysqldump -u root -p --opt rails_myapp
Легким движением руки превращается в
mysqldump -u root -p --opt --master-data --databases rails_myapp
Тогда данные о мастере будут в самом дампе (MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS= 107;
), также будет добавлена команда создания БД.
А если добавить--single-transaction
, то можно и вовсе делать дамп с живого сервера, на относительно небольших базах.
bo0rsh201
мне кажется, или это не самая полезная рекомендация?
стоит все-таки написать о проблемах такого решения
mobilesfinks
когда кажется… ну вы знаете. Чем вам не нравится эта опция? биндит сокет на все интерфейсы. это вызывает какой-то оверхед? расскажите пожалуйста поподробней.
bo0rsh201
тем самым вы открываете доступ к базе всему интернету.
гораздо лучше биндится на адрес во внутренней сети. насколько я помню, там можно несколько адресов указать.
Gendalph
Предлагаю освежить память:
dev.mysql.com/doc/refman/5.6/en/server-options.html#option_mysqld_bind-address
www.cyberciti.biz/faq/unix-linux-mysqld-server-bind-to-more-than-one-ip-address
Может быть только один bind-address. Поэтому либо биндимся на внутренний IP, либо на 0.0.0.0 +firewall, на случай если кому-то вздумается пойти на localhost…
Можно поробовать еще шифрование SSL-ное прикрутить. Механизмы есть, но я пока не разобрался на практике.