mcpField
D
database-sharding

database-sharding

github.com/secondskyデータ・データベース240277 回インストール5 週間前に更新
リポジトリ

database-sharding について

データベースの水平スケーリングに向けたシャーディング戦略、ルーターテンプレート、実装ガイドを提供するスキルです。シャード構成を設計・運用する開発者向けに、キー選定、複数シャード操作、再バランスも扱います。

主な機能

  1. 01ハッシュ・範囲・ディレクトリ方式
  2. 02シャードルーターテンプレート
  3. 03シャードキー選定基準
  4. 04複数シャードのクエリとトランザクション指針
  5. 05監視と再バランスのガイド

活用シーン

  1. 01ユーザーやテナントデータのキー選定
  2. 02データベースのシャードルーティング層の構築
  3. 03シャード追加とデータ移行の計画
  4. 04ホットスポットや複数シャードクエリの調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/secondsky/claude-skills --skill database-sharding

インストール後、Claude Code で/database-shardingを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
cross-shard-queries.md
error-catalog.md
implementation-patterns.md
rebalancing-guide.md
shard-key-selection.md
sharding-strategies.md
templates/
cross-shard-aggregation.ts
directory-router.ts
hash-router.ts
range-router.ts

詳細

database-sharding

ハッシュ、範囲、ディレクトリベースの戦略を用いた水平スケーリングのための、包括的なデータベースシャーディングパターンです。


クイックスタート(10 分)

ステップ 1:テンプレートからシャーディング戦略を選択します:

# Hash-based (even distribution)
cat templates/hash-router.ts

# Range-based (time-series data)
cat templates/range-router.ts

# Directory-based (multi-tenancy)
cat templates/directory-router.ts

ステップ 2:シャードキーの条件を選択します:

  • ✅ 高いカーディナリティ(数百万の一意な値)
  • ✅ 均等な分布(単一の値が 5% を超えない)
  • ✅ 不変(変更されない)
  • ✅ クエリとの整合性(WHERE 句の 80% 以上で使用される)

ステップ 3:ルーターを実装します:

import { HashRouter } from './hash-router';

const router = new HashRouter([
  { id: 'shard_0', connection: { host: 'db0.example.com' } },
  { id: 'shard_1', connection: { host: 'db1.example.com' } },
  { id: 'shard_2', connection: { host: 'db2.example.com' } },
  { id: 'shard_3', connection: { host: 'db3.example.com' } },
]);

// Query single shard
const user = await router.query('user_123', 'SELECT * FROM users WHERE id = $1', ['user_123']);

重要なルール

✓ 必ず行うこと
ルール理由
クエリにシャードキーを含めるすべてのシャードのスキャンを回避します(100 倍遅くなります)
シャードの分布を監視する障害が発生する前にホットスポットを検出します
事前にリバランスを計画する後からシャードを簡単に追加することはできません
不変のシャードキーを選択するキーの変更はデータ移行の大きな問題につながります
本番データで分布をテストする合成データでは実際のホットスポットが隠れてしまいます
データ局所性のために非正規化する関連データを同じシャードに保持します
✗ 絶対に行わないこと
アンチパターン問題点
範囲シャーディングで連番 ID を使用する最新のシャードに書き込みが集中します(ホットスポット)
タイムスタンプをシャードキーにする最近のシャードに負荷が集中します
2PC を使わずにシャード間トランザクションを行うデータの破損や不整合が発生します
一貫性ハッシュを使わずに単純な剰余演算を使う全データを再シャーディングせずにシャードを追加できません
NULL を許容するシャードキーを使うNULL の特別な処理によってホットスポットが発生します
シャードのルーティングレイヤーを設けないシャードがハードコードされ、リバランスできません

重大なエラー 7 件

エラー 1:誤ったシャードキーの選択(ホットスポット)

症状:1 つのシャードにトラフィックの 80% 以上が集中します 修正:

// ❌ Bad: Low cardinality (status field)
shard_key = order.status; // 90% are 'pending' → shard_0 overloaded

// ✅ Good: High cardinality (user_id)
shard_key = order.user_id; // Millions of users, even distribution
エラー 2:クエリにシャードキーが含まれていない

症状:クエリがすべてのシャードをスキャンします(非常に遅くなります) 修正:

// ❌ Bad: No shard key
SELECT * FROM orders WHERE status = 'shipped'; // Scans all 100 shards!

// ✅ Good: Include shard key
SELECT * FROM orders WHERE user_id = ? AND status = 'shipped'; // Targets 1 shard
エラー 3:範囲シャーディングで連番 ID を使用している

症状:最新のシャードにすべての書き込みが集中します 修正:

// ❌ Bad: Range sharding with auto-increment
// Shard 0: 1-1M, Shard 1: 1M-2M, Shard 2: 2M+ → All new writes to Shard 2!

// ✅ Good: Hash-based sharding
const shardId = hash(id) % shardCount; // Even distribution
エラー 4:リバランス戦略がない

症状:初期のシャード数のまま拡張できません 修正:

// ❌ Bad: Simple modulo
const shardId = hash(key) % shardCount; // Adding 5th shard breaks ALL keys

// ✅ Good: Consistent hashing
const ring = new ConsistentHashRing(shards);
const shardId = ring.getNode(key); // Only ~25% of keys move when adding shard
エラー 5:シャード間トランザクション

症状:データの不整合や書き込みの一部欠落が発生します 修正:

// ❌ Bad: Cross-shard transaction (will corrupt)
BEGIN;
UPDATE shard_1.accounts SET balance = balance - 100 WHERE id = 'A';
UPDATE shard_2.accounts SET balance = balance + 100 WHERE id = 'B';
COMMIT; // If shard_2 fails, shard_1 already committed!

// ✅ Good: Two-Phase Commit or Saga pattern
const txn = new TwoPhaseCommitTransaction();
txn.addOperation(shard_1, 'UPDATE accounts SET balance = balance - 100 WHERE id = ?', ['A']);
txn.addOperation(shard_2, 'UPDATE accounts SET balance = balance + 100 WHERE id = ?', ['B']);
await txn.execute(); // Atomic across shards
エラー 6:変更可能なシャードキー

症状:レコードが別のシャードに移動し、重複が発生します 修正:

// ❌ Bad: Shard by country (user relocates)
shard_key = user.country; // User moves US → CA, now in different shard!

// ✅ Good: Shard by immutable user_id
shard_key = user.id; // Never changes
エラー 7:監視がない

症状:ホットスポットに気づかないまま、突然パフォーマンスが低下します 修正:

// ✅ Required metrics
- Per-shard record counts (should be within 20%)
- Query distribution (no shard > 40% of queries)
- Storage per shard (alert at 80%)
- Latency p99 per shard

詳細な修正方法を含む 10 件すべてのエラーについては、references/error-catalog.md を読み込んでください。


シャーディング戦略

戦略最適な用途メリットデメリット
ハッシュユーザーデータ、均等な負荷が重要な場合ホットスポットがなく、予測可能です範囲クエリが複数のシャードに分散します
範囲時系列データ、ログ、追記専用データ範囲クエリが効率的で、アーカイブにも適しています最近のシャードにホットスポットが発生します
ディレクトリマルチテナント、複雑なルーティング柔軟で、リバランスが容易ですルックアップのオーバーヘッド、単一障害点

本番環境での事例(Instagram、Discord、Salesforce)を含む詳細な比較については、references/sharding-strategies.md を読み込んでください。


シャードキーの選択条件

条件重要度確認方法
高いカーディナリティ重大COUNT(DISTINCT shard_key) > shard_count × 100
均等な分布重大どの値も全体の 5% を超えない
不変重大値が変更されない
クエリとの整合性高クエリの 80% 以上に含まれる
データ局所性中関連レコードが同じ場所にまとまる

判断ツリー:

  • ユーザー中心のアプリ → user_id
  • マルチテナント SaaS → tenant_id
  • 時系列データ/ログ → timestamp(範囲シャーディング)
  • 製品カタログ → product_id

包括的な判断ツリーとテスト戦略については、references/shard-key-selection.md を読み込んでください。


設定の概要

ハッシュベースのルーター
import { HashRouter } from './templates/hash-router';

const router = new HashRouter([
  { id: 'shard_0', connection: { /* PostgreSQL config */ } },
  { id: 'shard_1', connection: { /* PostgreSQL config */ } },
]);

// Automatically routes to correct shard
const user = await router.query('user_123', 'SELECT * FROM users WHERE id = $1', ['user_123']);
範囲ベースのルーター
import { RangeRouter } from './templates/range-router';

const router = new RangeRouter(shardConfigs, [
  { start: Date.parse('2024-01-01'), end: Date.parse('2024-04-01'), shardId: 'shard_q1' },
  { start: Date.parse('2024-04-01'), end: Date.parse('2024-07-01'), shardId: 'shard_q2' },
  { start: Date.parse('2024-07-01'), end: Infinity, shardId: 'shard_q3' },
]);

// Range queries target specific shards
const janEvents = await router.queryRange(
  Date.parse('2024-01-01'),
  Date.parse('2024-02-01'),
  'SELECT * FROM events WHERE created_at BETWEEN $1 AND $2'
);
ディレクトリベースのルーター
import { DirectoryRouter } from './templates/directory-router';

const router = new DirectoryRouter(directoryDBConfig, shardConfigs);

// Assign tenant to specific shard
await router.assignShard('tenant_acme', 'shard_enterprise');

// Route automatically
const users = await router.query('tenant_acme', 'SELECT * FROM users');

リファレンスを読み込むタイミング

戦略の選択

ロード references/sharding-strategies.md:

  • ハッシュ、範囲、ディレクトリのいずれかを選ぶ場合
  • 本番環境での例(Instagram、Discord)が必要な場合
  • ハイブリッド方式を計画する場合
シャードキーの選択

ロード references/shard-key-selection.md:

  • 新しいプロジェクトのシャードキーを選ぶ場合
  • 既存のシャードキーを評価する場合
  • 本番データで分散をテストする場合
実装

ロード references/implementation-patterns.md:

  • シャードルーターを一から構築する場合
  • コンシステントハッシュを実装する場合
  • トランザクション処理(2PC、Saga)が必要な場合
  • モニタリング/メトリクスを設定する場合
クロスシャード操作

ロード references/cross-shard-queries.md:

  • シャード間で集計(COUNT、SUM、AVG)する必要がある場合
  • クロスシャード結合を実装する場合
  • シャード間のページネーションを構築する場合
  • Scatter-Gather パターンを最適化する場合
リバランシング

ロード references/rebalancing-guide.md:

  • 新しいシャードを追加する場合
  • シャード間でデータを移行する場合
  • ゼロダウンタイム移行を計画する場合
  • 不均等な負荷を調整する場合
エラーの防止

ロード references/error-catalog.md:

  • パフォーマンスの問題をトラブルシューティングする場合
  • シャードアーキテクチャをレビューする場合
  • 修正方法が記載された、文書化済みの 10 件すべてのエラーを確認する場合

セットアップ完了チェックリスト

シャーディングの前:

  • 本番データでシャードキーの分散をテスト済み
  • クエリの 80% 以上にシャードキーが含まれている
  • モニタリング基盤の準備が完了している
  • リバランシング戦略を計画済み

ルーターの実装:

  • シャードルーティングレイヤー(シャードをハードコードしない)
  • シャードごとのコネクションプーリング
  • エラー処理と再試行
  • メトリクスの収集(シャードごとのクエリ数、レイテンシ)

シャードの設定:

  • 初期シャード数は 4~8(拡張の余地を確保)
  • コンシステントハッシュまたは仮想シャード
  • シャードごとのレプリカ(HA)
  • シャードごとのバックアップ戦略

アプリケーションの変更:

  • すべてのクエリにシャードキーを含める
  • クロスシャード結合を排除(非正規化)
  • トランザクション境界を遵守
  • コネクションプーリングを設定

本番環境の例

変更前(単一データベースに過負荷が発生):

// Single PostgreSQL instance
const db = new Pool({ host: 'db.example.com' });

// All 10M users on one server
const users = await db.query('SELECT * FROM users WHERE status = $1', ['active']);
// Query time: 5000ms (slow!)
// DB CPU: 95%
// Disk: 500GB, growing

変更後(8 台のサーバーにシャーディング):

// Hash-based sharding with 8 shards
const router = new HashRouter([
  { id: 'shard_0', connection: { host: 'db0.example.com' } },
  { id: 'shard_1', connection: { host: 'db1.example.com' } },
  // ... 6 more shards
]);

// Query single user (targets 1 shard)
const user = await router.query('user_123', 'SELECT * FROM users WHERE id = $1', ['user_123']);
// Query time: 10ms (500x faster!)

// Query all shards (scatter-gather)
const allActive = await router.queryAll('SELECT * FROM users WHERE status = $1', ['active']);
// Query time: 800ms (parallelized across 8 shards, 6x faster than single)

// Result: Each shard handles ~1.25M users
// DB CPU per shard: 20%
// Disk per shard: 65GB
// Can scale to 16 shards easily (consistent hashing)

既知の問題の防止

文書化済みの 10 件すべてのエラーを防止します:

  1. ✅ 誤ったシャードキー(ホットスポット)→ まず分散をテスト
  2. ✅ クエリにシャードキーがない → コードレビュー、リンティング
  3. ✅ クロスシャードトランザクション → 2PC または Saga パターンを使用
  4. ✅ 連番 ID によるホットスポット → ハッシュベースのシャーディングを使用
  5. ✅ リバランシング戦略がない → 初日からコンシステントハッシュを使用
  6. ✅ タイムスタンプシャーディングによるホットスポット → ハッシュと範囲のハイブリッド方式を使用
  7. ✅ 変更可能なシャードキー → 不変キー(user_id)を選択
  8. ✅ ルーティングレイヤーがない → 最初からルーターで抽象化
  9. ✅ モニタリングがない → シャードごとのメトリクスを追跡
  10. ✅ 弱いハッシュ関数 → MD5、MurmurHash3、xxHash を使用

参照:詳しい修正方法は references/error-catalog.md


リソース

テンプレート:

  • templates/hash-router.ts - ハッシュベースのシャーディング
  • templates/range-router.ts - 範囲ベースのシャーディング
  • templates/directory-router.ts - ディレクトリベースのシャーディング
  • templates/cross-shard-aggregation.ts - 集計パターン

リファレンス:

  • references/sharding-strategies.md - 戦略の比較
  • references/shard-key-selection.md - キー選択ガイド
  • references/implementation-patterns.md - ルーターの実装
  • references/cross-shard-queries.md - クエリパターン
  • references/rebalancing-guide.md - 移行戦略
  • references/error-catalog.md - 文書化済みの 10 件すべてのエラー

本番環境の例:

  • Instagram:メディア向けの範囲シャーディング
  • Discord:メッセージ向けのハッシュシャーディング
  • Salesforce:組織向けのディレクトリシャーディング

本番環境で検証済み | 10 件のエラーを防止 | MIT License

コメント