System Design Primer

donnemartin/system-design-primer の日本語READMEを、面接と実務の両方で使える「設計判断の地図」として再構成。

1 — 概要

System Design Primer は、大規模システム設計の学習素材、設計トピック、面接課題、補助的な暗算メモを体系化したオープンソースの索引。単なる用語集ではなく、「何を聞くか」「どこを深掘るか」「どのトレードオフを説明するか」を組み立てるための教材になっている。

4interview steps
CAPcore tradeoff
SQLor NoSQL
ns → mslatency scale
2 — 学習パス

README-ja.md の学習指針は「全部やれ」ではなく、持ち時間と経験に応じて幅・深さ・演習量を調整する考え方。まず全体を広く把握し、面接課題と実世界アーキテクチャで具体化していく。

期間学習範囲演習量狙い
短期システム設計トピックを広く読むいくつかの課題会話で詰まらない最低限の地図を作る
中期広く読み、重要領域をそれなりに深掘る多くの課題自分の回答と模範解答を比較できる状態にする
長期トピック、企業ブログ、実世界アーキを深く追うほぼ全ての課題設計選択の理由と失敗条件まで説明する
3 — システム設計面接の4ステップ

使用例・制約・推計を聞く

誰が使うか、機能、入力と出力、データ量、RPS、読み書き比率を質問で固める。

高レベル設計を描く

主要コンポーネントと接続をスケッチし、なぜその構成なのかを説明する。

核となる部品を深掘る

URL短縮ならハッシュ、衝突、SQL/NoSQL、スキーマ、APIなどを具体化する。

ボトルネックとスケールを議論する

ロードバランサー、水平スケール、キャッシュ、シャーディングとその副作用を扱う。

面接の本質: Yes/No で答える試験ではなく、制約を聞き出して会話を設計する場。設計案だけでなく、捨てた選択肢とトレードオフを説明できると強い。
4 — 設計トレードオフ

パフォーマンス問題は一人のユーザーにとって遅い状態。スケーラビリティ問題は一人では速いが、多数のリクエストで遅くなる状態。

レイテンシーは結果が返るまでの時間。スループットは単位時間あたりの処理数。通常は許容レイテンシー内で最大スループットを狙う。

CAPでは、一貫性・可用性・分断耐性のうち同時保証できるのは二つまで。ネットワークは信頼できないため、実務ではCPかAPかを選ぶ。

Consistency全ての読み取りが最新の書き込み、またはエラーを受け取る
Availability最新とは限らなくても、全リクエストへレスポンスする
Partition toleranceネットワーク分断や順不同があっても動作を続ける

アトミックな読み書きが重要ならCP。結果整合性や停止しないことが重要ならAP。ここでの選択が、データベース、キャッシュ、キュー、API設計の細部に波及する。

5 — リクエスト経路と構成要素
DNS名前解決。結果整合性の代表例。
CDN静的資産や一部レスポンスをエッジで返す。
LB不健康なサーバーや過負荷を避ける。
Reverse Proxy外部向け窓口、SSL終端、圧縮、キャッシュ。
App Layer単一責任のサービス群とAPI。
Cache / Queueホットデータと重い処理を吸収。
Database永続化、一貫性、クエリ、複製。
Layer 4 LB IPアドレスやポートなど、トランスポート層の情報で振り分ける。柔軟性は低いが軽い。
Layer 7 LB ヘッダー、メッセージ、Cookieなどを見て判断する。柔軟だが処理コストは増える。
6 — データ層の選び方

SQL/RDBMSは構造化データ、厳格なスキーマ、リレーショナルデータ、複雑なJOIN、トランザクションに向く。スケール手段は読み書きの性質によって選ぶ。

Read replica読み取りをスレーブに逃がす
Multi-master可用性と書き込み先制御
Federation機能ごとにDBを分ける
Shardingデータ断片を分散する

NoSQLは正規化を弱め、アプリケーション側でJOINすることが多い。BASEは一貫性より可用性を優先する説明として使われる。

Key-valueO(1)読み書き、キャッシュ向き
Document柔軟なオブジェクト表現
Wide column巨大データセットと高可用性
Graph複雑な関係性、SNS向き
選択向く条件注意点
SQL構造化データ、厳格なスキーマ、複雑なJOIN、トランザクション、成熟したエコシステム水平分割や分散JOINでアプリケーションロジックが複雑になる
NoSQL準構造化データ、柔軟なスキーマ、TB/PB級データ、高いIOPS、ログやクリックストリームACIDより結果整合性を選ぶ場面が多く、整合性モデルを説明する必要がある
7 — キャッシュと非同期処理

キャッシュは読み込み時間とDB負荷を下げるが、真のデータとの整合性と更新タイミングが難所になる。

パターン要点
Cache asideアプリがDBを読み、ミス時だけキャッシュへ追加
Write throughキャッシュが同期的にデータストアへ書く
Write behind書き込みを非同期化して性能を上げるが、損失リスクあり
Refresh ahead期限切れ前にホットな項目を更新する

非同期ワークフローは、インラインで処理するとリクエスト時間を圧迫する重い処理を分離する。キューが膨らみすぎる場合はバックプレッシャーで制限し、必要ならHTTP 503と再試行を返す。

Message queue ジョブをキューに渡し、ワーカーが処理する。ユーザー処理は止めない。
Task queue スケジュールや重いバックグラウンド処理を扱う。
def get_user(self, user_id):
    user = cache.get("user.{0}", user_id)
    if user is None:
        user = db.query("SELECT * FROM users WHERE user_id = {0}", user_id)
        if user is not None:
            key = "user.{0}".format(user_id)
            cache.set(key, json.dumps(user))
    return user
8 — 通信の選び分け

自己完結したリクエスト・レスポンスのアプリケーション層プロトコル。中間にLB、キャッシュ、暗号化、圧縮を置きやすい。

順序と欠損なしを保証する接続型プロトコル。信頼性が必要で、時間制約が厳しくない処理に向く。

保証を減らして低レイテンシーを狙う。VoIP、ビデオチャット、ストリーミング、リアルタイムゲーム向き。

操作RPCスタイルRESTスタイル
サインアップPOST /signupPOST /persons
Person読み込みGET /readPerson?personid=1234GET /persons/1234
アイテム更新POST /modifyItemPUT /items/456
アイテム削除POST /removeItemDELETE /items/456
9 — 暗算メモ
乗数厳密値目安
2^101,0241 KB
2^201,048,5761 MB
2^301,073,741,8241 GB
2^401,099,511,627,7761 TB
0.5 nsL1 cache reference
100 nsMain memory reference
150 usRead 4 KB randomly from SSD
500 usRound trip within same datacenter
10 msDisk seek
150 msCA to Netherlands to CA
面接で使うコツ: 厳密な値よりオーダー感が重要。メモリ、SSD、ディスク、ネットワークの差を即座に説明できると、見積りとボトルネック議論が速くなる。