MariaDB Replication

개인적으로 트랜잭션 처리가 중요할 경우에 noSQL 데이터베이스보다는 관계형 데이터베이스가 적합하다고 판단하며,
그 중에서도 저는 MariaDB가 비영리 목적으로 사용할 경우 무료로 사용할 수 있어 개인적인 용도로 많이 사용되고 있습니다.

Replication은 복제라는 의미를 가지고 있으며,
Master와 Slave 구조로 데이터베이스 이중화 처리를 위해서 사용합니다.

Replication 원리

MariaDB에서는 INSERT, UPDATE, DELETE 문이 발생(데이터베이스에 수정)이 발생하였을 때,
Transaction에 관련한 부분을 Log파일로 관리하고 있으며 해당 Log파일을 통해서
서로 다른 MariaDB 서버가 비동기적으로 동기화를 진행합니다.

Master를 1개 지정하여 Write(쓰기)만을 위한 권한을 주고,
Slave로 여러 대를 지정하여 Read(읽기)만을 위한 권한을 주어,
Slow Query, Table Lock 과 같은 문제가 발생하였을 때 처리를 위해서
Master에서는 쓰기만, Slave에서는 읽기만 가능하도록 합니다.

왜 Docker 인가?

Docker는 이미지 기반으로 배포를 자유롭게 할 수 있으며, 쪼개어서 Container 단위로 관리가 가능하기 때문에,
Micro Architecture에 중요하게 작용하고 있습니다.
로컬에서 Vmware나 VirtualBox와 같은 OS단위의 가상화가 아닌 반가상화인 Docker를 통해 쉽고 빠르게 배포와 관리를 할 수 있습니다.
Docker가 설치가 되어있다는 전제하에 본 글을 진행하도록 하겠습니다.

Replication을 위한 MariaDB 설정 파일 생성

MariaDB의 설정 파일인 .cnf 파일을 통해서 설정합니다.

Docker/master/config.cnf

[mysqld]
log-bin=maria-bin
server-id=1

Docker/slave/config.cnf

[mysqld]
server-id=2

Docker Network 생성

Docker에서는 Container간의 통신을 위해서 같은 Network에 소속되어 있어야 합니다.

$ docker network create replication
1fce7955cbd392f194ef2f249e6aa903ff6af360122327f454266221c10b5e7f

Docker Network 확인

추가한 replication이라는 Network가 잘 추가되었는지 확인합니다.

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
191a3bf2765f        bridge              bridge              local
802c60718313        host                host                local
8ad318e255c1        none                null                local
1fce7955cbd3        replication         bridge              local

Docker Container 생성

Replication을 위한 MariaDB Master 컨테이너와 MariaDB Slave 컨테이너를 생성합니다.

maria-master

$ docker run --name maria-master --network replication -p 6000:3306 -v `pwd`/master/:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=지정할루트비밀번호 -d mariadb
a2d239ad61475398d533cbf8a3483262c757127ecf8905a67395cb33d47dc358

maria-slave

$ docker run --name maria-slave --network replication -p 6001:3306 -v `pwd`/slave/:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=지정할루트비밀번호 -d mariadb
f8bce6dba9f62e7069f080c6fc49fc97983fdd5cdb9d3b79912b56630bd13485

Docker Container 생성 확인

생성한 maria-master와 maria-slave가 생성이 잘 되었는지 확인합니다.

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED                  STATUS              PORTS                    NAMES
f8bce6dba9f6        mariadb             "docker-entrypoint.s…"   Less than a second ago   Up 52 seconds       0.0.0.0:6001->3306/tcp   maria-slave
a2d239ad6147        mariadb             "docker-entrypoint.s…"   17 seconds ago           Up About a minute   0.0.0.0:6000->3306/tcp   maria-master

MariaDB Replication

MariaDB Master 컨테이너에 Replication을 위한 사용자를 추가 해주어야 합니다.

$ docker exec -it maria-master bash

-it 옵션은 해당 컨테이너의 가상 TTY를 통해 접속한다는 의미를 가지고 있습니다.
해당 명령을 통해 maria-master 컨테이너에 bash shell을 사용하게 됩니다.

Replication 사용자 생성

Master 컨테이너에 Replication 권한을 가진 사용자를 생성합니다.

$ docker exec -it maria-master bash
root@a2d239ad6147:/# mysql -uroot -p루트비밀번호
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 9
Server version: 10.2.14-MariaDB-10.2.14+maria~jessie-log mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> create user 'repl'@'%' identified by '사용자비밀번호';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> grant replication slave on *.* to 'repl'@'%';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]>
Replication 사용자 접속 확인

Replication 권한을 가진 사용자가 접속이 잘되는지 확인해봅니다.

root@a2d239ad6147:/# mysql -urepl -p사용자비밀번호
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 10
Server version: 10.2.14-MariaDB-10.2.14+maria~jessie-log mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> exit
Bye

테스트를 진행할 데이터베이스와 테이블 생성

Replication 설정 및 테스트를 위한 더미 데이터베이스와 테이블을 생성합니다.

root@a2d239ad6147:/# mysql -uroot -p루트비밀번호
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 11
Server version: 10.2.14-MariaDB-10.2.14+maria~jessie-log mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> create database repldb;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> use repldb;
Database changed

MariaDB [repldb]> create table user (user_name varchar(20));
Query OK, 0 rows affected (0.01 sec)

MariaDB [repldb]> desc user;
+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| user_name | varchar(20) | YES  |     | NULL    |       |
+-----------+-------------+------+-----+---------+-------+
1 row in set (0.00 sec)

데이터베이스 백업 파일 생성 및 복구

Replication을 위해서는 여러 데이터베이스가 동일한 정보를 가지고 있어야 하기에 해당 데이터베이스 파일을 백업합니다.

root@a2d239ad6147:/# mysqldump -uroot -p루트비밀번호 repldb > repldb.sql

MariaDB Slave 컨테이너에도 동일한 정보를 가지기 위해서 백업한 SQL파일을 옮깁니다.

$ docker cp maria-master:repldb.sql .
$ docker cp repldb.sql maria-slave:.

MariaDB Slave 컨테이너에 접속하여 백업받은 SQL파일을 복구시킵니다.

$ docker exec -it maria-slave bash
root@f8bce6dba9f6:/# mysql -uroot -p루트비밀번호
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 8
Server version: 10.2.14-MariaDB-10.2.14+maria~jessie mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> create database repldb;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> Bye
root@f8bce6dba9f6:/# mysql -uroot -p루트비밀번호 repldb < repldb.sql
root@f8bce6dba9f6:/# mysql -uroot -p루트비밀번호 repldb
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 10
Server version: 10.2.14-MariaDB-10.2.14+maria~jessie mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [repldb]> desc user;
+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| user_name | varchar(20) | YES  |     | NULL    |       |
+-----------+-------------+------+-----+---------+-------+
1 row in set (0.00 sec)

생성했던 user테이블이 복구가 잘되었는지 확인합니다.

Master 컨테이너에서 Slave 컨테이너로 Replication을 진행하기 위해서
Slave 컨테이너가 Master 컨테이너의 Log파일의 이름과 위치를 알아야합니다.
그러므로 MariaDB Master 컨테이너에 접속하여 현재 Log파일의 이름과 위치정보를 알아옵니다.

$ docker exec -it maria-master bash
root@a2d239ad6147:/# mysql -uroot -p루트비밀번호
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 13
Server version: 10.2.14-MariaDB-10.2.14+maria~jessie-log mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> show master status\G
*************************** 1. row ***************************
            File: maria-bin.000003
        Position: 1068
    Binlog_Do_DB:
Binlog_Ignore_DB:
1 row in set (0.00 sec)

현재 Master 컨테이너의 Log파일 이름은 maria-bin.000003 이며, 위치는 1068 인 것을 볼 수 있습니다.

MariaDB Slave 설정

마지막으로 MariaDB에 Slave를 설정합니다.

$ docker exec -it maria-slave bash
root@f8bce6dba9f6:/# mysql -uroot -p루트비밀번호
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 11
Server version: 10.2.14-MariaDB-10.2.14+maria~jessie mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> change master to 
    -> master_host="maria-master",
    -> master_user="repl",
    -> master_password="사용자비밀번호",
    -> master_log_file="maria-bin.000003",
    -> master_log_pos=1068;
Query OK, 0 rows affected (0.01 sec)

MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.00 sec)

조금전에 알아 왔던 MariaDB Master 컨테이너의 Log파일 이름과 위치를 입력합니다. MariaDB Slave 컨테이너의 마스터를 MariaDB Master 컨테이너로 설정해주고,
Slave 서버로 동작하도록 설정합니다.

MariaDB Slave 설정 확인

MariaDB Slave 컨테이너가 Slave 서버로 잘 동작하는지 확인합니다.

MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: maria-master
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: maria-bin.000003
          Read_Master_Log_Pos: 1068
               Relay_Log_File: mysqld-relay-bin.000002
                Relay_Log_Pos: 555
        Relay_Master_Log_File: maria-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 1068
              Relay_Log_Space: 865
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 1
               Master_SSL_Crl:
           Master_SSL_Crlpath:
                   Using_Gtid: No
                  Gtid_IO_Pos:
      Replicate_Do_Domain_Ids:
  Replicate_Ignore_Domain_Ids:
                Parallel_Mode: conservative
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
1 row in set (0.00 sec)

해당 내용 중 Last_IO_Errno 부분에 0인 경우 Replication이 정상적으로 동작하는것을 의미합니다.

Replication Test

Replication이 정상적으로 동작하고 있는지 MariaDB Master 컨테이너에서 INSERT 쿼리를 통해서 데이터베이스에 변화를 줍니다.

$ docker exec -it maria-master bash
root@a2d239ad6147:/# mysql -uroot -p루트비밀번호 repldb
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 15
Server version: 10.2.14-MariaDB-10.2.14+maria~jessie-log mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [repldb]> insert into user (user_name) values ('admin');
Query OK, 1 row affected (0.01 sec)

MariaDB [repldb]> select * from user;
+-----------+
| user_name |
+-----------+
| admin     |
+-----------+
1 row in set (0.00 sec)

MariaDB Master 컨테이너에서 정상적으로 데이터가 삽입된것을 확인했습니다.

$ docker exec -it maria-slave bash
root@f8bce6dba9f6:/# mysql -uroot -p루트비밀번호 repldb
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 16
Server version: 10.2.14-MariaDB-10.2.14+maria~jessie mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [repldb]> select * from user;
+-----------+
| user_name |
+-----------+
| admin     |
+-----------+
1 row in set (0.00 sec)

MariaDB Slave 컨테이너에서도 정상적으로 데이터가 삽입되어져 있는 것을 확인 할 수 있었습니다.

이후 개발을 진행할 때 Master 서버에서는 Write(쓰기)만 가능하며,
Slave 서버에서는 Read(읽기) 만 가능하도록 구현하면 되겠습니다!

태그DockerMariaDB