シャーディングとは
シャーディングは、データを複数のデータベース(シャード)に水平分割して格納する技術です。単一のデータベースでは処理できない大量のデータやトラフィックに対応できます。
レプリケーションとの違い: レプリケーションは同じデータのコピーを複数サーバーに持ちますが、シャーディングは異なるデータを異なるサーバーに分散します。
シャーディングの仕組み
flowchart TB
subgraph Before["シャーディング前"]
Single["単一データベース<br/>全ユーザーデータ<br/>(1億レコード)"]
end
flowchart LR
subgraph After["シャーディング後"]
S0["Shard 0<br/>ユーザー A-F<br/>2500万"]
S1["Shard 1<br/>ユーザー G-L<br/>2500万"]
S2["Shard 2<br/>ユーザー M-R<br/>2500万"]
S3["Shard 3<br/>ユーザー S-Z<br/>2500万"]
end
シャーディング方式
範囲ベースシャーディング
キーの範囲でシャードを決定します。
| user_id 範囲 | シャード |
|---|---|
| 1-1,000,000 | Shard 0 |
| 1,000,001-2,000,000 | Shard 1 |
| 2,000,001-3,000,000 | Shard 2 |
メリット: 範囲クエリが効率的 デメリット: データの偏りが発生しやすい
ハッシュベースシャーディング
キーのハッシュ値でシャードを決定します。
shard_id = hash(user_id) % num_shards
| user_id | 計算結果 | シャード |
|---|---|---|
| user_123 | hash(“user_123”) % 4 = 2 | Shard 2 |
| user_456 | hash(“user_456”) % 4 = 0 | Shard 0 |
メリット: データが均等に分散 デメリット: 範囲クエリが非効率
ディレクトリベースシャーディング
ルックアップテーブルでシャードを決定します。
| user_id | shard |
|---|---|
| user_123 | Shard 2 |
| user_456 | Shard 0 |
| user_789 | Shard 1 |
メリット: 柔軟なマッピング デメリット: ルックアップのオーバーヘッド
シャードキーの選び方
シャードキーは、シャーディングの成否を決める最も重要な要素です。
良いシャードキーの条件
- ✓ カーディナリティが高い(多様な値を持つ)
- ✓ アクセスパターンに合っている
- ✓ 書き込みが均等に分散する
- ✓ ほとんどのクエリにキーが含まれる
シャードキーの例
| ユースケース | 良いシャードキー | 悪いシャードキー |
|---|---|---|
| マルチテナントSaaS | tenant_id | created_at |
| ECサイト | user_id | product_category |
| SNS | user_id | post_date |
| ログ分析 | 時間 + 識別子の複合 | 時間のみ |
ホットスポットの問題
| パターン | シャードキー | 結果 |
|---|---|---|
| 悪い例 | created_at | 最新データのシャードに書き込みが集中 |
| 良い例 | user_id + created_at の複合キー | 書き込みが分散 |
クロスシャードクエリ
複数のシャードにまたがるクエリは複雑になります。
Scatter-Gather
flowchart TB
Client["クライアント"] --> Router["ルーター"]
Router -->|"Scatter<br/>(全シャードにクエリ)"| S0["S0"]
Router --> S1["S1"]
Router --> S2["S2"]
Router --> S3["S3"]
S0 -->|"Gather<br/>(結果を集約)"| Router
S1 --> Router
S2 --> Router
S3 --> Router
Router --> Client
JOIN の制限
-- 同一シャード内: 通常のJOIN
SELECT u.name, o.total
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.id = 123; -- シャードキーを含む
-- クロスシャード: アプリケーション側で結合
-- 1. users テーブルからデータ取得
-- 2. orders テーブルからデータ取得
-- 3. アプリケーション側でJOIN
リバランシング
シャード間でデータを再配置する作業です。
必要になる場面
- シャードの追加・削除
- データの偏りの解消
- パフォーマンスの最適化
コンシステントハッシング
シャード数が変わっても、移動するデータを最小限に抑える手法です。
| 手法 | シャード数変更 | データ移動量 |
|---|---|---|
| 従来のハッシュ | 4→5 | 約80% |
| コンシステントハッシング | 4→5 | 約20% |
シャーディングの課題
| 課題 | 対策 |
|---|---|
| トランザクションの複雑化 | 2相コミット、Sagaパターン |
| JOINの制限 | データの非正規化、アプリ側結合 |
| スキーマ変更の難しさ | オンラインDDLツール |
| 運用の複雑さ | マネージドサービスの利用 |
| バックアップと復元 | シャードごとの戦略 |
マネージドシャーディング
| サービス | 特徴 |
|---|---|
| Amazon Aurora | 自動シャーディング対応 |
| CockroachDB | 分散SQL、自動リバランス |
| Vitess | MySQL互換、YouTube開発 |
| MongoDB | 組み込みシャーディング |
| TiDB | MySQL互換、NewSQL |
シャーディングの判断基準
シャーディングが必要な場合:
- 単一DBの容量限界を超える
- 書き込みスループットが限界
- 垂直スケーリングのコストが高すぎる
まず検討すべき代替手段:
- 読み取りレプリカの追加
- キャッシュの導入
- クエリの最適化
- インデックスの見直し
- より大きなインスタンスへの移行
まとめ
シャーディングは、データベースの水平スケーリングを実現する強力な手法ですが、複雑さも伴います。シャードキーの選定が成功の鍵であり、アクセスパターンを十分に分析してから導入を決定しましょう。可能であれば、マネージドサービスの利用を検討することで運用負荷を軽減できます。
← 一覧に戻る