- Authors
- Name

はじめに
「サーバーが1台落ちたらサービスも落ちる」— これが単一障害点(SPOF)です。
二重化・三重化は、このSPOFを排除する技術です。銀行、証券、航空管制システムは三重化まで行い、私たちが毎日使うクラウドサービスも二重化以上で運用されています。
可用性(Availability)の数字の意味
可用性 = 正常運用時間 / 全体時間 × 100%
| 可用性 | 等級 | 年間ダウンタイム | 月間ダウンタイム |
|---|---|---|---|
| 99% | Two 9s | 3.65日 | 7.3時間 |
| 99.9% | Three 9s | 8.77時間 | 43.8分 |
| 99.99% | Four 9s | 52.6分 | 4.38分 |
| 99.999% | Five 9s | 5.26分 | 26.3秒 |
| 99.9999% | Six 9s | 31.5秒 | 2.6秒 |
ポイント: 99.9%から99.99%に上げるのは、8時間から52分への短縮。しかしコストは10倍以上増加!
二重化(Redundancy)パターン
1. Active-Standby(アクティブ・スタンバイ)
正常状態:
[Activeサーバー] ←── すべてのトラフィック
[Standbyサーバー] (待機、同期のみ)
障害発生:
[Activeサーバー] ✗ 障害検知!
[Standbyサーバー] ←── トラフィック切り替え(Failover)
↑
新Activeに昇格
# KubernetesでのActive-Standby: StatefulSet + Leader Election
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-ha
spec:
replicas: 2 # 1 Active + 1 Standby
selector:
matchLabels:
app: redis
template:
spec:
containers:
- name: redis
image: redis:7
ports:
- containerPort: 6379
- name: sentinel # 障害検知 + 自動Failover
image: redis:7
command: ['redis-sentinel', '/etc/sentinel.conf']
メリット: リソース効率が良い(Standbyは最小リソース) デメリット: Failover時間(数秒〜数十秒のダウンタイム)
2. Active-Active(アクティブ・アクティブ)
正常状態:
[サーバーA] ←── トラフィック50%
[サーバーB] ←── トラフィック50%
↑
Load Balancerが分散
障害発生:
[サーバーA] ✗ 障害!
[サーバーB] ←── トラフィック100%(自動)
# Kubernetes Service = 自動Active-Active
apiVersion: v1
kind: Service
metadata:
name: my-api
spec:
selector:
app: my-api
ports:
- port: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-api
spec:
replicas: 2 # 両方Active!
template:
spec:
containers:
- name: api
image: my-api:latest
readinessProbe: # 障害検知
httpGet:
path: /health
port: 8080
periodSeconds: 5
failureThreshold: 3 # 3回失敗 → トラフィックから除外
メリット: ダウンタイムほぼ0(すでに分散中のため) デメリット: データ同期が複雑(競合解決が必要)
3. N+1 / N+2 二重化
N+1: N台必要なところに1台追加(最小限の余裕)
[サーバー1] [サーバー2] [サーバー3] [+予備1]
→ 1台落ちてもOK
N+2: N台必要なところに2台追加
[サーバー1] [サーバー2] [サーバー3] [+予備1] [+予備2]
→ 2台同時に落ちてもOK + 1台メンテナンス可能
2N: 全体を2倍に(最もコスト高)
[サーバー1] [サーバー2] [サーバー3] [サーバー4] [サーバー5] [サーバー6]
→ 半分が落ちてもOK(ミッションクリティカル)
三重化(Triple Redundancy)
なぜ三重化?
二重化の致命的弱点: スプリットブレイン(Split Brain)
二重化でネットワーク断絶時:
[サーバーA] ──✗── [サーバーB]
「Bが落ちた?自分がActive!」 「Aが落ちた?自分がActive!」
→ 両方Active → データ不整合 → 大惨事!
三重化 + クォーラムで解決:
三重化(3ノードクラスター):
[ノードA]──[ノードB]──[ノードC]
ネットワーク分割時:
[ノードA] [ノードB]──[ノードC]
1票(少数) 2票(過半数 = クォーラム!)
→ Aは自主退任
→ B、Cがサービスを継続
→ スプリットブレイン防止!
クォーラム公式: 過半数 = (N/2) + 1
3ノード: 2票必要(1ノード障害許容)
5ノード: 3票必要(2ノード障害許容)
7ノード: 4票必要(3ノード障害許容)
etcd(Kubernetesの頭脳)— 三重化必須!
# etcd 3ノードクラスター(Raft合意アルゴリズム)
# 1ノードダウン: クォーラム(2/3)維持 → サービス継続
# 2ノードダウン: クォーラム喪失 → 読み取りのみ可能
# kubeadmデフォルト設定
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
etcd:
local:
extraArgs:
initial-cluster: >-
etcd-0=https://10.0.0.1:2380,
etcd-1=https://10.0.0.2:2380,
etcd-2=https://10.0.0.3:2380
# Raft合意アルゴリズム(疑似コード)
class RaftNode:
def __init__(self, node_id, peers):
self.state = "follower" # follower → candidate → leader
self.term = 0
self.voted_for = None
self.log = []
def request_vote(self):
"""リーダー選出 — 過半数の投票が必要"""
self.state = "candidate"
self.term += 1
votes = 1 # 自分自身
for peer in self.peers:
if peer.grant_vote(self.term, self.log):
votes += 1
if votes > len(self.peers) // 2: # クォーラム!
self.state = "leader"
return True
return False
def replicate(self, entry):
"""データ複製 — 過半数確認後にコミット"""
self.log.append(entry)
acks = 1
for peer in self.peers:
if peer.append_entry(entry):
acks += 1
if acks > len(self.peers) // 2: # クォーラム!
self.commit(entry) # 過半数確認 → 安全にコミット
レイヤー別の二重化戦略
全体アーキテクチャ
[ユーザー]
│
▼
[DNS] ← Route 53ヘルスチェック(マルチリージョン)
│
▼
[CDN] ← CloudFront(グローバルエッジ)
│
▼
[L4 LB] ← NLB x2(Active-Active、AZ分散)
│
▼
[L7 LB] ← ALB x2(Active-Active)
│
▼
[Webサーバー] ← Deployment replicas: 3+(Active-Active)
│
▼
[アプリサーバー] ← Deployment replicas: 3+(Active-Active)
│
├──▶ [DB Primary] ──同期レプリケーション──▶ [DB Standby](Active-Standby)
│ └── 非同期レプリケーション ──▶ [DB Read Replica x2]
│
├──▶ [Redis Primary] ── [Redis Replica x2](Sentinel)
│
└──▶ [MQ] ← RabbitMQ 3ノード(クォーラムキュー)
データベースの二重化
[同期レプリケーション](Strong Consistency)
Primary ──COMMIT──▶ Standby
「両方に書き込むまで待つ」
メリット: データ損失ゼロ
デメリット: 遅い(ネットワークRTT追加)
[非同期レプリケーション](Eventual Consistency)
Primary ──COMMIT──▶(後で)Standby
「まずPrimaryだけに書いて応答」
メリット: 速い
デメリット: 障害時に最新データ損失の可能性(RPOが0より大きい)
[半同期レプリケーション](Semi-Sync)
Primary ──COMMIT──▶ Standby(1つだけ確認)
MySQLデフォルト + 金融機関で好まれる
-- PostgreSQL Streaming Replication設定
-- Primary (postgresql.conf)
-- wal_level = replica
-- max_wal_senders = 3
-- synchronous_standby_names = 'standby1'
-- Standby確認
SELECT client_addr, state, sync_state
FROM pg_stat_replication;
-- client_addr | state | sync_state
-- 10.0.0.2 | streaming | sync
-- 10.0.0.3 | streaming | async
障害復旧指標
RPO (Recovery Point Objective):
「どれだけのデータを失っても許容できるか?」
同期レプリケーション: RPO = 0(データ無損失)
非同期レプリケーション: RPO = 数秒〜数分
RTO (Recovery Time Objective):
「どれだけ早く復旧しなければならないか?」
Active-Active: RTO ≈ 0
Active-Standby: RTO = 数秒〜数分
バックアップ復元: RTO = 数時間
MTBF (Mean Time Between Failures):
障害間の平均時間(長いほど良い)
MTTR (Mean Time To Repair):
復旧までの平均時間(短いほど良い)
可用性 = MTBF / (MTBF + MTTR)
コスト対可用性
可用性 │ 構成 │ 相対コスト
───────────┼─────────────────────┼──────────
99% │ 単一サーバー │ 1x
99.9% │ 二重化(1リージョン)│ 2〜3x
99.99% │ 三重化 + 自動復旧 │ 5〜10x
99.999% │ マルチリージョンActive│ 10〜50x
99.9999% │ マルチリージョン + DR│ 50〜100x
クイズ — 二重化/三重化(クリックして確認!)
Q1. Active-StandbyとActive-Activeの最大の違いは? ||Active-Standby: 通常時は1台のみトラフィック処理、Failover時に切り替え遅延あり。Active-Active: 通常時からすべてのサーバーでトラフィック分散、1台が落ちても残りが即座に吸収(ほぼ無停止)||
Q2. スプリットブレイン(Split Brain)とは何か、どう防止するか? ||ネットワーク断絶により両側が自分がActiveだと判断する状態。データ不整合が発生する。三重化 + クォーラム(過半数投票)で防止 — 過半数を得られない側が自主退任||
Q3. etcdが3ノードである理由は?4ノードではない理由は? ||3ノード: 1ノード障害許容(クォーラム2/3)。4ノード: 同じく1ノードのみ障害許容(クォーラム3/4)で3ノードと同じだがコスト増加のみ。奇数が効率的||
Q4. RPOとRTOの違いは? ||RPO: 許容可能なデータ損失量(同期レプリケーション = 0、非同期 = 数秒)。RTO: 障害発生からサービス復旧までの許容時間。どちらも短いほど良いがコスト増加||
Q5. 99.99%と99.999%可用性の年間ダウンタイムの差は? ||99.99% = 52.6分/年、99.999% = 5.26分/年。約10倍の差があり、コストは5〜10倍以上増加||
Q6. N+1と2N二重化の違いは? ||N+1: 必要台数(N) + 予備1台 — コスト効率が良く、1台の障害を許容。2N: 全体を2倍 — コストが高いが半分が落ちてもサービス維持、ミッションクリティカルシステム用||
Q7. 同期レプリケーションと非同期レプリケーションはそれぞれどのような状況で使うか? ||同期: 金融取引、決済などデータ無損失必須(RPO=0)。非同期: 読み取り負荷分散、分析用レプリケーションなど多少の遅延を許容できる場合(パフォーマンス優先)||
Q8. Raft合意でのリーダー選出プロセスを説明せよ。 ||FollowerがリーダーのHeartbeatを受信できなくなるとCandidateに移行 → term増加 → 他のノードに投票を要求 → 過半数の得票でLeaderに昇格 → クライアントリクエストの処理を開始||