RDS からEC2へ Multi-master replicationを組んでみた

この記事はRetty Inc. Advent Calendar 2017 15日目の記事です。
昨日は @isaoeka  さんによる [OS X アプリケーション(Today Extension)開発に触れてみる](https://qiita.com/isaoeka/items/fde975ab14b7a1d93def)  でした。

こんにちは、Rettyでインフラを担当している@takumi-suzukiです。
７月から宮城でリモート勤務をしていて、１１月から東京に帰ってきました。
東京はamazonで注文したものが翌日には届いて最高です。

今回は、MySQLを調べていて興味をもったMulti-master replicationについて書きます。
業務でも活かせるように、AWSのRDSを使用していたものから、EC2にレプリケーションを貼ります。

# 使用したサーバー
1. Master DB01 (RDS MySQL 5.7.19)
1. Master DB02 (RDS MySQL 5.7.19)
1. Replica DB01(EC2 AmazonLinux2)

# ReplicaDB の準備
最近リリースされた、AmazonLinux 2にMySQL 5.7をインストールして使用します。

## MySQL5.7のインストール
AmazonLinuxで通常通り `yum install mysql` とかとやってしまうと、MariaDBが入ってしまうので、以下の方法でMySQLをインストールします。

```
# リポジトリ追加
$ sudo yum localinstall http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm

# 確認
$ yum info mysql-community-server

# インストール
$ sudo yum -y install mysql-community-server

[ec2-user@ip-172-22-246-193 ~]$ mysqld --version
mysqld  Ver 5.7.20 for Linux on x86_64 (MySQL Community Server (GPL))
[ec2-user@ip-172-22-246-193 ~]$

# 自動起動設定
$ sudo systemctl enable mysqld.service

# 起動
$ sudo systemctl start mysqld.service
```

## MySQL5.7の初期設定
MySQL5,7ではポリシーでMEDIUMが設定されているため、パスワードが厳し目に設定しなければいけません。
テスト的にやりたいのに、そんなパスワードは設定したくないため、以下の方法でポリシーを変更し、パスワード変更を行います。

```
# パスワード設定しないと諸々変更できないので、とりあえずのパスワードを設定します。
> set password for root@localhost=password('PassWord@0123456789');

# パスワードポリシーの変更
> SET GLOBAL validate_password_length=4;
> SET GLOBAL validate_password_policy=LOW;

# パスワード変更
> set password for root@localhost=password('root');
```

## my.cnfの設定
replicationが組めるように、以下の設定を追記します。

```
server-id=1024
relay_log_info_repository = TABLE
master_info_repository = TABLE
relay_log_recovery = ON
```

mysqlを再起動します
`sudo systemctl restart mysqld.service`

# レプリケーション設定
ここから、RDSとEC2でレプリケーションを組んでいきます。

## Master にReplication Userを作成
replication を組むためのuserをMasterとなるそれぞれのDBに対して作成します。
```
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%' IDENTIFIED BY 'repl';
```

## Master情報の確認
replicationを組むためにのmasterのLogとポジションを調べます。

```
mysql> show master status\G
*************************** 1. row ***************************
             File: mysql-bin-changelog.000021
         Position: 154
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 
1 row in set (0.03 sec)

mysql> show master status\G
*************************** 1. row ***************************
             File: mysql-bin-changelog.000021
         Position: 154
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 
1 row in set (0.03 sec)
```

## Replication 開始
Master情報をReplicaDBに設定します

```
> CHANGE MASTER TO
  MASTER_HOST='master01.********.ap-northeast-1.rds.amazonaws.com',
  MASTER_USER='repl',
  MASTER_PASSWORD='repl',
  MASTER_PORT=3306,
  MASTER_LOG_FILE='mysql-bin-changelog.000021',
  MASTER_LOG_POS=154,
  MASTER_CONNECT_RETRY=10
  for channel 'master01';

> CHANGE MASTER TO
  MASTER_HOST='master02.********.ap-northeast-1.rds.amazonaws.com',
  MASTER_USER='repl',
  MASTER_PASSWORD='repl',
  MASTER_PORT=3306,
  MASTER_LOG_FILE='mysql-bin-changelog.000022',
  MASTER_LOG_POS=154,
  MASTER_CONNECT_RETRY=10
  for channel 'master02';
```

以下のコマンドでReplicationを開始します。
```
start slave for channel 'master01';
start slave for channel 'master02';
```

## 確認
以下のようにして、それぞれのMasterとのreplicationが確立されているかを確認します。

```
mysql> mhow slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: test-master01.ckudyu9ubkf5.ap-northeast-1.rds.amazonaws.com
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: mysql-bin-changelog.000046
          Read_Master_Log_Pos: 521
               Relay_Log_File: ip-172-22-246-193-relay-bin-master1.000050
                Relay_Log_Pos: 754
        Relay_Master_Log_File: mysql-bin-changelog.000046
             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: 521
              Relay_Log_Space: 1038
              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: 1940910623
                  Master_UUID: 2a111330-e15e-11e7-8d0e-0a57ab429cea
             Master_Info_File: mysql.slave_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: master1
           Master_TLS_Version: 
*************************** 2. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: test-master02.ckudyu9ubkf5.ap-northeast-1.rds.amazonaws.com
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: mysql-bin-changelog.000045
          Read_Master_Log_Pos: 154
               Relay_Log_File: ip-172-22-246-193-relay-bin-master2.000050
                Relay_Log_Pos: 387
        Relay_Master_Log_File: mysql-bin-changelog.000045
             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: 671
              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: 1018574732
                  Master_UUID: bdeace00-e15e-11e7-b0c2-067018182636
             Master_Info_File: mysql.slave_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: master2
           Master_TLS_Version: 
2 rows in set (0.00 sec)
```

# テスト
master01とmaster02にINSERTを行い、ReplicaDBに反映されるかを確認します。

```tex:master1
mysql> INSERT INTO item (id,name) VALUES (1,"master1");
Query OK, 1 row affected (0.04 sec)

mysql> INSERT INTO item (id,name) VALUES (4,"master1");
Query OK, 1 row affected (0.03 sec)

mysql> SELECT * FROM item
    -> ;
+------+---------+
| id   | name    |
+------+---------+
|    1 | master1 |
|    4 | master1 |
+------+---------+
2 rows in set (0.04 sec)
```

```tex:master2
mysql> INSERT INTO item (id,name) VALUES (2,"master2");
Query OK, 1 row affected (0.04 sec)

mysql> INSERT INTO item (id,name) VALUES (3,"master22");
Query OK, 1 row affected (0.05 sec)

mysql> SELECT * FROM item ;
+------+---------+
| id   | name    |
+------+---------+
|    2 | master2 |
|    3 | master2 |
+------+---------+
2 rows in set (0.05 sec)

mysql> 
```

```tex:replicaDB
mysql> SELECT * FROM item;
+------+---------+
| id   | name    |
+------+---------+
|    2 | master2 |
|    3 | master2 |
|    1 | master1 |
|    4 | master1 |
+------+---------+
4 rows in set (0.00 sec)

mysql>
```
無事反映されてることを確認できました。

# まとめ
最近のタスクでDB周りをやっていて、RDS周りで調査がスムーズにできないために外だししたくて試してみました。
思ったほど、癖があるわけではなくすんなりとレプリケーションを組むことができました。
しかし、検証環境や調査環境で使う分にはいいですが、本番はあまり使いたくないなと思っている所存です！！


明日は captain( @takaaki-suzuki  ) の **NVIDIA DGX Station を試してみた** です。お楽しみに〜