はじめに:5分で始めるマルチソースレプリケーション
例えば、2つのマスター(ソースAとソースB)を管理しており、レポート作成のためにすべてのデータを1つのスレーブ(レプリカ)に集約する必要があるとします。コードを書いて苦労する代わりに、FOR CHANNEL句を活用しましょう。これが、MySQLが異なるデータストリームを識別するための「鍵」となります。
マスター側でレプリケーション用ユーザーを作成した後、レプリカ側で以下の便利なコマンドを実行して設定を行うだけです:
-- ソースA(例:注文DB)からのチャネル設定
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.1.10',
SOURCE_USER='repl_user',
SOURCE_PASSWORD='超強力パスワード',
SOURCE_LOG_FILE='mysql-bin.000001',
SOURCE_LOG_POS=156
FOR CHANNEL 'source_A';
-- ソースB(例:ユーザーDB)からのチャネル設定
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.1.20',
SOURCE_USER='repl_user',
SOURCE_PASSWORD='超強力パスワード',
SOURCE_LOG_FILE='mysql-bin.000005',
SOURCE_LOG_POS=450
FOR CHANNEL 'source_B';
-- 両方のストリームを並行して有効化
START REPLICA FOR CHANNEL 'source_A';
START REPLICA FOR CHANNEL 'source_B';
すべてがスムーズに動作しているか確認するには、SHOW REPLICA STATUS\Gを実行します。両方のチャネルでRunning: Yesと表示されれば、基本設定は完了です!
実体験:5つのマイクロサービスを統合した話
以前、あるEC系スタートアップで働いていたとき、システムには5つの個別のデータベースを持つ5つのマイクロサービスがありました。ある日突然、上司から「明日の朝8時までにリアルタイムの売上ダッシュボードを作ってくれ」と頼まれました。その時、5つのリモートDBを結合(Join)するコードを書くことを考えただけで、その遅延と複雑さに冷や汗が出ました。
その時の救世主がMySQL Multi-Source Replicationでした。重厚なETLツールを使う代わりに、5つのデータソース(合計約200GB)を16GB RAMのセントラルレプリカに直接同期させました。結果は驚くべきものでした:
- 超高速レポート: マスターでの顧客の注文速度に影響を与えることなく、レプリカ上で自由なクエリ実行が可能。
- バックアップが楽に: 5つのバックアップジョブを走らせる代わりに、すべてを集約して1回で済みます。
- マルチリージョン分析: シンガポールやアメリカのサーバーからベトナムへ、わずか100〜200msの遅延でデータを集約できました。
詳細設定:小さなミスが大きなトラブルを招かないために
本番環境でシステムを安定稼働させたいなら、GTID (Global Transaction Identifiers)の使用を強くお勧めします。マスターに障害が発生するたびに夜通しエラー修正をしたくないのであれば、従来のbinlog_file方式は避けましょう。
1. my.cnf ファイルの最適化
設定ファイルを開き、以下のパラメータが含まれていることを確認してください:
[mysqld]
server-id = 101 # 各サーバーに一意の番号を割り当て(重複不可)
gtid_mode = ON
enforce_gtid_consistency = ON
log_bin = /var/log/mysql/mysql-bin.log
log_slave_updates = ON # このレプリカを他のノードのソースにする場合に必要
2. レプリケーションユーザーのセキュリティ
決してrootユーザーを使用しないでください。セキュリティリスクを最小限に抑えるため、必要最低限の権限を持つ専用ユーザーを作成します:
CREATE USER 'repl_user'@'%' IDENTIFIED WITH mysql_native_password BY '超強力パスワード';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%';
FLUSH PRIVILEGES;
3. フィルター活用のコツ
通常、サーバー全体をコピーする必要はなく、重要な特定のデータベースだけが必要な場合がほとんどです。例えば、ソースAからはdb_ordersのみ、ソースBからはdb_usersのみを取得するとします。データの重複や競合を避けるために、直接フィルターを設定しましょう:
CHANGE REPLICATION FILTER REPLICATE_DO_DB = (db_orders) FOR CHANNEL 'source_A';
CHANGE REPLICATION FILTER REPLICATE_DO_DB = (db_users) FOR CHANNEL 'source_B';
私が経験した落とし穴
設定自体はスムーズに見えますが、実際のデータが大量に(1日約1,000万レコードほど)流れ込み始めると、非常に厄介な問題に直面します。
主キーの競合 (Primary Key Conflict)
これは最も典型的なエラーです。ソースAとソースBの両方がID 1のユーザーを作成した場合、レプリカに同期される際にDuplicate entryエラーが発生し、レプリケーションが即座に停止します。
私がとった解決策:
- 主キーをAuto IncrementではなくUUIDに変更する。
- Auto Incrementを使い続ける場合は、
auto_increment_offsetを異なる値に設定する(例:ソースAは奇数、ソースBは偶数)。 - あるいは最もシンプルな方法として、レプリカ上のソースごとに別々のスキーマ(データベース)にデータを流し込む。
スレーブ遅延(Slave Lag)への対処
複数のソースからデータを受け取ると、レプリカの負荷が高まり、ダッシュボードの情報が古くなってしまうことがあります。私はMySQL 8.0でマルチスレッドスレーブ(MTS)を有効にすることで最適化しました。16コアのサーバーで、8ワーカーを設定するのがベストでした:
set global slave_parallel_type = 'LOGICAL_CLOCK';
set global slave_parallel_workers = 8;
この設定により、遅延を30分から1秒未満に短縮できました。ダッシュボードの数値がリアルタイムに更新されるのを見るのは、最高に気持ちいいものです!
サーバー室からの結び
長年の運用の末、得られた教訓がいくつかあります。ディスク容量不足を避けるために常にrelay logsを監視すること、そして通常のmysqldumpではなくPercona XtraBackupを使用することです。中央集権的なデータウェアハウスの構築を考えているなら、MySQL Multi-Sourceは間違いなく最初に検討すべきツールです。設定で動かない部分があれば、コメント欄で気軽に質問してくださいね!

