レプリケーションとは
レプリケーション(Replication)は、データベースのデータを複数のサーバーにコピーして同期する仕組みです。可用性の向上、読み取り性能の向上、災害対策などの目的で使用されます。
なぜ必要か: 単一のデータベースサーバーは単一障害点(SPOF)となります。レプリケーションにより、障害時もサービスを継続でき、読み取りクエリを分散できます。
レプリケーションの基本構成
マスター・スレーブ(プライマリ・レプリカ)
flowchart TB
M["Master (Primary)<br/>← 書き込み"]
M -->|レプリケーション| S1["Slave 1 (Replica)<br/>← 読み取り"]
M -->|レプリケーション| S2["Slave 2 (Replica)<br/>← 読み取り"]
M -->|レプリケーション| S3["Slave 3 (Replica)<br/>← 読み取り"]
- Master(Primary): 書き込みを受け付ける主サーバー
- Slave(Replica): マスターのデータをコピーし、読み取りを担当
マルチマスター
flowchart LR
M1["Master 1"] <-->|レプリケーション| M2["Master 2"]
M1 --> RW1["読み書き"]
M2 --> RW2["読み書き"]
複数のマスターが書き込みを受け付けます。コンフリクト解決が課題となります。
同期 vs 非同期レプリケーション
同期レプリケーション
sequenceDiagram
participant C as クライアント
participant M as Master
participant S as Slave
C->>M: 書き込み
M->>S: レプリケーション
S->>M: ACK
M->>C: 応答
| メリット | デメリット |
|---|---|
| データ損失なし | レイテンシが増加 |
| 強い整合性 | スレーブ障害で書き込み停止 |
非同期レプリケーション
sequenceDiagram
participant C as クライアント
participant M as Master
participant S as Slave
C->>M: 書き込み
M->>C: 応答
M-->>S: レプリケーション(後から適用)
| メリット | デメリット |
|---|---|
| 低レイテンシ | レプリケーションラグ |
| スレーブ障害の影響なし | データ損失の可能性 |
半同期レプリケーション
少なくとも1つのスレーブがデータを受信したらコミットを確定します。
sequenceDiagram
participant C as クライアント
participant M as Master
participant S1 as Slave 1
participant S2 as Slave 2
C->>M: 書き込み
M->>S1: レプリケーション
S1->>M: ACK
M->>C: 応答
M-->>S2: レプリケーション(後から適用)
レプリケーションの方式
ステートメントベース
SQLステートメント自体をレプリケートします。
-- マスターで実行
INSERT INTO users (name, created_at) VALUES ('Alice', NOW());
-- スレーブでも同じSQLを実行
-- 問題: NOW()の結果が異なる可能性
行ベース
変更された行のデータ自体をレプリケートします。
flowchart LR
Before["{id: 1, name: 'Alice'}"] --> Change["変更"] --> After["{id: 1, name: 'Bob'}"]
After --> Apply["この差分をスレーブに適用"]
混合モード
通常はステートメントベース、非決定的な関数を含む場合は行ベースを使用します。
レプリケーションラグ
スレーブがマスターに追いつくまでの遅延です。
flowchart LR
subgraph Master["マスター"]
MT["トランザクション 1, 2, 3, 4, 5 ✓"]
end
subgraph Slave["スレーブ(ラグ: 2トランザクション分)"]
ST["トランザクション 1, 2, 3 ✓"]
end
Master -.-> Slave
ラグが問題になるケース
// 書き込み後すぐに読み取り
await db.master.query('UPDATE users SET name = ? WHERE id = ?', ['Bob', 1]);
// スレーブから読み取り → 古いデータが返る可能性
const user = await db.slave.query('SELECT * FROM users WHERE id = ?', [1]);
// user.name が 'Alice' のまま!
対策
- Read Your Writes: 書き込み直後はマスターから読み取る
- Causal Consistency: 書き込みのタイムスタンプを追跡
- 同期レプリケーション: 重要なデータのみ
フェイルオーバー
マスターに障害が発生した場合、スレーブをマスターに昇格させます。
自動フェイルオーバー
flowchart TB
A["1. マスター障害検知<br/>監視システムがマスターの応答なしを検知"]
B["2. スレーブ選出<br/>最もレプリケーションが進んでいるスレーブを選択"]
C["3. 昇格処理<br/>選出されたスレーブをマスターに昇格"]
D["4. 切り替え<br/>アプリケーションの接続先を新マスターに変更"]
A --> B --> C --> D
フェイルオーバー時の注意点
| 課題 | 対策 |
|---|---|
| スプリットブレイン | フェンシング(旧マスターを強制停止) |
| データ損失 | 非同期レプリの未適用トランザクション |
| 接続切り替え | 仮想IP、DNS更新、プロキシ |
代表的な実装
MySQL
-- マスター設定
CHANGE MASTER TO
MASTER_HOST='master.example.com',
MASTER_USER='repl_user',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=4;
START SLAVE;
PostgreSQL
# postgresql.conf (マスター)
wal_level = replica
max_wal_senders = 3
# recovery.conf (スレーブ)
standby_mode = 'on'
primary_conninfo = 'host=master.example.com port=5432'
マネージドサービス
| サービス | レプリカ機能 |
|---|---|
| Amazon RDS | リードレプリカ、Multi-AZ |
| Cloud SQL | リードレプリカ、高可用性構成 |
| Azure SQL | geo-replication |
読み取りスケーリングのパターン
flowchart LR
App["アプリ"]
App --> M["Master<br/>(書き込み)"]
App --> LB["Load Balancer"]
LB --> R1["Replica 1"]
LB --> R2["Replica 2"]
LB --> R3["Replica 3"]
subgraph Read["読み取り"]
R1
R2
R3
end
ロードバランサーで読み取りクエリをレプリカに分散します。
まとめ
データベースレプリケーションは、高可用性と読み取りスケーラビリティを実現するための基盤技術です。同期/非同期の選択、レプリケーションラグへの対処、フェイルオーバー戦略を適切に設計することで、堅牢なデータベースシステムを構築できます。
← 一覧に戻る