Репликация MySQL-серверов с помощью Docker

До выхода приложения в бой, нужно смоделировать его поведение в тестовой среде.

Технология Docker Swarm позволяет легко масштабировать приложение горизонтально. Но часто приложению приходится обращаться к серверу баз данных, задача масшабировать который гораздо труднее.

Много приложений - одна база

В нашем случае количество запросов на чтение информации гораздо меньше количества изменений (есть подозрение, что так на большинстве веб-проектов). Логичный способ увеличения такого бутылочного горлышка - увеличить количество баз на чтение и настроить приложение таким образом, чтобы большее количество запросов на чтение отправлялось на SLAVE-сервера.

Много приложений - одна база

Предварительная установка

Установить docker, docker-compose на вашу операционную систему.

Текст далее протестирован на

Проект

Создадим папку, где будет располагаться конфигурация серверов

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)