ツナワタリマイライフ

日常ネタから技術ネタ、音楽ネタまで何でも書きます。

MySQL5.7でレプリケーションを試す

はじめに

仕事でMariaDBを扱っているのですが、本屋でMySQLまわりもパラパラと見ていると、この本が詳しそうだったので書いました。

詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド (NEXT ONE)

詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド (NEXT ONE)

まず第1章のMySQLの概要、第2章のレプリケーションを読みました。本書はMySQL5.7の膨大な新機能をセクションごとに解説する本ですが、MySQL自体初学の人間(私とか)でも非常に詳しい説明がなされていて、この本を最初に見ればよかった、という思いです。

今回、第2章で扱われているレプリケーションについて、MySQL5.7の導入とともに実践してみます。

MySQL5.7のinstall

CloudGarageさんお世話になります。やっぱりレプリケーションもできる、3台貸し出しは本当に助かる。

take-she12.hatenablog.com

installは以下の記事通り、CentOS 7.3に対して行いましたので省略。

weblabo.oscasierra.net

# yum remove mariadb-libs
# rm -rf /var/lib/mysql/
# yum localinstall http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm
# yum -y install mysql-community-server
# systemctl enable mysqld.service
# systemctl start mysqld.service

設定

初期パスワードがログに出ます。

[root@mysql57-2 ~]# grep "temporary password" /var/log/mysqld.log 
2017-11-08T11:49:27.602209Z 1 [Note] A temporary password is generated for root@localhost: By30kodp0g/v

ログイン後に、パスワードをrootに変更したいですが、制限が厳しいのでそれを緩和させてやります。

以下の記事が参考になりました。

qiita.com

[root@mysql57-2 ~]# mysql -uroot -pBy30kodp0g/v
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.20

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

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

mysql> set password for root@localhost=password('passwordPASSWORD@999');
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> SET GLOBAL validate_password_length=4;
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL validate_password_policy=LOW;
Query OK, 0 rows affected (0.00 sec)

mysql> set password for root@localhost=password('root');
Query OK, 0 rows affected, 1 warning (0.00 sec)

masterノードの設定

bin_log(バイナリログ)の有効化と、replicationのためのserver_idを設定してやります。serveri_idはmasterとslaveで異なる値を設定しましょう。

[root@mysql57 ~]# tail -n7 /etc/my.cnf
# replication
server-id=1
log-bin=mysql-bin

# pasword policy
validate_password_length=4
validate_password_policy=LOW

ちなみにバイナリログとは、データベース上のすべてのテーブル変更の記録です。show binary logsコマンドで一覧できます。

mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       177 |
| mysql-bin.000002 |      1181 |
+------------------+-----------+
2 rows in set (0.00 sec)

このバイナリログをSQLのレベルでレプリケーションに使用する方式をStatementBasedReplication(SBR)と呼びます。(statement=SQL)しかし、この方法だとSQLの種類によってデータベースの変更結果がmasterとslaveで異なる場合がある問題があります。(UUID関数など)

その問題に対処するのが行ベースレプリケーション(RowBasedReplication, RBR)です。SQLの実行結果、変更が生じた行の前後を記録する方式なので、SQL文で結果が異なっても大丈夫です。

次にslaveが接続するよためのuserを作成します。

ログが流れてしまいましたが、

> create user 'repl' identified by 'repl';
> grant replication slave on *.* to 'repl';

でいけると思います。以下を参考にしました。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 17.1.1.3 レプリケーション用ユーザーの作成

DBのdump

面倒なことに、slaveに対してはmasterのdbのdumpを流し込んで、同じレベルにしなければなりません。

slaveがmasterに接続する場合、現在のbinary_log_fileの名前と、log_positionという値が必要であるため、その情報が出力される形式でdumpを取る必要があります。

[root@mysql57 ~]# mysqldump -uroot -proot --master-data=2 -A >mysql.dump 
mysqldump: [Warning] Using a password on the command line interface can be insecure.
[root@mysql57 ~]# 

CLIでpassword打つと怒られちゃいますね。このdumpをscpかなんかでslaveに送って、restoreしてください。

slaveの設定

masterと同じでいいです。configでserver_idだけは異なるものにしてください。

レプリケーションの設定です。

mysql> change master to 
    -> master_host='192.168.0.11',
    -> master_port=3306,
    -> master_log_file='mysql-bin.000002',
    -> master_log_pos=990,
    -> master_heartbeat_period=60;
Query OK, 0 rows affected (0.01 sec)

おっと、ここのlog_fileとlog_posはdbのdumpから確認してください。

[root@mysql57-2 ~]# grep -e '-- CHANGE MASTER TO MASTER_LOG_FILE' dump.sql 
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=990;

replicationをはじめるにはslaveでstart slave statementを実行します。結果は、Slave_IO_Runningがyesであることを確認しましょう。

mysql> start slave user = 'repl' password = 'repl';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show slave status;
+----------------------------------+--------------+-------------+-------------+---------------+------------------+---------------------+----------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+----------------------------+-----------+---------------------+--------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+
| Slave_IO_State                   | Master_Host  | Master_User | Master_Port | Connect_Retry | Master_Log_File  | Read_Master_Log_Pos | Relay_Log_File             | Relay_Log_Pos | Relay_Master_Log_File | Slave_IO_Running | Slave_SQL_Running | Replicate_Do_DB | Replicate_Ignore_DB | Replicate_Do_Table | Replicate_Ignore_Table | Replicate_Wild_Do_Table | Replicate_Wild_Ignore_Table | Last_Errno | Last_Error | Skip_Counter | Exec_Master_Log_Pos | Relay_Log_Space | Until_Condition | Until_Log_File | Until_Log_Pos | Master_SSL_Allowed | Master_SSL_CA_File | Master_SSL_CA_Path | Master_SSL_Cert | Master_SSL_Cipher | Master_SSL_Key | Seconds_Behind_Master | Master_SSL_Verify_Server_Cert | Last_IO_Errno | Last_IO_Error | Last_SQL_Errno | Last_SQL_Error | Replicate_Ignore_Server_Ids | Master_Server_Id | Master_UUID                          | Master_Info_File           | SQL_Delay | SQL_Remaining_Delay | Slave_SQL_Running_State                                | Master_Retry_Count | Master_Bind | Last_IO_Error_Timestamp | Last_SQL_Error_Timestamp | Master_SSL_Crl | Master_SSL_Crlpath | Retrieved_Gtid_Set | Executed_Gtid_Set | Auto_Position | Replicate_Rewrite_DB | Channel_Name | Master_TLS_Version |
+----------------------------------+--------------+-------------+-------------+---------------+------------------+---------------------+----------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+----------------------------+-----------+---------------------+--------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+
| Waiting for master to send event | 192.168.0.11 | repl        |        3306 |            60 | mysql-bin.000002 |                 990 | mysql57-2-relay-bin.000003 |           320 | mysql-bin.000002      | Yes              | Yes               |                 |                     |                    |                        |                         |                             |          0 |            |            0 |                 990 |             531 | None            |                |             0 | No                 |                    |                    |                 |                   |                |                     0 | No                            |             0 |               |              0 |                |                             |                1 | ca6806d3-c473-11e7-9e52-fa163e4c44c2 | /var/lib/mysql/master.info |         0 |                NULL | Slave has read all relay log; waiting for more updates |              86400 |             |                         |                          |                |                    |                    |                   |             0 |                      |              |                    |
+----------------------------------+--------------+-------------+-------------+---------------+------------------+---------------------+----------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+----------------------------+-----------+---------------------+--------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+
1 row in set (0.00 sec)

masterで変更を加えた結果が、slaveでも反映されていれば成功です。

master側ではこのようなログがでていました。

2017-11-08T12:10:16.099322Z 12 [Note] Start binlog_dump to master_thread_id(12) slave_server(2), pos(mysql-bin.000002, 990)

slave

2017-11-08T12:09:34.187408Z 2 [Note] Slave SQL thread for channel '' initialized, starting replication in log 'mysql-bin.000002' at position 990, relay log './mysql57-2-relay-bin.000001' position: 4
2017-11-08T12:09:34.188654Z 0 [Note] End of list of non-natively partitioned tables
2017-11-08T12:10:16.096654Z 6 [Note] Slave I/O thread for channel '': connected to master 'repl@192.168.0.11:3306',replication started in log 'mysql-bin.000002' at position 990

slave側ではslave IO threadがmaster threadからのbinary logを受け取り、relay logに書き込みます。それをslave SQL threadがストレージエンジンに書き込むんですね。

おわりに

そこそこ簡単にMySQLレプリケーションが実現できましたが、この感じだとデータに差分がある状態ではレプリケーションができないのかな?と思いました。つまり、稼働中のクラスタに対して、稼働したまま新規slaveを追加するにはどうしたらいいのか、それともできないのか、疑問に思いました。