(続)MySQLでのレプリケーション 〜 実践編2「レプリケーションの運用」

MySQLでのレプリケーション」ではレプリケーションの概要を述べ、「(続)MySQLでのレプリケーション 〜 実践編1「レプリケーションの設定」」では実際にMySQLレプリケーション設定を行い、レプリケーション構成を稼働させた。

今回は、MySQLを稼働させた後に必要なことや遭遇することを、少しだけだが考えてみる。
他にも監視など、運用するにあたって必要なことは沢山あるけど、いったんはこの程度で。

レプリケーションの稼働確認
◎バイナリログの確認
◎バイナリログのローテーション
◎バイナリログの削除
レプリケーションの障害
◎スレッドの停止

レプリケーションの稼働確認
マスタが稼働しており、スレーブが稼働しており、両者の整合性がとれていればレプリケーションは正常に稼働している判断できるだろう。以下、これらの3点から確認する。
1.マスタの稼働確認
マスタのmysqldに接続して状態を確認する。

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

2.スレーブの稼働確認
スレーブのmysqldに接続して状態を確認する。レプリケーションが稼働しているかを判断するには「Slave_IO_Running」、「Slave_SQL_Running」がYESであることを確認すればよい。

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: 973
               Relay_Log_File: mysqld-relay-bin.000015
                Relay_Log_Pos: 647
        Relay_Master_Log_File: master-bin.000015
             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: 973
              Relay_Log_Space: 821
              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: 131
                  Master_UUID: 4c913370-38f0-11e4-aafd-000c29dbe969
             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:
     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)

3.マスタでの状態とスレーブでの状態の整合性
スレーブでの「show slave status」の結果と、マスタでの「show master status」の結果は、次の点を比較すれば良い。

・「Slave_IO_Running」、「Slave_SQL_Running」がYESであること
※)「Slave_IO_Running」がNOである場合、マスタからバイナリを取得できていない。「Slave_SQL_Running」がNOの場合、リレーログから読み込んだ情報の反映に失敗している。
・スレーブでの「show slave status」の「Master_Log_File」および「Relay_Master_Log_File」のファイル名が、マスタでの「show master status」のFile名と一致していること
・スレーブでの「show slave status」の「Exec_Master_Log_Pos」が、マスタでの「show master status」のPositionと一致していること。
※)この値が異なっていてもレプリケーションの動作には問題がないが、マスタとスレーブでのデータの状態が異なることを意味しており、負荷分散の用途で使用している場合は特に注意が必要。

今回は一致していることが確認された。

◎バイナリログの確認
バイナリログが出力されていることが確認できたが、実際に中身を目視で確認する方法について述べる。
バイナリログはmysqlbinlogコマンドで確認することができる。

root@ubuntu:~# mysqlbinlog /var/log/mysql/master-bin.00001
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
mysqlbinlog: File '/var/log/mysql/master-bin.00001' not found (Errcode: 2 - No such file or directory)
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

これを使うタイミングは、例えばバックアップの時である。
スレーブが2台あって、1台が故障して2台目のバイナリログを使用して復旧しようとした場合、1台目と2台目のバイナリログの差分を確認して、差分になっているクエリを実行する場合がある(進んでいる方のバイナリログから進んでいるクエリを抽出し、遅れているサーバへ反映させる)。


◎バイナリログのローテーション
バイナリログはMySQLによってローテーションされる。
バイナリログにはサイズ上限値があり、その上限値に達した時点でローテートされる。サイズ上限値のデフォルトは1GBだが、
my.cnfのmax_binlog_sizeで指定することで変更可能である。
なお、mysqladmin flush-logsを使用することで手動でローテートさせることも可能である。

root@ubuntu:/var/log/mysql# ls -l
-rw-rw---- 1 mysql adm  168 Sep 20 07:53 master-bin.000008
-rw-rw---- 1 mysql adm  168 Sep 20 08:07 master-bin.000009
-rw-rw---- 1 mysql adm  120 Sep 20 08:07 master-bin.000010

root@ubuntu:/var/log/mysql# mysqladmin flush-logs -uroot -p
root@ubuntu:/var/log/mysql# ls -l
-rw-rw---- 1 mysql adm  168 Sep 20 07:53 master-bin.000008
-rw-rw---- 1 mysql adm  168 Sep 20 08:07 master-bin.000009
-rw-rw---- 1 mysql adm  168 Sep 20 08:08 master-bin.000010
-rw-rw---- 1 mysql adm  120 Sep 20 08:08 master-bin.000011

もしくは、mysqldに接続してFLUSH LOGSを打ち込んでも良い。

mysql> FLUSH LOGS;
Query OK, 0 rows affected (0.01 sec)
root@ubuntu:/var/log/mysql# ls -l
-rw-rw---- 1 mysql adm  168 Sep 20 07:53 master-bin.000008
-rw-rw---- 1 mysql adm  168 Sep 20 08:07 master-bin.000009
-rw-rw---- 1 mysql adm  168 Sep 20 08:08 master-bin.000010
-rw-rw---- 1 mysql adm  120 Sep 20 08:08 master-bin.000011
-rw-rw---- 1 mysql adm  120 Sep 20 08:10 master-bin.000012

◎バイナリログの削除
バイナリログはローテーションされるが自動的に削除されるわけではない。そのため、レプリケーションを運用しているとバイナリログのファイルの容量は大きくなっていく。
これを防ぐためには、次の2通りの方法がある。

1.expire_logs_daysパラメータを設定することで、指定日より前のバイナリログファイルを自動的に削除する
2.手動でPURGE BINARY LOGS BEFORE 'yyyy-mm-dd HH:MM:SS';を実行することで指定日時より前のバイナリログを削除する

2番目の方法を試してみる。

root@ubuntu:/var/log/mysql# ls -l
-rw-rw---- 1 mysql adm  168 Sep 19 07:54 master-bin.000001
-rw-rw---- 1 mysql adm  143 Sep 19 22:20 master-bin.000002
-rw-rw---- 1 mysql adm  143 Sep 19 23:18 master-bin.000003
-rw-rw---- 1 mysql adm  143 Sep 19 23:28 master-bin.000004
-rw-rw---- 1 mysql adm  143 Sep 19 23:39 master-bin.000005
-rw-rw---- 1 mysql adm  143 Sep 19 23:54 master-bin.000006
-rw-rw---- 1 mysql adm  519 Sep 20 00:54 master-bin.000007
-rw-rw---- 1 mysql adm  168 Sep 20 07:53 master-bin.000008

ここで9月19日以前のバイナリログを削除してみる。

mysql> PURGE BINARY LOGS BEFORE '2014-09-20';
Query OK, 0 rows affected (0.03 sec)

確認する。

root@ubuntu:/var/log/mysql# ls -l
-rw-rw---- 1 mysql adm  519 Sep 20 00:54 master-bin.000007
-rw-rw---- 1 mysql adm  168 Sep 20 07:53 master-bin.000008

レプリケーションの障害
障害といっても様々だが、ここでは下記について述べる。

■スレーブの障害
・スレーブでSQLプロセスが停止した場合
■マスタの障害
・マスタで障害は発生してマスタが停止し、スレーブをマスタに昇格させる場合

・スレーブでSQLプロセスが停止した場合
エラーになった原因のクエリを無視しても良い場合は、無視するバイナリログ中のクエリ数をsql_slave_skip_counterで指定してからスレーブを開始すると指定したクエリを無視してスレーブを起動することができる。

mysql> set global sql_slave_skip_counter=1;
mysql>start slave;

この方法で対処できない場合は、my.cnf のslave-skip-errorsにLast_Errnoの数字を記述して、エラーを強制的にスキップする(指定したエラーがでても、レプリケーションを続行するように SQL スレッドに指示する)。

・マスタで障害が発生してマスタが停止し、スレーブをマスタに昇格させる場合
MySQLの公式ドキュメントを参照。
別途実践。
下記資料も参考になるかも。

◎スレッドの停止
IO スレッド、または SQL スレッドのどちらかを別々に一時停止することができる。
まずはIOスレッドの停止。これにより、スレーブはマスタからのバイナリ ログの読み込みを止める。

mysql> show slave status \G;
*************************** 1. row ***************************
・・・・・・・・・・
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

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

mysql> show slave status \G;
*************************** 1. row ***************************
・・・・・・・・・・
             Slave_IO_Running: No
            Slave_SQL_Running: Yes

次に、SQLスレッドの停止。これにより、スレーブは未処理のリレー ログのイベント処理を停止する。

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

mysql> show slave status \G;
*************************** 1. row ***************************
・・・・・・・・・・
             Slave_IO_Running: No
            Slave_SQL_Running: No