スクエニ ITエンジニア ブログ

マルチソースレプリケーションでDBインスタンスを統合する

皆さん、こんにちは!新卒3年目のオバカムと言います。
普段はクラウドを利用してソーシャルゲームのインフラを構築・管理しています。

さて、データベースの運用をしていると、データベースの統合をしたくなる時ってありませんか? データベースの統合といってもいくつか種類がありますが、今回はMySQLデータベースをホスティングしているサーバの統合について書きます。

負荷分散のため水平分割していたデータベースを一つのサーバに戻したい、あるいはサーバインスタンスの料金削減のために複数のデータベースを相乗りしたい、そういったときにMySQLのマルチソースレプリケーション機能を使うと簡単にデータベースサーバーの統合ができます!

環境

今回は以下の環境でデータベースサーバの統合をやりました。

  • MySQL 5.7
  • CentOS 7

構成としては少しレガシーですが、MySQL 8でもやることは大きくは変わらないです。

構成

今回は統合したいデータベースサーバ・統合先データベースサーバともに1:1のレプリケーションがなされている状態でのマルチソースレプリケーションです。

図にしてみるとこんな感じです。

レプリケーション構成
青い背景のレプリケーションが1:1のレプリケーション、赤い背景のレプリケーションがマルチソースレプリケーションです。

すでに本番環境で運用しているデータベースをメンテナンスなしで新しく構築したデータベースサーバへ統合しようとしている、そんな状況を想定しています。
そのため統合したいデータベースサーバから直接レプリケーションせずいったんバックアップ用のデータベースレプリカサーバを挟んでレプリケーションします。

やること

レプリケーション元サーバの設定確認

今回のマルチソースレプリケーションはすでにレプリケーションを行っているサーバから実施するため、以下設定がオンになっているかを確認しましょう。 MySQL 8.0.26を境に確認する変数が変わっているので要注意です。

# MySQL 5.7
log-slave-updates=ON

# ~>MySQL 8.0.26
log-replica-updates=ON

統合するデータベースのダンプファイルをとる

統合するデータベースのダンプファイルを取ります。

ダンプファイルを取得する際にはレプリケーションを一時停止しておくといいです。以下ではSQL実行スレッドだけを止めています。

/* MySQL 5.7 */
STOP SLAVE SQL_THREAD;

/* ~>MySQL 8.0.22 */
STOP REPLICA SQL_THREAD;

今回は統合するデータベース単位でダンプを取ることにします。

mysqldump -h 'Replica DB1' -u 'DB1 User' -p --single-transaction --triggers --routines --set-gtid-purged=ON --databases DB1 > dump_DB1.sql
mysqldump -h 'Replica DB2' -u 'DB2 User' -p --single-transaction --triggers --routines --set-gtid-purged=ON --databases DB2 > dump_DB2.sql

いくつかオプションを付けていますが、重要なのは--set-gtid-purged=ONです。 マルチソースレプリケーションはGTIDベースのレプリケーションに対応しています。

MySQL 5.7の場合はここでダンプファイルに書き出されたGTID_PURGEDの値をメモしておきます。メモした後にはダンプファイルからGTID_PURGEDの設定をする行を削除します。MySQL 5.7ではGTID_PURGEDのsetは上書きになるため、マルチソースレプリケーションがうまくいかなくなってしまうことを防ぐためにこのようなことをします。

# GTID_PURGEDの値を取得
# GTIDセットが複数ある場合があるので、行がセミコロンで終わっているか確認が必要
grep GTID_PURGED dump_DB1.sql
grep GTID_PURGED dump_DB2.sql

# GTID_PURGEDの設定行を削除
sed -i '/GTID_PURGED/d' dump_DB1.sql
sed -i '/GTID_PURGED/d' dump_DB2.sql

統合先データベースサーバにダンプファイルを取り込む

取得したダンプファイルを統合先データベースサーバへ流し込みます。

mysql -h 'Integrated DB' -u 'Integrated DB User' -p < dump_DB1.sql
mysql -h 'Integrated DB' -u 'Integraded DB User' -p < dump_DB2.sql

MySQL 5.7の場合は先ほどメモしたGTID_PURGEDを設定することを忘れないように。

RESET MASTER;
SET @@GTID_PURGED = "(メモしたGTIDをカンマ(,)区切りで記述)";

マルチソースレプリケーション

いよいよマルチソースレプリケーションを行っていきます! ここはMySQLのバージョンによってSQL文が大きく異なるのでバージョンごとに分けて記載していきます。

MySQL 5.7

CHANGE MASTER TO MASTER_HOST = "Replica DB1", MASTER_USER = "DB1 User", MASTER_PASSWORD = "DB1 Password", MASTER_AUTO_POSITION = 1 FOR CHANNEL "DB1";
CHANGE MASTER TO MASTER_HOST = "Replica DB2", MASTER_USER = "DB2 User", MASTER_PASSWORD = "DB2 Password", MASTER_AUTO_POSITION = 1 FOR CHANNEL "DB2";

マルチソースレプリケーションで重要になるのはチャネルという概念です。 これにより複数のサーバからくるクエリを混線せずに処理することが可能になります。

START SLAVE;

レプリケーションの設定が出来たらレプリケーションを起動してみましょう。うまく行っていればデータが入ってくると思います。

MySQL 8.0

Mysql 8.0.23以降では上記で紹介したSQLが非推奨になります。推奨のSQLは以下です。

CHANGE REPLICATION SOURCE TO SOURCE_HOST = "Replica DB1", SOURCE_USER = "DB1 User", SOURCE_PASSWORD = "DB1 Password", SOURCE_AUTO_POSITION = 1 FOR CHANNEL "DB1";
CHANGE REPLICATION SOURCE TO SOURCE_HOST = "Replica DB2", SOURCE_USER = "DB2 User", SOURCE_PASSWORD = "DB2 Password", SOURCE_AUTO_POSITION = 1 FOR CHANNEL "DB2";
START REPLICA;

マルチソースレプリケーションができたら

無事マルチソースレプリケーションが動作したらダンプをとるために停止していたレプリカサーバのレプリケーションを再度動かしてみます。

/* MySQL 5.7 */
START SLAVE;

/* ~>MySQL 8.0.22 */
START REPLICA;

全部のデータベースが同期された状態になっていればデータベース統合も完了です!

統合前のデータベースサーバはアプリケーション側で接続先を統合後データベースサーバに切り替えた後で停止しましょう。
オンプレミスの場合はデータベースをDROPして別のデータベースサーバとして運用、ということもあるかもしれないですね。

まとめ

これで、MySQLのマルチソースレプリケーションを使ったデータベースサーバの統合ができたと思います!

マルチソースなんて一見大変そう……に思えますが、やってみるとそんなに難しくないと思います。 MySQL 8ならGTID_PURGEDの修正も必要なくなるので、手軽にできるかと思います!

以上、オバカムでした!

この記事を書いた人

記事一覧
SQUARE ENIXでは一緒に働く仲間を募集しています!
興味をお持ちいただけたら、ぜひ採用情報ページもご覧下さい!