MySQLはバージョン5.7とそれ以降で、マルチソースレプリケーションができるようになりました。マルチソースレプリケーションを利用することで、複数のデータベースをマスターとしてレプリケーションを構築することが可能となります。過去にシャーディングしていたデータの再統合や集約データベースの作成など、構成次第でさまざまなデータベースを作成することができます。
今回はそんなマルチソースレプリケーションについて紹介します。
マルチソースレプリケーションのイメージ
マルチソースレプリケーションの準備
統合するスレーブ側でマルチソースレプリケーションを有効にするためには、master_info_repositoryとrelay_log_info_repositoryのtypeをTABLEとする必要があります。
スレーブ側が持つリレーログの情報は、mysql.slave_relay_log_info
に挿入されます。バージョン8.0.2とそれ以降のバージョンでは、master_info_repositoryとrelay_log_info_repositoryはデフォルトでTABLEに変更されました。slave_relay_log_infoの詳細については第53回 リレーログファイルについて をご確認ください。
続いて、スレーブ側に統合するデータベースを作成します。データの投入については、各マスターとなるデータベースからmysqldumpコマンドなどを用いてデータを取得し、スレーブ側に投入します。
最後に、マスター情報をスレーブ側に提供するCHANGE MASTER TO構文を実施します。マルチソースレプリケーションを実施する時は、CHANGE MASTER TO構文にFOR CHANNEL チャネル名
をつけて実施します。このCHANNELは各マスターとの通信するchannel名で、各マスターそれぞれに違う名前をつけて実施します。
各masterにchennel名をmydatabase1~3と名付けてCHANGE MASTER TO構文を実施する
mysql> CHANGE MASTER TO master_host='127.0.0.1',
-> master_port= 3306,
-> master_user='repl',
-> master_password='repl',
-> master_log_file='mysql-bin.000022',
-> master_log_pos=195
-> FOR CHANNEL 'mydatabase1';
Query OK, 0 rows affected, 2 warnings (0.28 sec)
mysql> CHANGE MASTER TO master_host='127.0.0.1',
-> master_port= 3308,
-> master_user='repl',
-> master_password='repl',
-> master_log_file='mysql-bin.000003',
-> master_log_pos=195
-> FOR CHANNEL 'mydatabase2';
Query OK, 0 rows affected, 2 warnings (0.28 sec)
mysql> CHANGE MASTER TO master_host='127.0.0.1',
-> master_port= 3310,
-> master_user='repl',
-> master_password='repl',
-> master_log_file='mysql-bin.000010',
-> master_log_pos=195
-> FOR CHANNEL 'mydatabase3';
Query OK, 0 rows affected, 2 warnings (0.28 sec)
マルチソースレプリケーションの運用
今、CHANGE MASTER TO構文を利用して3つのMySQL(ポートが3306、3308、3310)をmydatabase1~3というチャネル名にしてマルチソースレプリケーション構成にしました。
では実際にmydatabase1にd1スキーマ、mydatabase2にd2スキーマを作ってスレーブ側でSHOW DATABASES構文を実施してみます。なお、下記プロンプト名はそれぞれのデータベースを指します。
slave> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.09 sec)
mydatabase1> CREATE DATABASE d1;
Query OK, 1 row affected (0.14 sec)
mydatabase2> CREATE DATABASE d2;
Query OK, 1 row affected (0.22 sec)
slave> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| d1 |
| d2 |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
6 rows in set (0.13 sec)
マルチソースレプリケーションを介してslave側にはd1,d2スキーマが作成されました。もちろんmydatabase1にはd2スキーマはありませんし、mydatabase2にはd1スキーマはありません。
各チャネルのレプリケーションステータスを確認するには、SHOW SLAVE STATUS FOR CHANNEL channel名
を実施します。
SLAVE> SHOW SLAVE STATUS FOR CHANNEL 'mydatabase1'\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 127.0.0.1
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000023
Read_Master_Log_Pos: 368
Relay_Log_File: mysql-relay-mydatabase1.000003
Relay_Log_Pos: 495
Relay_Master_Log_File: mysql-bin.000023
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
(中略)
Channel_Name: mydatabase1
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
1 row in set (0.00 sec)
channel名を指定せず、従来通りSHOW SLAVE STATUS
を実施すると、すべてのCAHNNELのレプリケーションステータスが表示されます。また、上記情報はperfomance_schemaにあるreplication_applier_*とreplication_connection_*で確認することができます。
各テーブルの項目に関してはMySQL公式ドキュメントのPerformance Schema Replication Tables をご確認ください。
IOスレッドをperfomance_schemaを使って確認する例
SLAVE> SHOW TABLES LIKE 'replication%';
+---------------------------------------------+
| Tables_in_performance_schema (replication%) |
+---------------------------------------------+
| replication_applier_configuration |
| replication_applier_filters |
| replication_applier_global_filters |
| replication_applier_status |
| replication_applier_status_by_coordinator |
| replication_applier_status_by_worker |
| replication_connection_configuration |
| replication_connection_status |
| replication_group_member_stats |
| replication_group_members |
+---------------------------------------------+
10 rows in set (0.00 sec)
SLAVE> SELECT rcc.CHANNEL_NAME, HOST, PORT, USER, LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE FROM replication_connection_configuration as rcc INNER JOIN replication_connection_status as rsc ON rcc.CHANNEL_NAME = rsc.CHANNEL_NAME;
+--------------+-----------+------+------+-------------------+--------------------+
| CHANNEL_NAME | HOST | PORT | USER | LAST_ERROR_NUMBER | LAST_ERROR_MESSAGE |
+--------------+-----------+------+------+-------------------+--------------------+
| mydatabase1 | 127.0.0.1 | 3306 | repl | 0 | |
| mydatabase2 | 127.0.0.1 | 3308 | repl | 0 | |
| mydatabase3 | 127.0.0.1 | 3310 | repl | 0 | |
+--------------+-----------+------+------+-------------------+--------------------+
3 rows in set (0.02 sec)
マルチソースレプリケーションを利用する際の注意点
マルチソースレプリケーションを利用する際には、各マスターで同じスキーマやテーブルを更新しないように運用する必要があります。
同じスキーマ、テーブルでもマルチソースレプリケーションを利用することは可能ですが、運用が複雑になってしまいます。各マスターで挿入するデータがプライマリーキー成約やユニーク成約を持っているデータをスレーブ側では重複エラーになってしまったり、同じスキーマのテーブルを更新するようなSQLを実行してしまった場合はマスターとスレーブ間でデータの差異が生じます。
たとえば、mydatabase1であるテーブルのデータをWHERE c1 >= 10
という条件で更新したあとに同じスキーマのテーブルをmydatabase2でWHERE c1 >= 20
というような条件で更新してしまうと、mydatabase1と統合データベース上ではc1 >= 20
のデータに差異が生まれてしまいます。
もし、テーブルの統合などで同じスキーマのテーブルを更新するマルチソースレプリケーションを実施する場合は、ROW_FORMATをRBRにしたり、各CHANNELで同じデータを更新しないような工夫をする必要があります。
とはいえ、ユーザー管理テーブル(mysql.user)などは各マスターでCREATE USER構文を同じユーザー名で実施すると、重複エラーになってしまいます。そういうときは、SQL_LOG_BIN = 0
にしてバイナリログに吐かないようにして各マスター、スレーブに実施するか、CREATE USER IF NOT EXISTS
を利用して重複エラーにならないようにしましょう。
まとめ
今回はマルチソースレプリケーションについて説明しました。データベースの再統合をする際などには非常に便利な機能ですが、注意点に記載した通り、同じデータを更新するような構成は運用が大変です。可能であれば、各マスターで違うスキーマを更新するような構成で組んで、安全に運用していく必要があります。