(続)MySQLでのレプリケーション 〜 実践編1「レプリケーションの設定」

MySQLでのレプリケーション」では、レプリケーションの定義や種類、概念、レプリケーションの用途およびメリット・デメリットについて触れた。
今回は、実際にレプリケーション環境を構築してみる。
その前に、レプリケーション環境を構築するといっても、次の3パターンが考えられる。
そして、どのパターンかによって、スレーブを構築する際に実施しなければならないことが若干変わるので注意が必要である。

【パターン1】マスタもスレーブも新規に作成する場合
この場合は、マスタとスレーブをそれぞれ作成して同時に稼働させれば良いだろう。

【パターン2】マスタが既に稼働している環境に、スレーブを追加する場合
この場合は、スレーブを構築するまでにマスタが稼働していたことにより蓄積されたマスタのデータを、スレーブにコピーしてからスレーブを稼働させる必要がある。つまり、マスタの状態とスレーブの状態の同期化をしてから、スレーブを稼働させる必要がある。なぜなら、レプリケーションの仕組み上、スレーブを稼働した後のデータからレプリケートされるからのようだ。マスタがバイナリログに更新情報を記録し始めて以降のデータしかスレーブに反映することができないから。例えば、もともとマスタがバイナリログを出力しておらず、途中からバイナリログに更新情報を記録し始めていた場合、バイナリログを使用する前の情報はマスタとスレーブでデータベースファイルを同期してスレーブに反映させるしか無い。

【パターン3】既にレプリケーション環境が構築されているところにスレーブを追加する場合
この場合は、パターン2と同じ方法も使えるが、既に稼働しているスレーブとデータを同期する方法も可能である。

それでは次に作業内容を確認する。ここではパターン2を実施する想定で作業内容を洗い出してみた。

マスタ側の作業 スレーブ側の作業
パラメータ設定 ・マスタのserver-idの設定 ・スレーブのserver-idの設定
・バイナリログの出力設定(log-binの設定) ・バイナリログの出力設定(log-binの設定)
※)スレーブの場合、バイナリログの出力設定は必須ではないが、スレーブをマスタに昇格させる場合も考慮すると設定しておいたほうが良いかも。
レプリケーション用ユーザの作成 スレーブからマスタに接続するためのレプリケーション用ユーザをマスタに作成する。
マスタとスレーブのデータ同期 【DBファイルをコピーする方法】
1.テーブルを読み取り専用にロックする。
2.マスタの状態を確認し、FileとPositionの情報をメモする。
3.mysqldを停止する。
4.データベースファイルをスレーブにコピーする。
※)master.infoファイル、バイナリログファイル、リレーログファイルはコピー不要。

【mysqldumpでデータダンプする方法】
1.mysqldumpでマスタデータをダンプする。
※)テーブルはREADロックされる
2.ダンプしたSQLファイルをスレーブにコピーする。
【DBファイルをコピーする方法】
5.mysqldを停止する。
6. 4でマスタからコピーしたデータを配置する。
7.mysqldに--skip-slave-startオプションをつけて、スレーブを起動せずにmysqlを起動する。
8.change master文によってマスタの設定をする。
※)ここで2でメモしたFileとPosition情報を使用する。
9.start slaveを実行し、スレーブを起動する。これによりレプリケーションが開始する(はず)。

【mysqldumpでデータダンプする方法】
3.mysqldに--skip-slave-startオプションをつけて、スレーブを起動せずにmysqlを起動する。
4.change master文によってマスタの設定をする。
5.マスタからコピーしたダンプSQLファイルを実行する。
6.start slaveを実行し、スレーブを起動する。これによりレプリケーションが開始する(はず)。

※)(追記)bind-addressの設定も確認し、スレーブがマスタへ接続できるように設定しておくこと。

作業内容を洗い出したところで、実践してみる。
まずは作業順序に制約が無い設定ファイルの編集を行い、次にマスタとスレーブのデータ同期を行う。
1.設定ファイル(/etc/mysql/my.cnf)の編集
◎マスタ側での作業

root@ubuntu:~# vi /etc/mysql/my.cnf
log-bin = /var/log/mysql/master-bin
log-bin-index = /var/log/mysql/master-bin
server-id=131

◎スレーブ側での作業

root@ubuntu:~# vi /etc/mysql/my.cnf
log-bin = /var/log/mysql/master-bin
log-bin-index = /var/log/mysql/master-bin
server-id=132

2.レプリケーション用ユーザの作成(マスタ側での作業)

root@ubuntu:~# mysql -uroot -p

mysql> GRANT REPLICATION SLAVE ON *.* TO 'slave-mysql'@'%' IDENTIFIED BY 'password';
Query OK, 0 rows affected (0.05 sec)

3.マスタとスレーブのデータ同期
【DBファイルをコピーする方法】
1.マスタDB でテーブルを読み取り専用にロックする

mysql> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)

2.マスタDBでマスタの状態を確認し、FileとPositionの情報をメモする

mysql> show master status\G;
*************************** 1. row ***************************
             File: master-bin.000009
         Position: 325
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)

実際にディレクトリを確認するとmaster-bin.000009まで作成されている(この確認は不要)。

root@ubuntu:~# ls -l /var/log/mysql
total 1456
-rw-r----- 1 mysql adm  12217 Sep 18 19:07 error.log
-rw-r----- 1 mysql adm     20 Sep 17 12:57 error.log.1.gz
-rw-r----- 1 mysql adm     20 Sep 16 07:56 error.log.2.gz
-rw-r----- 1 mysql adm  11274 Sep 15 18:33 error.log.3.gz
-rw-r----- 1 mysql adm   3111 Sep 13 05:33 error.log.4.gz
-rw-r----- 1 mysql adm   1358 Sep 12 09:50 error.log.5.gz
-rw-r----- 1 mysql adm   2338 Sep 11 04:52 error.log.6.gz
-rw-r----- 1 mysql adm   4226 Sep 10 07:22 error.log.7.gz
-rw-rw---- 1 mysql adm 496117 Sep 18 19:25 general.log
-rw-rw---- 1 mysql adm    143 Sep 14 18:50 master-bin.000001
-rw-rw---- 1 mysql adm    143 Sep 14 18:57 master-bin.000002
-rw-rw---- 1 mysql adm    143 Sep 14 18:58 master-bin.000003
-rw-rw---- 1 mysql adm    143 Sep 14 19:07 master-bin.000004
-rw-rw---- 1 mysql adm 898676 Sep 16 07:56 master-bin.000005
-rw-rw---- 1 mysql adm    168 Sep 17 12:57 master-bin.000006
-rw-rw---- 1 mysql adm    168 Sep 18 07:59 master-bin.000007
-rw-rw---- 1 mysql adm    143 Sep 18 19:07 master-bin.000008
-rw-rw---- 1 mysql adm    325 Sep 18 19:19 master-bin.000009
-rw-rw---- 1 mysql adm    297 Sep 18 19:07 master-bin.index

3.マスタDBのmysqldを停止する

root@ubuntu:~# /etc/init.d/mysql stop
....
 * MySQL Community Server 5.6.20 is stopped

4.マスタDBからデータベースファイルをスレーブDBにコピーする
/var/lib/mysqlをdatadirに指定しているので、それをスレーブにコピーする。
※)master.infoファイル、バイナリログファイル、リレーログファイルはコピー不要。
※)(追記)データディレクトリ直下に有る、auto.cnfもコピー不要。これをコピーしてしまうと、UUIDがマスタとスレーブで重複してスレーブが稼働しなかった。

5.スレーブDBでmysqldを--skip-slave-startオプションを付与して起動する
/etc/mysql/my.cnfを編集して「skip-slave-start」というキーワードを追記。その後、/etc/init.d/mysqlを起動する。

root@ubuntu:/# vi /etc/mysql/my.cnf
root@ubuntu:/var/lib# /etc/init.d/mysql start

スレーブが起動していない常態かどうかをmysqladminコマンドを使用して確認する。

root@ubuntu:/var/lib# mysqladmin extended-status -uroot -p
Enter password:
+-----------------------------------------------+-------------+
| Variable_name                                 | Value       |
+-----------------------------------------------+-------------+
| Aborted_clients                               | 0           |
| Aborted_connects                              | 0           |
| Binlog_cache_disk_use                         | 0           |
・・・・・・・・・・・・・・・・・・・
| Slave_heartbeat_period                        | 0.000       |
| Slave_last_heartbeat                          |             |
| Slave_open_temp_tables                        | 0           |
| Slave_received_heartbeats                     | 0           |
| Slave_retried_transactions                    | 0           |
| Slave_running                                 | OFF         |
・・・・・・・・・・・・・・・・・・・

6.スレーブでmysqldに接続してchange masterクエリを発行する。

mysql> change master to
    -> master_host='192.168.133.131',
    -> master_user='slave-mysql',
    -> master_password='password',
    -> master_log_file='master-bin.000009',
    -> master_log_pos=325;
Query OK, 0 rows affected, 2 warnings (0.04 sec)

7.スレーブDBでスレーブを起動する

mysql> start slave

スレーブが稼働したかを確認する。

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Connecting to master
                  Master_Host: 192.168.133.131
                  Master_User: slave-mysql
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000009
          Read_Master_Log_Pos: 325
               Relay_Log_File: mysqld-relay-bin.000001
                Relay_Log_Pos: 4
        Relay_Master_Log_File: master-bin.000009
             Slave_IO_Running: Connecting
            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: 325
              Relay_Log_Space: 120
              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: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 2003
                Last_IO_Error: error connecting to master 'slave-mysql@192.168.133.131:3306' - retry-time: 60  retries: 1
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 0
                  Master_UUID:
             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 the slave I/O thread to update it
           Master_Retry_Count: 86400
                  Master_Bind:
      Last_IO_Error_Timestamp: 140919 22:58:38
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 0
1 row in set (0.00 sec)

「 Slave_SQL_Running: Yes」であり、SQLプロセスは正常に稼働したようだ。しかし、「Slave_IO_Running: Connecting」であり、IOプロセスがYESとならない。
さっそく、/var/log/mysql/error.logを確認するとエラーが発生している。

2014-09-19 22:59:38 17278 [ERROR] Slave I/O: error connecting to master 'slave-mysql@192.168.133.131:3306' - retry-time: 60 retries: 2, Error_code: 2003

エラーコード2003はアクセス拒否のエラーだから、ホスト側のアクセス許可設定を調べる。
可能性としては、次の2通りくらいだろうか。

MySQLの設定でスレーブからマスタへの接続が拒否されている
Linuxファイアウォールの設定、iptablesの設定で、スレーブからマスタへの接続が拒否されている

まず、/etc/mysql/my.cnfでbind-addressの設定を確認してみると、「bind-address=127.0.0.1」となっていた。これだと127.0.0.1への接続しか受け付けない
試しに、mysqlコマンドを使用してslave-mysqlユーザでスレーブからマスタにリモート接続してみるが確かに接続できない。

root@ubuntu:/var/lib# mysql -h 192.168.133.131 -u slave-mysql -p
Enter password:
ERROR 2003 (HY000): Can't connect to MySQL server on '192.168.133.131' (111)

そこで、マスタのmy.cnfのbind-addressの設定を変更して、192.168.133.131への接続を許可するようにする。
今回は練習なので一旦bind-addressをコメントアウトして再度マスタへ接続を試みると今度は成功。

root@ubuntu:/var/lib# mysql -h 192.168.133.131 -u slave-mysql -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.

スレーブを再起動して再度スレーブの状態を確認する。

root@ubuntu:/var/lib# /etc/init.d/mysql restart
root@ubuntu:/var/lib# mysql -uroot -p
mysql>
mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State:
                  Master_Host: 192.168.133.131
                  Master_User: slave-mysql
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000009
          Read_Master_Log_Pos: 325
               Relay_Log_File: mysqld-relay-bin.000004
                Relay_Log_Pos: 4
        Relay_Master_Log_File: master-bin.000009
             Slave_IO_Running: No
            Slave_SQL_Running: Yes

スレーブが起動していないので、/var/log/mysq/error.logを確認する。

2014-09-19 23:39:07 19031 [ERROR] Slave I/O: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work. Error_code: 1593

UUIDがユニークじゃないと怒られている。server-idはマスタとスレーブで異なるものを設定したのに、何故だろうと思ったが、まずはUUIDがどこで設定されているのかを調べる。
UUIDは/etc/mysql/my.cnfで設定するものではなく、MySQLのデータディレクトリ(今回は/var/lib/mysql)直下にあるauto.cnfファイルに設定されている。
ここで、マスタのデータディレクトリのバックアップを取得して、スレーブに配置した際に全てをコピーしたのだった。スレーブのauto.cnfファイルを削除してからスレーブを再起動する(ただし、削除する前にバックアップはとっておくこと)。

スレーブの稼働状況を確認する。

root@ubuntu:/var/lib# mysqladmin extended-status -uroot -p
Enter password:
+-----------------------------------------------+-------------+
| Variable_name                                 | Value       |
+-----------------------------------------------+-------------+
| Aborted_clients                               | 0           |
・・・・・・・・・・・
| Slave_retried_transactions                    | 0           |
| Slave_running                                 | ON          |

どうやらスレーブは稼働したようだ。mysqldに接続してshow slave statusによって確認してみる。

root@ubuntu:/var/lib# mysql -uroot -p
mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.133.131
                  Master_User: slave-mysql
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000015
          Read_Master_Log_Pos: 120
               Relay_Log_File: mysqld-relay-bin.000012
                Relay_Log_Pos: 284
        Relay_Master_Log_File: master-bin.000015
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

「Slave_IO_Running: Yes」、「Slave_IO_Running: Yes」となっている。漸くレプリケーションが稼働した。

ためしに、マスタにテーブルを作成して、それがスレーブに反映されるかを確認してみる。
まず、マスタ(192.168.133.131)とスレーブ(192.168.133.132)に接続する。


次に、テスト用のtestdbに接続する。そして、テーブルの数を確認する。

最後に、マスタにテーブルを作成して、スレーブにレプリケイトされるかを確認する。

成功。

◎最後に
・今回は練習だから良いが、本番作業でこうやっていくつも詰まっていたら困るので、当然手順の精緻化は必須。
・今回はコールドバックアップを例にしたが、mysqldumpを使用してデータダンプする方法もある。さらにInnoDBに限定すれば、--single-transactionオプションを使用してロックの時間を短くすることができる。