До выхода приложения в бой, нужно смоделировать его поведение в тестовой среде.
Технология Docker Swarm позволяет легко масштабировать приложение горизонтально. Но часто приложению приходится обращаться к серверу баз данных, задача масшабировать который гораздо труднее.
В нашем случае количество запросов на чтение информации гораздо меньше количества изменений (есть подозрение, что так на большинстве веб-проектов). Логичный способ увеличения такого бутылочного горлышка - увеличить количество баз на чтение и настроить приложение таким образом, чтобы большее количество запросов на чтение отправлялось на SLAVE-сервера.
Предварительная установка
Установить docker, docker-compose на вашу операционную систему.
Текст далее протестирован на
- Ubuntu 18.04
- docker 18.09
- docker-compose 1.25.4
Проект
Создадим папку, где будет располагаться конфигурация серверов
mkdir db-replication
и перейдём в неё
cd db-replication
Дальнейшие действия будут производиться относительно папки с проектом.
Настройка репликации
Создадим папку для хранения конфигураций серверов mysql
mkdir -p build_env/mysql
Изменение в my.cnf для каждого сервера
Каждый сервер должен иметь свой номер.
Master-сервер server-id=1
.
Slave-сервер server-id>1
.
Конфигурационный файл находится по адресу
/etc/mysql/conf.d/my.cnf
Создадим файл конфигурации master-сервера
nano build_env/mysql/master.cnf
с содержимым
[mysqld]
server-id=1
binlog_format=ROW
log-bin
Конфигурация slave1
nano build_env/mysql/slave1.cnf
[mysqld]
server-id=2
Конфигурация slave2
nano build_env/mysql/slave2.cnf
[mysqld]
server-id=3
Изменения при старте сервера
На master-сервере нужно выдать права пользователю для чтения файла лога
nano build_env/mysql/master.sql
CREATE USER repl@'%' IDENTIFIED WITH mysql_native_password BY 'slavepass';
GRANT REPLICATION SLAVE ON *.* TO repl@'%';
На slave-сервере нужно указать координаты для подключения к master
nano build_env/mysql/slave.sql
CHANGE MASTER TO MASTER_HOST='db-master', MASTER_USER='repl', MASTER_PASSWORD='slavepass';
Создадим файл для docker-compose
nano docker-compose.yml
с содержимым
version: '3.7'
services:
mysql:
image: 'percona:8.0'
container_name: db-master
volumes:
- ./build_env/mysql/master.cnf:/etc/my.cnf.d/repl.cnf
- ./build_env/mysql/master.sql:/docker-entrypoint-initdb.d/start.sql
environment:
MYSQL_ROOT_PASSWORD: "secret"
mysqlread1:
image: 'percona:8.0'
container_name: db-slave1
volumes:
- ./build_env/mysql/slave1.cnf:/etc/my.cnf.d/repl.cnf
- ./build_env/mysql/slave.sql:/docker-entrypoint-initdb.d/start.sql
depends_on:
- mysql
environment:
MYSQL_ROOT_PASSWORD: "secret"
mysqlread2:
image: 'percona:8.0'
container_name: db-slave2
volumes:
- ./build_env/mysql/slave2.cnf:/etc/my.cnf.d/repl.cnf
- ./build_env/mysql/slave.sql:/docker-entrypoint-initdb.d/start.sql
depends_on:
- mysql
environment:
MYSQL_ROOT_PASSWORD: "secret"
Запуск
docker-compose rm -vf && docker-compose up
Проверка
Открываем ещё 1 терминал, заходим в master-сервер
docker exec -it db-master mysql -uroot -psecret
И ещё 1 терминал, заходим в любой slave
docker exec -it db-slave1 mysql -uroot -psecret
На master выполняем
show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
Создадим на master базу данных test
create database test;
В подключении для slave проверяем, появилась ли созданная на master база данных:
show databases;
В выводе должна появиться база данных test
.
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
Диагностика
Для диагностики нужно иметь возможность подключения к консоли mysql. Подключаемся к master-серверу:
docker exec -it db-master mysql -uroot -psecret
Смотрим статус
mysql> show master status;
+-------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| mysqld-bin.000004 | 119471 | | |
+-------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
В процессах master-сервера мы можем видеть подключения со SLAVE-контейнеров, либо ошибки
mysql> SHOW PROCESSLIST;
+----+-----------------+------------------+------+-------------+------+---------------------------------------------------------------+------------------+-----------+---------------+
| Id | User | Host | db | Command | Time | State | Info | Rows_sent | Rows_examined |
+----+-----------------+------------------+------+-------------+------+---------------------------------------------------------------+------------------+-----------+---------------+
| 4 | event_scheduler | localhost | NULL | Daemon | 234 | Waiting on empty queue | NULL | 0 | 0 |
| 8 | repl | 172.18.0.4:57040 | NULL | Binlog Dump | 230 | Master has sent all binlog to slave; waiting for more updates | NULL | 0 | 0 |
| 9 | repl | 172.18.0.3:51798 | NULL | Binlog Dump | 228 | Master has sent all binlog to slave; waiting for more updates | NULL | 0 | 0 |
| 10 | root | localhost | NULL | Query | 0 | starting | SHOW PROCESSLIST | 0 | 0 |
+----+-----------------+------------------+------+-------------+------+---------------------------------------------------------------+------------------+-----------+---------------+
4 rows in set (0.00 sec)
Для slave-сервера
docker exec -it db-slave1 mysql -uroot -psecret
mysql> SHOW SLAVE STATUS;
+----------------------------------+-------------+-------------+-------------+---------------+-------------------------+---------------------+-------------------------------+---------------+-------------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+-------------------------+-----------+---------------------+--------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+------------------------+-----------------------+-------------------+
| Slave_IO_State | Master_Host | Master_User | Master_Port | Connect_Retry | Master_Log_File | Read_Master_Log_Pos | Relay_Log_File | Relay_Log_Pos | Relay_Master_Log_File | Slave_IO_Running | Slave_SQL_Running | Replicate_Do_DB | Replicate_Ignore_DB | Replicate_Do_Table | Replicate_Ignore_Table | Replicate_Wild_Do_Table | Replicate_Wild_Ignore_Table | Last_Errno | Last_Error | Skip_Counter | Exec_Master_Log_Pos | Relay_Log_Space | Until_Condition | Until_Log_File | Until_Log_Pos | Master_SSL_Allowed | Master_SSL_CA_File | Master_SSL_CA_Path | Master_SSL_Cert | Master_SSL_Cipher | Master_SSL_Key | Seconds_Behind_Master | Master_SSL_Verify_Server_Cert | Last_IO_Errno | Last_IO_Error | Last_SQL_Errno | Last_SQL_Error | Replicate_Ignore_Server_Ids | Master_Server_Id | Master_UUID | Master_Info_File | SQL_Delay | SQL_Remaining_Delay | Slave_SQL_Running_State | Master_Retry_Count | Master_Bind | Last_IO_Error_Timestamp | Last_SQL_Error_Timestamp | Master_SSL_Crl | Master_SSL_Crlpath | Retrieved_Gtid_Set | Executed_Gtid_Set | Auto_Position | Replicate_Rewrite_DB | Channel_Name | Master_TLS_Version | Master_public_key_path | Get_master_public_key | Network_Namespace |
+----------------------------------+-------------+-------------+-------------+---------------+-------------------------+---------------------+-------------------------------+---------------+-------------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+-------------------------+-----------+---------------------+--------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+------------------------+-----------------------+-------------------+
| Waiting for master to send event | db-master | repl | 3306 | 60 | 07a9adad7189-bin.000003 | 155 | 0c53f622dac3-relay-bin.000005 | 383 | 07a9adad7189-bin.000003 | Yes | Yes | | | | | | | 0 | | 0 | 155 | 2955798 | None | | 0 | No | | | | | | 0 | No | 0 | | 0 | | | 1 | b9bb3878-7c11-11ea-9d4d-0242ac120002 | mysql.slave_master_info | 0 | NULL | Slave has read all relay log; waiting for more updates | 86400 | | | | | | | | 0 | | | | | 0 | |
+----------------------------------+-------------+-------------+-------------+---------------+-------------------------+---------------------+-------------------------------+---------------+-------------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+-------------------------+-----------+---------------------+--------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+------------------------+-----------------------+-------------------+
1 row in set (0.00 sec)