engineering-system-designer について
新しいアーキテクチャの設計や既存システムの拡張に取り組むエンジニア向けのガイドです。設計手順、技術選択の枠組み、検証項目と容量計算スクリプトを提供します。
主な機能
- 01要件整理と容量見積もりの手順
- 02アーキテクチャとデータストアの選択指針
- 03障害分析とモニタリング計画
- 04容量計算スクリプト
活用シーン
- 01新規システムの設計
- 02既存アーキテクチャのレビューや拡張
- 03モノリスからサービスへの移行計画
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ peterhdd/ agent-skills --skill engineering-system-designerインストール後、Claude Code で/engineering-system-designerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/code-examples.mdfailure-analysis.mdscaling-patterns.mdworked-examples.mdscripts/capacity_calculator.py詳細
システム設計ガイド
概要
このガイドでは、プロダクト要件をデプロイ可能で、可観測性と耐障害性を備えた分散システムアーキテクチャに変換するプロセスを説明します。新規アーキテクチャの設計、既存システムのスケーリング、設計レビュー、アーキテクチャ決定記録の作成、モノリスからサービスへの移行に活用してください。
設計プロセス
1. 要件
機能要件、非機能目標(レイテンシ、スループット、耐久性)、読み取りと書き込みの比率、ピーク時のトラフィックパターン、地理的な分布を明確にします。関係者からトラフィック数値を得られない場合は、ユーザー数から推定します。DAU/MAU比率を10%、セッションあたりのリクエスト数を5件、8時間に全トラフィックの80%が集中すると仮定します(ピーク時は平均の3倍)。
2. キャパシティの見積もり
QPS、ストレージの増加量、帯域幅を計算します。負荷が1倍、5倍、10倍の場合を予測します。ボトルネックとなるリソースを特定します。計算には scripts/capacity_calculator.py を使用します。計算過程を必ず示してください。根拠を示さずにキャパシティを述べてはいけません。
3. 高レベルアーキテクチャ
コンポーネント、データストア、キュー、キャッシュ、外部依存関係を図にします。同期と非同期の境界を定義します。できるだけ少ないコンポーネントから始めます。3つのボックスで解決できるなら、7つ描いてはいけません。
4. コンポーネントの詳細設計
技術の選択とその根拠を示します。各ストアについて、パーティショニング、レプリケーション、一貫性モデル、キャッシュ無効化の方法を定義します。技術を選択する際は、必ず「よりシンプルな代替案ではなく、なぜこれを選ぶのか」に答えられるようにします。
5. データモデルと API の設計
主要なアクセスパターンに合わせてスキーマを設計します。エラーコードとレート制限を含む API 契約を定義します。移行戦略を計画します。すべてのテーブルについて、想定レイテンシとともに上位3つのクエリパターンを記載します。
6. 障害モード
すべてのコンポーネント障害とその影響範囲を列挙します。サーキットブレーカー、再試行、タイムアウト、フォールバックを定義します。各障害モードについて、何が停止するのか、誰が影響を受けるのか、どのように検知するのか、自動復旧の方法は何かを記載します。
7. モニタリング
リリース前に必要なメトリクス、アラート、ダッシュボードを指定します。すべての SLO に対応するアラートを設定します。すべてのアラートにランブックへのリンクを付けます。
判断フレームワーク
SQL と NoSQL の比較
- 複数のエンティティにまたがるトランザクション、レポート作成のための複雑な結合、または厳格なスキーマ制約が必要な場合は、SQL(デフォルトは PostgreSQL)を使用します。
- アクセスパターンがキーと値の検索である場合、スキーマが頻繁に変更される場合、または単一ノードを超える水平書き込みスケーリングが必要な場合は、NoSQL を使用します。
- 具体的な目安: 10TB 未満でリレーショナルなアクセスパターンの場合は PostgreSQL。100k QPS を超える負荷で10ms 未満のレイテンシが必要なキーと値のアクセスには Redis または DynamoDB。柔軟なスキーマで50TB 未満のドキュメントストアには MongoDB。1PB 超、または毎秒100万回超の書き込みが発生する時系列データには、ワイドカラム型の Cassandra または ScyllaDB。全文検索には、プライマリストアに Elasticsearch/OpenSearch を組み合わせます(信頼できる唯一の情報源として使ってはいけません)。
データベースのスケーリング目安
- 単一の PostgreSQL: 最新のハードウェアでは、最大約10k QPS の読み取りと約5k QPS の書き込みに対応します。読み取りが多い(読み取りが80%超)場合は、まず読み取りレプリカを追加します。
- 読み取りレプリカ: 読み取り QPS が単一ノードの処理能力を超える場合、または読み取りレイテンシの p95 が50ms を超える場合に追加します。レプリケーション遅延は1〜5秒を見込み、読み取りレプリカでは結果整合性を前提に設計します。
- コネクションプーリング(PgBouncer): 接続数が200を超える場合に必要です。アプリケーションから無制限に接続を開かせてはいけません。
- シャーディング: 単一ノードの書き込み QPS が不足する場合、または単一ノードのストレージが約5TBを超える場合に必要です。カーディナリティが最も高く、最も頻繁にクエリされる列をシャードキーに選びます。均等な分散にはハッシュベースのシャーディング、時系列データや地理データには範囲ベースのシャーディングを使用します。
- Redis によるキャッシュ: 同一の結果を返す同じクエリが1分間に100回を超えて実行される場合に追加します。キャッシュアサイドパターンを使用します。TTL を明示的に設定し、有効期限のないキャッシュは使わないでください。キャッシュヒット率が80%未満なら、キャッシュは役に立っていません。削除するか、キーの設計を修正します。
同期通信と非同期通信
- 呼び出し元が処理を進めるために結果を必要とし、200ms 未満のレイテンシを実現できる場合は、同期通信を使用します。
- 処理を後から完了できる場合、トラフィックの急増を吸収する必要がある場合、または下流サービスのレイテンシにばらつきがある場合は、非同期メッセージングを使用します。
- キューの選択: シンプルなジョブキュー(メッセージが 256KB 未満、少なくとも 1 回の配信)には SQS を使用します。1 万 msg/sec 未満のルーティング/優先度キューには RabbitMQ を使用します。1 万 msg/sec を超えるイベントストリーミング、リプレイ機能、または同じストリームを複数のコンシューマーが利用する場合は Kafka を使用します。
モノリスとマイクロサービス
- まずモノリスから始めます。明確なスケーリング上のボトルネック、独立したデプロイ頻度の要件、またはマージ競合を引き起こすチームの所有境界がある場合にのみ、サービスを切り出します。
- 一度に切り出すサービスは 1 つまでにします。次の切り出しに進む前に、運用準備が整っていることを検証します。
- チーム規模のルール: エンジニアが 10 人未満ならモノリス、10〜50 人なら明確なドメイン境界を持つモジュラーモノリス、50 人超ならチームの境界に沿ったマイクロサービスを採用します。アーキテクチャを運用能力より先行させてはいけません。
ロードバランシングと CDN
- 1k QPS 未満:ヘルスチェック付きの単一インスタンスで十分です。
- 1k〜50k QPS:オートスケーリンググループ(最小 2 インスタンス、CPU 使用率が 60% を超えた場合、またはリクエスト数に応じてスケール)とともに Application Load Balancer を使用します。
- 50k QPS 超:静的アセットとキャッシュ可能な API レスポンス用に CDN(CloudFront/Cloudflare)を追加します。トラフィックの 80% 超がキャッシュ可能であれば、CDN だけで負荷を処理できる可能性があります。
- 2 大陸を超える地域にユーザーがいる場合:Route 53 のレイテンシベースルーティング、または Cloudflare のグローバルロードバランシングを使用したマルチリージョンデプロイを行います。
レート制限
- すべての公開エンドポイントに対して、API ゲートウェイで適用します。デフォルトはユーザーごとに 100 req/min、IP ごとに 1000 req/min です。
- 書き込みの多いエンドポイント(POST/PUT/DELETE)では、ユーザーごとに 10〜30 req/min にします。
- 負荷の高い処理(検索、レポート、エクスポート)では、ユーザーごとに 5 req/min にします。
Retry-Afterヘッダーを付けて429 Too Many Requestsを返します。悪用の検知に備え、レート制限されたリクエストをログに記録します。
設計原則
- CAP 定理を意識する: 一貫性、可用性、分断耐性のうち、システムがどの 2 つを優先するかを把握し、トレードオフを明示的に文書化します。設計内の各データストアについて CAP のトレードオフを説明できない場合、その設計は未完成です。
- シンプルに始める: 要件を満たす最小限のコンポーネントから始めます。測定結果から必要性が示された場合にのみ複雑さを加えます。新しいコンポーネントを追加する場合は、解決する具体的なボトルネックを示す必要があります。「将来必要になるかもしれない」は理由になりません。
- 障害に備えて設計する: すべてのコンポーネントはいずれ障害を起こします。コードを書く前に、障害発生時の動作を定義します。障害モード分析がないコンポーネントは、本番環境に投入できる状態ではありません。
- 枯れた技術を優先する: 明確で定量化された優位性(スループット 2 倍超、コスト 50% 超削減、または枯れた技術では実現不可能な機能)がない限り、新しい選択肢より、十分に理解され運用実績の豊富なツールを選びます。
- 変更しやすい意思決定をする: システム全体を書き直さずに、コンポーネントを個別に交換、スケール、削除できる設計を優先します。コンポーネントの交換に 3 つを超えるサービスの変更が必要な場合は、抽象化レイヤーを追加します。
見積もりクイックリファレンス
- ストレージ: ユーザー 100 万人、平均 10 フィールド、それぞれ 100 バイトの場合、生データは約 1GB です。インデックスとオーバーヘッドを含めるため、3 倍を目安にします。
- 帯域幅: 平均レスポンスサイズ 5KB の API 呼び出しを 10k QPS で処理すると、50MB/s = 400Mbps です。2 倍の余裕を見込んで計画します。
- DAU から QPS を算出: DAU * avg_requests_per_session / seconds_in_peak_hours。ピーク時は平均の 3 倍です。
- レプリケーション: 耐久性を確保するには、最低 3 つのレプリカが必要です。リージョン間レプリケーションでは、レイテンシが 50〜200ms 増加します。
- 接続数の計算: PostgreSQL の接続 1 つあたり、約 10MB の RAM を使用します。100 接続では、接続だけで 1GB 必要です。200 を超える接続が必要な場合は PgBouncer を使用します。
参考:システム設計ドキュメントのテンプレート
すべてのシステム設計ドキュメントには、次の項目を含める必要があります。
- 問題の説明と機能要件。
- 具体的な数値目標を伴う非機能要件。
- 計算過程を示した容量見積もり。
- 高レベルのアーキテクチャ図の説明(コンポーネント、データフロー、プロトコル)。
- アクセスパターンとインデックス戦略を含むデータモデル。
- すべてのサービス境界に対する API 契約。
- すべてのコンポーネントの障害モード分析。
- 具体的なメトリクスとアラートしきい値を含む監視計画。
- サービス開始時と 10 倍の規模でのインフラコスト見積もり。
自己検証プロトコル
システム設計を完成させたら、提示する前に次の項目を確認してください。
- すべてのコンポーネントに障害モード分析があります。コンポーネントが停止したときに何が起きるかを説明できない場合、その設計は未完成です。
- すべてのデータストアについて、CAP に関するトレードオフが明示的に記載されています。「...なので、CP ではなく AP を選びました」という説明が必要です。
- 1 倍、5 倍、10 倍の容量計算が示されています。導出根拠のない数値がある場合は、仮定として明記してください。
- すべての技術選定について、「よりシンプルな代替案ではなく、なぜこれを選ぶのか?」に答えられます。答えが「使い慣れているから」であれば、モノリスでは妥当ですが、分散システムでは妥当ではありません。
- すべてのサービス境界に、リクエスト/レスポンスのスキーマ、エラーコード、レート制限を含む API 契約があります。
- 監視計画には、具体的なメトリクス名、アラートしきい値、ランブックへの参照があります。「監視します」だけでは不十分です。
- 相互参照:機能要件を読み返し、それぞれが少なくとも 1 つのコンポーネントに対応していることを確認してください。どのコンポーネントにも対応していない要件があれば、設計に不備があります。
- コスト見積もりが含まれています。インフラコストが月額 10,000 ドルを超える場合は、主な項目ごとに根拠を示してください。
障害からの復旧
- 設計がレイテンシ目標を満たさない:呼び出しチェーンの最長経路を特定します。まずボトルネックにキャッシュを追加してください。それでも不十分な場合は、非同期処理に移行するか、データモデルを非正規化します。レイテンシの問題を解決するためにコンポーネントを追加してはいけません。ホップ数を減らしてください。
- 書き込みスループットが単一ノードの容量を超える:ボトルネックが実際に存在することを確認します(負荷の高いクエリで
EXPLAIN ANALYZEを実行します)。確認できた場合は、カーディナリティが最も高い書き込みキーでシャーディングします。書き込みパターンが追記専用(ログ、イベント)の場合は、リレーショナルストアをシャーディングするのではなく、Kafka または時系列 DB を使用します。 - 設計レビューで要件の見落としが判明した:その場しのぎの修正を追加してはいけません。ステップ 1(要件)に戻り、容量見積もりを更新して、高レベルのアーキテクチャを再評価してください。継ぎ足しで拡張された設計は、負荷がかかると破綻します。
- ステークホルダーが設計原則に反する機能を求めている:トレードオフを明示的に記載してください。「リアルタイム同期を追加するには、このストアを CP から AP に切り替える必要があります。そのため、ユーザーには最大 5 秒間、古いデータが表示される可能性があります。」曖昧な懸念ではなく、具体的なトレードオフ情報をもとにステークホルダーに判断してもらいましょう。
- コスト見積もりが高すぎる:エッジから内側に向かって削減します。CDN を削除 → レプリカ数を減らす → インスタンスのサイズを小さくする → モノリスに簡素化する。コスト削減のために監視やバックアップを削ってはいけません。
既存システムの評価
既存システムの再設計やスケールが求められた場合:
- 提案の前に測定する — 現在の QPS、p50/p95/p99 レイテンシ、エラー率、ストレージの増加率を確認します。推測に基づく設計は失敗します。
- 実際のボトルネックを特定する — 推測せず、プロファイリングします。ボトルネックは、多くの場合、想定されている箇所とは異なります。遅いクエリ(pg_stat_statements)、接続の飽和、CPU バウンドか I/O バウンドか、キャッシュヒット率を確認します。
- 効果の大きい対策を見つける — スケーリングの問題の 80% を解決する単一の変更は何でしょうか?まずそこから始めます。よくある対策は、インデックスの追加、キャッシュの追加、読み取りレプリカの追加、負荷の高いジョブの非同期化です。
- うまくいっている部分は維持する — 現在のシステムがトラフィックの 80% を問題なく処理できているなら、書き換えないでください。問題を起こしている 20% をスケールします。
- 段階的に移行する — ストラングラーフィグパターンを使い、新しいトラフィックを新システムにルーティングし、古いトラフィックを徐々に移行します。1k QPS を超えるシステムで、一斉に切り替えてはいけません。
スクリプト
scripts/capacity_calculator.py-- トラフィックの想定値から QPS、ストレージ、帯域幅を計算します。オプションを確認するには--helpを指定して実行します。
容量の見積もり、API コントラクト、シャーディングを使ったデータベーススキーマ、サーキットブレーカーを含む実装パターンの全容については、コード例を参照してください。
URL 短縮サービスと WhatsApp のようなチャットシステムのシステム設計を、要件から本番アーキテクチャまで詳しく解説した例については、実践例を参照してください。
障害モード分析のテンプレート、キャッシュ戦略の比較、負荷遮断、バルクヘッドパターン、カオスエンジニアリングのチェックリストについては、障害分析を参照してください。
コンシステントハッシュ、データベースのシャーディング、CQRS、レート制限、バックプレッシャー処理、AWS のコスト見積もりテンプレートについては、スケーリングパターンを参照してください。