高可用性(HA)アーキテクチャにおける位置づけ
エンタープライズ環境における信頼性保証は、通常年間稼働率(計画外停止時間を除く)で評価されます。各SLAレベルに対応する許容停電時間は以下の通り算出されます。
- 99.9%:約 525.6 分/年(月換算で約5分弱の停止を許容)
- 99.99%:約 52.56 分/年
- 99.999%:約 5.256 分/年
これを達成するための階層的アプローチは一般的に以下のように分類されます。
- L4/L7レイバランシング:LVSやNginxによる負荷分散層。単体ではフェイルオーバー機能に限界があるため、HAの一部として組み込まれます。
- アクティブ・スタンバイ型:Keeper系ツール(Keepalived)、MHA、MMMなど。単一マスタが稼働し、障害発生時にフェイルオーバーを行う典型的な冗長構成です。
- マルチアクティブ/クラスタ型:NDB Cluster、Oracle RAC、MariaDB Galera Cluster(PXC)、InnoDB Cluster(MGR)など。複数のノードが同時に書き込み可能であり、真のHAを実現します。
レプリケーションの動作原理と構成要件
MySQLにおけるレプリケーションは、非同期コピーを基本とし、バイナリログに基づくイベント伝搬によって実現されます。主な前提条件は以下の通りです。
- インスタンス数:少なくとも2つのデータベースサーバーが必要。
- バイナリログ有効化:ソース側(マスター)で
log_binを有効化する必要がある。 - サーバーIDの一意性:
server_idはクラスター内でもグローバルでも重複してはならない。 - 専用複製アカウント:
REPLICATION SLAVE権限を持つユーザの作成。 - 初期データ整合性:スレーブはマスターの完全バックアップリストアから開始し、ギャップを埋める。
- 接続情報の設定:マスターのIP、ポート、認証情報、複製開始位置を明示的に定義。
- スレッド起動:スレーブ側で
start slaveを実行し、専用スレッドを起動させる。
環境構築の手順実装
複数インスタンスの準備から複製チェーンの確立まで、ロジックを整理した実装フローを示します。
1. インスタンスの初期化と起動制御
# 既存プロセスのクリーンアップと新しいインスタンス用ディレクトリの確保
pkill mysqld
mkdir -p /data/mysqldb/beta/data
rm -rf /data/mysqldb/beta/*
# ベースディレクトリ指定での初期化
mysqld --initialize-insecure \
--user=mysql \
--basedir=/app/mysql \
--datadir=/data/mysqldb/beta/data
# サービス起動とポート確認
systemctl start mysqld_beta
mysql -S /data/mysqldb/beta/mysql.sock -e "SELECT @@port;"
mysql -S /data/mysqldb/alpha/mysql.sock -e "SELECT @@port;"
2. 設定ファイルの検証
両ノードで server_id と log_bin パラメータが矛盾なく定義されているか確認します。
# αノード(マスター)設定例
[mysqld]
datadir=/data/mysqldb/alpha/data
socket=/data/mysqldb/alpha/mysql.sock
port=5001
server_id=101
log_bin=/data/mysqldb/alpha/bin-log
# βノード(スレーブ)設定例
[mysqld]
datadir=/data/mysqldb/beta/data
socket=/data/mysqldb/beta/mysql.sock
port=5002
server_id=102
log_bin=/data/mysqldb/beta/bin-log
3. 複製用アカウントの作成とデータの移行
-- αノード(マスター)で複製権限を持つアカウントを作成
mysql -S /data/mysqldb/alpha/mysql.sock -e "
CREATE USER 'db_sync'@'10.10.%' IDENTIFIED BY 'Str0ngPass!';
GRANT REPLICATION SLAVE ON *.* TO 'db_sync'@'10.10.%';
FLUSH PRIVILEGES;"
-- スナップショット取得(トランザクション整合性を保つためフラッシュテーブル併用)
mysqldump -S /data/mysqldb/alpha/mysql.sock \
--all-databases \
--master-data=2 \
--single-transaction \
--triggers \
--routines \
--events \
-R > /tmp/full_snapshot.sql
-- βノード(スレーブ)へリストア
mysql -S /data/mysqldb/beta/mysql.sock -e "SET sql_log_bin = 0;"
mysql -S /data/mysqldb/beta/mysql.sock < /tmp/full_snapshot.sql
4. 複製ポジションの設定とスレッド起動
-- ダンプ実行時に出力された binlog ファイル名とポジションを確認後、βノードで設定
mysql -S /data/mysqldb/beta/mysql.sock <<EOF
CHANGE MASTER TO
MASTER_HOST = '10.10.0.55',
MASTER_USER = 'db_sync',
MASTER_PASSWORD = 'Str0ngPass!',
MASTER_PORT = 5001,
MASTER_LOG_FILE = 'bin-log.000003',
MASTER_LOG_POS = 1548,
MASTER_CONNECT_RETRY = 15;
START SLAVE;
EOF
</code>
正常に構築されると、αノードでのDDL/DML変更が自動的にβノードに反映されます。検証用のスキーマ作成とチェックは通常のクライアント接続で行います。
内部処理フローの解析
複製機構は主に3つのスレッドと2つの設定ファイルが協調して動作しています。
- 初期化フェーズ:
CHANGE MASTER TO実行時に、接続パラメータと複製開始ポイントがmaster.infoに記録されます。 - スレッド起動:
START SLAVEで IO スレッドと SQL スレッドが生成されます。 - データフェッチ(IOスレッド):
master.infoを読み取り、マスターのダンプスレッドへ接続要求を行います。指定されたバイナリログ位置以降の変更イベントを受信すると、TCPバッファを経てディスク上のリレーログ(relay-bin.*)へ永続化します。完了後はACKを返し、master.infoを更新します。 - イベント適用(SQLスレッド):
relay.infoから最後に適用したリレーログのオフセットを取得します。最新のrelay-binをシリアルに解釈・実行し、データベースの状態を同期させます。適用が完了次第relay.infoを更新し、不要なリレーログは自動削除されます。
これにより、マスター側でのトランザクション.commitと同時に通知が発火し、リアルタイムに近い同期が維持されます。
ステータス監視と検証項目
運用中の健全性はスレーブインスタンスで以下を実行して確認します。主要パラメータの意味は以下の通りです。
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Master_Host: 10.10.0.55
Master_User: db_sync
Master_Port: 5001
Master_Log_File: bin-log.000003
Read_Master_Log_Pos: 2845
Relay_Log_File: beta-relay-bin.000002
Relay_Log_Pos: 1250
Exec_Master_Log_Pos: 2845
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Last_Errno: 0
Last_Error:
Seconds_Behind_Master: 0
Gtid_Mode: ON
Retrieved_Gtid_Set: abc-123:1-50
Executed_Gtid_Set: abc-123:1-50
Auto_Position: 1
Slave_IO_Running/Slave_SQL_Running:両方ともYesであることが必須。Read_Master_Log_PosvsExec_Master_Log_Pos:差分が大きいほど遅延 occurring を示唆。Seconds_Behind_Master:秒単位で表示されるキャッチアップ遅延時間。NULLは接続切断状態。Gtid_Set関連:GTID環境下では論理トランザクションIDで追跡できるため、物理ログファイル名の依存が解消されます。
代表的なエラー事象と復旧フロー
IOスレッド障害
ネットワーク遮断、認証情報の変更、またはマスター側の RESET MASTER 実行によりバイナリログがクリアされることが主要原因です。
対策としては、まず接続テストを実施し、問題が解決しない場合は複製チェーンを再初期化します。
STOP SLAVE;
RESET SLAVE ALL;
CHANGE MASTER TO
MASTER_HOST='10.10.0.55',
MASTER_USER='db_sync',
MASTER_PASSWORD='Str0ngPass!',
MASTER_PORT=5001,
MASTER_LOG_FILE='bin-log.000001',
MASTER_LOG_POS=154;
START SLAVE;
RESET MASTER の直後には、マスター側で SHOW MASTER STATUS; を発行し、新たに割り当てられたログファイルとポジションを必ず確認してください。
SQLスレッド障害
スレーブ上での誤った更新操作や、インデックス不整合に伴うキー違反が発生すると止まります。根本的な修復方針は以下の2点です。
- 即時対応:発生したエラーを無視する(
SQL_SLAVE_SKIP_COUNTER)か、手動で反転クエリを実行して整合性を戻す。ただし、データ欠損リスクが高いため慎重に検討が必要です。 - 再構築:最も安全なのはマスターから再リストアし、複製関係を張り直すことです。
再発防止のため、スレーブ側への直接書き込みを禁止する read_only および super_read_only 属性を設定し、ProxySQL や MaxScale などの読み書き分離プロキシを間に挟む設計が業界標準となっています。
同期遅延の要因特定と最適化策
アプリケーション側からは正常に見えるが、スレーブのデータが数分~数時間遅れる現象は、以下の要素が複合的に起因しています。
- マスター側のボトルネック:
sync_binlog=1によるディスク同期頻度の高まり、または大量の並列トランザクションに対する単一ダンプスレッドの渋滞。 - スレーブ側の処理能力:従来の古典的レプリケーションは SQL スレッドが単一スレッドであるため、マスターが並列実行するトランザクションに対してキャッチアップが遅くなります。
- インフラ差異:CPUアーキテクチャの違い、SSD/HDDの混在、OSパラメータ(カーネルメモリ管理やネットワークスタック)の不一致。
- スキーマ不整合:スレーブにインデックスが存在せず、マスターからの高速なインデックス付きINSERTが、スレーブではフルテーブルスキャンになり実行時間が数十倍になるケース。
現代における最適化アプローチ:
- GTID + Group Commit:トランザクションの順序管理を論理IDで行い、グループコミット機能によりDumpスレッドのバッチ処理効率を向上させます。
- MTS(Multi-Threaded Slave):MySQL 5.7 以降の
log_clockモードを活用し、スレーブ側で論理的に関連性の低いトランザクションを並列実行可能です。これにより大きなキャッチアップ遅延を劇的に緩和できます。
遅延の詳細な把握には、マスター側で SHOW MASTER STATUS; を実行して現在の Position を取得し、スレーブ側で Exec_Master_Log_Pos と比較計算を行います。この差分サイズが大きくなる傾向が見られた場合、上記のパラメータ調整やインデックス追加を実施することでパフォーマンスの均衡を図ります。