들어가면서

Replication이란, 2대 이상의 DBMS로 데이터를 나누는 구조, Master / Slave 구성으로 이루어진다. 참고자료

  • Master DBMS : 데이터 등록,수정,삭제 요청시 바이너리 로그를 생성하여, Slave 서버로 전달 (동시성 높은 트렌젝션 부분 담당)

  • Slave DBMS : Master DBMS에서 전달받은 바이너리 로그를 이용하여, 데이터로 반영(데이터 요청시 사용) (읽기 전용 데이터 조회)

Master/Slave

활용 방법

  • Master DBMS가 장애시, Slave DBMS를 대신 사용가능(fail over)
  • DBMS 부화분산 목적, 사용자의 폭주로 인하여, 1대의 DB 서버가 감당할 수 없을때 사용

주의 사항

  • 호환성을 위해 Replication을 사용하는 Mysql 버전 동일하게 맞추기
  • 만약 버전이 다르면, Slave가 상위 버전으로 세팅
  • Repliacation 시동시 Master -> Slave 순으로 가동

Docker를 활용한 Mysql Replication

참고자료 디렉토리 구성은 아래와 같다.

디렉토리구성

실행순서

  1. master-slave 두 서버 띄우기
    docker-compose up -d
    
  2. internal IP 찾기
    • Network id를 먼저 찾는다.
      ❯ docker network ls
      NETWORK ID     NAME                    DRIVER    SCOPE
      c936b9b7cc42   repli_net-mysql         bridge    local
      
  • docker inspect {NETWORK ID}에서 IPv4Address에 해당하는 값을 기억한다.

❯ docker inspect c936b9b7cc42

[
    {
        "Name": "repli_net-mysql",
        "Id": "c936b9b7cc4214b978aa64d7397d218c0fe62dd76389971ef2134ea8a8560765",
        "Created": "2022-01-11T14:36:21.9461848Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.19.0.0/16",
                    "Gateway": "172.19.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "31b2a62702a6249c666076d7182a34c30ac3e2939ea6924b84b237fb6a57e915": {
                "Name": "repli_db-slave_1",
                "EndpointID": "afbd9ee57c687c50fab1b39be1b97919229fff04fc418269612c058cbff06554",
                "MacAddress": "02:42:ac:13:00:03",
                "IPv4Address": "172.19.0.3/16",
                "IPv6Address": ""
            },
            "43bb2e42864eaa10c730ae53c01ab9817a49c5c34db2eba62ce3e14f92779cdb": {
                "Name": "repli_db-master_1",
                "EndpointID": "6e2d8cc63e3fc5d6322ab2de3d6bf414ee49a885ded7e26d66b4afb9188e6090",
                "MacAddress": "02:42:ac:13:00:02",
                "IPv4Address": "172.19.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "net-mysql",
            "com.docker.compose.project": "repli",
            "com.docker.compose.version": "1.29.0"
        }
    }
]

  1. Slave에서 Master로 연결한다.

사실 이 부분에서 삽질을 조금했었다. 내가 마주했었던 오류는, “Error 1236 - “Could not find first log file name in binary log index file” 이었는데, slave 서버에서 MASTER_LOG_FILE을 세팅할 때, master 서버에 존재하는 log file을 기준으로 세팅을 해야한다.

이를 위해서 master 서버에서 아래 문구를 치면 이렇게 나온다.

mysql> SHOW BINARY LOGS;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       177 |
| mysql-bin.000002 |   3072319 |
| mysql-bin.000003 |       177 |
| mysql-bin.000004 |       154 |
+------------------+-----------+

이중에 없는 로그 파일 인덱스를 선택하면 에러가 난다. 그 후 아래와 같이 세팅을 맞춰줬다. 결론적으로, Slave_IO_Running: Yes / Slave_SQL_Running: Yes 으로 표시되면 동기화가 완료된 것이다.

mysql> CHANGE MASTER TO MASTER_HOST='172.19.0.3', MASTER_USER='root', MASTER_PASSWORD='password', MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=0;
Query OK, 0 rows affected, 2 warnings (0.00 sec)

mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.19.0.3
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000004
          Read_Master_Log_Pos: 154
               Relay_Log_File: mysql-relay-bin.000004
                Relay_Log_Pos: 367
        Relay_Master_Log_File: mysql-bin.000004
             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: 154
              Relay_Log_Space: 787
              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: 10
                  Master_UUID: fd513db6-72eb-11ec-890b-0242ac130002
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

테스트

결론적으로 테스트를 해보기 위해서, DB와 테이블 데이터를 직접 넣어보았다.

Master DB

mysql> use bootex;
Database changed

mysql> create table Member (ID int not null primary key, name varchar(100));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into Member(id, name)  values (1,"song")
    -> ;
Query OK, 1 row affected (0.01 sec)

Slave DB

mysql> show tables;
+------------------+
| Tables_in_bootex |
+------------------+
| Member           |
+------------------+
1 row in set (0.00 sec)

mysql> select * from Member;
+----+------+
| ID | name |
+----+------+
|  1 | song |
+----+------+
1 row in set (0.00 sec)