ストーリー
CAP定理とは
2000年にEric Brewerが提唱した定理で、分散データストアは以下の3つのうち、同時に2つしか保証できないというものです。
| 特性 | 説明 |
|---|---|
| Consistency(一貫性) | すべてのノードが同じデータを返す |
| Availability(可用性) | すべてのリクエストがレスポンスを返す |
| Partition Tolerance(分断耐性) | ネットワーク分断が起きても動作し続ける |
Consistency
/\
/ \
/ CP \
/______\
/\ /\
/ \ ?? / \
/ AP \ / CA \
/______\/______\
Availability Partition
Tolerance
現実的な選択
ネットワーク分断は避けられないため、実質的にはCPかAPの選択になります。
// CP(一貫性 + 分断耐性)の例
// ネットワーク分断時、レスポンスを返さない(可用性を犠牲)
interface CPSystem {
// 分断時はエラーを返すが、データの一貫性は保証
read(): Promise<Data | NetworkError>;
write(data: Data): Promise<void | NetworkError>;
}
// AP(可用性 + 分断耐性)の例
// ネットワーク分断時でもレスポンスを返す(一貫性を犠牲)
interface APSystem {
// 分断時も古いデータを返す(結果整合性)
read(): Promise<Data>; // 常にレスポンスを返す
write(data: Data): Promise<void>; // 常に受け付ける
}
代表的なシステムの分類
| 分類 | システム例 | ユースケース |
|---|---|---|
| CP | ZooKeeper, etcd, HBase | 設定管理、リーダー選出 |
| AP | Cassandra, DynamoDB, CouchDB | SNS、IoTデータ収集 |
| CA | 単一ノードRDBMS | (分断が起きない前提) |
Fallacies of Distributed Computing
1994年にSun Microsystemsのエンジニアたちがまとめた「分散コンピューティングの8つの誤解」です。
// 8つの誤解(Fallacies)
const fallacies = [
"1. ネットワークは信頼できる", // → タイムアウト、リトライが必要
"2. レイテンシはゼロである", // → リモート呼び出しはローカルの100〜1000倍遅い
"3. 帯域幅は無限である", // → ペイロードサイズを最適化すべき
"4. ネットワークは安全である", // → 常に認証・暗号化が必要
"5. トポロジは変化しない", // → サービスディスカバリが必要
"6. 管理者は1人である", // → 複数チームの責任分界が必要
"7. トランスポートコストはゼロ", // → シリアライズ/デシリアライズのコスト
"8. ネットワークは均質である", // → 異なるプロトコル、バージョンの混在
];
誤解がコードに与える影響
Fallacy 1: ネットワークは信頼できる
// BAD: ネットワーク障害を考慮していない
async function getUser(id: string): Promise<User> {
const response = await fetch(`http://user-service/users/${id}`);
return response.json();
}
// GOOD: リトライ、タイムアウト、サーキットブレーカーを考慮
async function getUser(id: string): Promise<User> {
return await retry(
async () => {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 3000);
try {
const response = await fetch(`http://user-service/users/${id}`, {
signal: controller.signal,
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
} finally {
clearTimeout(timeout);
}
},
{ maxAttempts: 3, backoff: "exponential" }
);
}
Fallacy 2: レイテンシはゼロである
// BAD: N+1問題をリモート呼び出しで再現
async function getOrderDetails(orderId: string) {
const order = await orderService.getOrder(orderId); // 1回のリモート呼び出し
const user = await userService.getUser(order.userId); // 2回目
const products = await Promise.all(
order.items.map(item => productService.getProduct(item.productId)) // N回!
);
return { order, user, products };
}
// GOOD: バッチ取得でリモート呼び出しを最小化
async function getOrderDetails(orderId: string) {
const order = await orderService.getOrder(orderId);
const [user, products] = await Promise.all([
userService.getUser(order.userId),
productService.getProductsBatch(order.items.map(i => i.productId)),
]);
return { order, user, products };
}
PACELC定理
CAP定理を拡張した理論で、分断がない通常時のトレードオフも考慮します。
P(分断時): A(可用性)か C(一貫性)を選ぶ
E(通常時): L(レイテンシ)か C(一貫性)を選ぶ
| 分類 | 分断時 | 通常時 | 例 |
|---|---|---|---|
| PA/EL | 可用性優先 | レイテンシ優先 | DynamoDB, Cassandra |
| PC/EC | 一貫性優先 | 一貫性優先 | MongoDB(デフォルト設定) |
| PA/EC | 可用性優先 | 一貫性優先 | 設定次第で多くのDBが該当 |
まとめ
| ポイント | 内容 |
|---|---|
| CAP定理 | C, A, P のうち同時に2つまで |
| 現実的な選択 | Pは避けられないのでCPかAP |
| 8つの誤解 | ネットワークの信頼性を過信しない |
| PACELC | 通常時のレイテンシ vs 一貫性も考慮 |
チェックリスト
- CAP定理の3つの特性を説明できる
- CPとAPの違いを具体例で説明できる
- 8つの誤解のうち主要なものを3つ以上挙げられる
- PACELC定理の概要を理解した
次のステップへ
理論を学んだところで、次はマイクロサービスの具体的なメリットとリスクを見ていきます。どんな場面で採用し、どんな場面で避けるべきかを判断する力をつけましょう。
推定読了時間: 25分