自分的メモも兼ねて
構成
マイクロサービスの様な、複数のマスターRDSを持つ様な構成で分析用などにslaveを持ちたい場合に、それぞれのRDSについてリードレプリカを作成すると、マスターの個数分だけリードレプリカを作成する必要があり経済的な問題が生じる。
また、分析的な業務ではデータベースを跨いでJOINしたかったりするかもしれないため、一つのMySQLに複数のdatabaseのレプリケーションを受けたい。
マルチソースレプリケーション
MySQL5.7から導入された、database毎にレプリケーションの設定が出来る機能。
https://dev.mysql.com/doc/refman/5.7/en/replication-multi-source.html
作業
Read Replicaを作成する
RDSにはFLUSH TABLES WITH READ LOCK
権限が無いため、マスターから以下のようなコマンドでdumpを取得する事が出来ない。
(--master-dataは、CHANGE MASTER分をdumpの最後に付けるオプションだが、これをする為にはFLUSH TABLEしてポジションを取得しないといけない。)
$ mysqldump -h example.ap-northeast-1.rds.amazonaws.com -u user -p --single-transaction --master-data --databases sample > sample.sql
Enter password:
mysqldump: Couldn't execute 'FLUSH TABLES WITH READ LOCK': Access denied for user 'user'@'%' (using password: YES) (1045)
このため、まずはRead Replicaを作成し、そこからデータをダンプした後、マスターに繫ぐという事をする。
Read Replicaのレプリケーションを止めてポジションを記録する
Read Replicaが作成出来たら、以下のコマンドでレプリケーションを停止させる。これは、RDSでデフォルトで用意されているプロシージャ。
call mysql.rds_stop_replication;
レプリケーションが止まったら、SHOW SLAVE STATUS
でいまのポジションを記録しておく。必要なのはこの二つ。マスターのどのbinlogを読んでいるか、そのbinlogのどこまで読んだか。
Master_Log_File: mysql-bin-changelog.090689
Read_Master_Log_Pos: 23395
Read Replicaからdumpを取得し、MySQLに流し込む
レプリを止めたらその状態のデータをmysqldumpで取得して、今回新しくスレーブにしたいMySQLに流し込む。
dumpを取得し、
mysqldump -hexample-readreplica.ap-northeast-1.rds.amazonaws.com -u user -p --single-transaction --databases sample > sample.sql
流し込み。
cat sample.sql | mysql -uroot -p
MySQL側でCHANGE MASTERし、レプリを開始する
流し込みが終わったら、対象のMySQLサーバーにログインしてCHANGE MASTERを打つ。このとき、先ほど記録していたbinlogの値を使用する。
今回はマルチソースでレプリケーションしたいので、FOR CHANNELで固有のチャンネル名を指定する。
mysql> CHANGE MASTER TO
MASTER_HOST='xxx.xxx.xxx.xxx',
MASTER_USER='repl',
MASTER_PASSWORD='XXXXXXXXXXX',
MASTER_LOG_FILE='mysql-bin-changelog.090689',
MASTER_LOG_POS=23395 FOR CHANNEL 'sample';
エラーが出なければ、レプリを再開。この時にもCHANNEL指定。
mysql> START SLAVE FOR CHANNEL 'sample';
確認。
mysql> SHOW SLAVE STATUS FOR CHANNEL 'sample';
ここまで問題なければ一つのRDSに関しては終了。
引き続き他のRDSに関しても同じ作業を繰り返せばOK(ただし、CHANNEL名は全て固有の値にする事)。
(補足) binlogの保持期間について
RDSのbinlogはデフォルトでは必要なくなったら消されてしまうため、ダンプやリストアしている間に消えてしまう事がある。
以下の様に保持期間を伸ばしておくと良い。ちなみに、これもRDSが用意しているプロシージャ。
mysql> call mysql.rds_set_configuration('binlog retention hours', 24);
現在の設定値の確認方法。
mysql> call mysql.rds_show_configuration;
まとめ
マルチソースレプリケーションが便利すぎた。