MySQLレプリケーション設計——障害復旧・読み取り分散・RDS Multi-AZとの比較

MySQLのレプリケーションの仕組み(バイナリログ・マスタ/スレーブ構成)から、読み取り分散・フェイルオーバー設計、AWSのRDS Multi-AZやAurora Read Replicaとの対応関係まで整理する。

DBサーバが止まるとサービス全体が止まる。アプリサーバは冗長化できても、DBがシングルポイントになっているケースは多い。

MySQLレプリケーションはDBの可用性を高めるための基本技術で、AWSのRDS Multi-AZやAurora Read Replicaもこの仕組みの上に成り立っている。


レプリケーションの仕組み

MySQLのレプリケーションはバイナリログを使った非同期コピーだ。

マスタ                      スレーブ
┌──────────────┐            ┌──────────────┐
│  書き込み処理  │            │  読み取り処理  │
│              │            │              │
│  バイナリログ  │──────────→ │  リレーログ   │
│  (binlog)    │  I/Oスレッド │  (relaylog)  │
└──────────────┘            │              │
                            │  SQLスレッド  │
                            │  (再生)       │
                            └──────────────┘
  1. マスタでデータ変更が発生するとバイナリログに記録される
  2. スレーブのI/Oスレッドがバイナリログを受け取りリレーログに書き込む
  3. スレーブのSQLスレッドがリレーログを再生してデータを更新する

非同期のため、スレーブはマスタより少し遅れる(レプリケーション遅延)


シングルマスタ・マルチスレーブ構成

標準的な構成は1台のマスタと複数のスレーブだ。

           [アプリサーバ]
          /              \
  書き込み               読み取り
      ↓                   ↓
  [マスタDB]  ──→  [スレーブDB × N]

マスタ: 書き込み専用(INSERT・UPDATE・DELETE) スレーブ: 読み取り専用(SELECT)。複数台で読み取り負荷を分散する。


設定の基本(MySQL 8.0)

-- マスタ側の設定(my.cnf)
[mysqld]
server-id = 1
log-bin = mysql-bin
binlog-format = ROW  # 推奨: ROW形式(行ベースのレプリケーション)

-- レプリケーション用ユーザを作成
CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
-- スレーブ側の設定(my.cnf)
[mysqld]
server-id = 2
relay-log = relay-bin
read-only = 1  # スレーブへの誤った書き込みを防ぐ

-- レプリケーション開始(MySQL 8.0+)
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST='master-host',
  SOURCE_USER='repl',
  SOURCE_PASSWORD='password',
  SOURCE_AUTO_POSITION=1;  # GTIDを使った自動ポジション管理

START REPLICA;
-- レプリケーション状態確認
SHOW REPLICA STATUS\G
-- Replica_IO_Running: Yes  ← I/Oスレッドが動いているか
-- Replica_SQL_Running: Yes ← SQLスレッドが動いているか
-- Seconds_Behind_Source: 0 ← 遅延秒数(0が理想)

レプリケーション遅延への対策

非同期レプリケーションの弱点は遅延だ。書き込み直後にスレーブから読み取ると古いデータが返ることがある。

// アプリ側での対処パターン

// パターン1: 書き込み後の読み取りはマスタから
async function updateAndRead(userId: number, data: UpdateInput) {
  await masterDb.update(userId, data);
  // スレーブから読まずにマスタから読む
  return masterDb.findOne(userId);
}

// パターン2: セッションに「最近書き込んだ」フラグを立てる
// 書き込み後N秒間はマスタ参照にする

半同期レプリケーション(MySQL 5.5+): 少なくとも1台のスレーブがバイナリログを受け取るまでコミットを待つ。データ損失を防ぐが書き込みのレイテンシが上がる。


フェイルオーバー設計

マスタが故障したとき、スレーブをマスタに昇格させる手順だ。

# 1. 故障したマスタへの接続を切断
# 2. スレーブの遅延を確認(全スレーブが追いついているか)
SHOW REPLICA STATUS\G  -- Seconds_Behind_Source 0 になるまで待つ

# 3. スレーブをマスタに昇格
STOP REPLICA;
RESET REPLICA ALL;

# 4. アプリの接続先を新マスタに切り替え
# VIP(仮想IP)を使っていれば切り替えを透過的にできる

手動フェイルオーバーは時間がかかるため、MySQL RouterMHA for MySQLなどの自動フェイルオーバーツールを使うのが実務では一般的だ。


AWSでのマネージド対応

オンプレでMySQLレプリケーションを手動で管理する代わりに、AWSのマネージドサービスを使うことで運用コストを大幅に削減できる。

RDS Multi-AZ

プライマリ(書き込み・読み取り)
      ↕ 同期レプリケーション
スタンバイ(フェイルオーバー用)
  • 同期レプリケーション: データ損失ゼロ
  • 自動フェイルオーバー: 障害検知から60〜120秒でエンドポイントが切り替わる
  • スタンバイは通常は読み取りに使えない(フェイルオーバー専用)

Aurora Read Replica

Auroraクラスター(共有ストレージ)
├── Writer(書き込み専用エンドポイント)
├── Reader 1(読み取り)
└── Reader 2(読み取り)
  • 共有ストレージ: レプリカラグがほぼゼロ(ストレージレイヤーで同期)
  • 最大15台のRead Replicaを追加可能
  • フェイルオーバー時間: 約30秒(RDS Multi-AZより高速)
  • 読み取り用エンドポイントで複数リーダーへ自動分散

比較

構成遅延フェイルオーバー読み取り分散コスト
MySQL レプリケーション(手動)非同期手動安い(要運用コスト)
RDS Multi-AZ同期自動(〜120秒)
Aurora + Read Replicaほぼゼロ自動(〜30秒)高い

まとめ

MySQLレプリケーションの設計原則:

  1. マスタ1台・スレーブN台が基本構成
  2. 読み取り専用クエリはスレーブへ分散する
  3. 書き込み後即時読み取りはマスタから(レプリケーション遅延対策)
  4. フェイルオーバー手順を事前に決めておく
  5. AWSならRDS Multi-AZかAurora + Read Replicaで運用負荷を下げる

レプリケーションの設計思想はサーバ/インフラを支える技術の2章で詳しく解説されている。