Show HN: システム設計のアトラス、インタラクティブなアーキテクチャ図付き
Show HN: An atlas of system designs with interactive architecture diagrams (atlas-sysdes.vercel.app)
要約
この「システム設計のアトラス」は、システム設計の基本的なトレードオフをインタラクティブな図で分かりやすく解説しています。記事では、事前計算かオンデマンド計算か、単一コピーか複数コピーか、単一マシンか複数マシンか、正確性か可用性かといった、システム設計における重要な選択肢とその影響を視覚的に提示しています。これにより、開発者は複雑なシステム設計の意思決定をより深く理解できるようになります。
全文翻訳
ほとんどすべての設計上の決定は、4つのトレードオフのいずれかである。
デザイン
15
最も頻繁に登場するものから順にランク付けされた、取り組まれた問題群。最初の5つで、尋ねられることのほとんどをカバーしています。
Twitter / Instagram フィード
毎秒15万回の読み取りを処理し、1つの投稿が1億人のフォロワーに届く可能性のあるホームタイムライン。
セレブリティ問題。中央値ユーザーにしか機能しない設計は失敗する — ファンアウトのコストは二峰性であり、コードパスは分割する必要がある。
Fan-out(ファンアウト)
イベントを多くの受信者に配信すること。例: 全フォロワーへの投稿。
Caching(キャッシング)
遅いルックアップをスキップするために、ホットなデータを高速なストレージに保持すること。
Cassandra
多数のノードにわたる大量の書き込みのために構築されたワイドカラムデータベース。
コア機能
非常に高速な書き込み(LSMツリー)
マスターレス、単一障害点なし
ノードを追加することによる線形スケーリング
クエリごとの整合性の調整
マルチデータセンターレプリケーション
使用するケース
書き込み負荷の高い時系列データやアクティビティフィード
常時稼働、マルチリージョンデータ
キーによるアクセスパターンが事前にわかっている場合
Pagination(ページネーション)
大きな結果セットを一度に1ページずつ返すこと。
Chat / Slack
5000万の同時ソケット、順序付けられたメッセージ配信、そして会話の途中でオフラインになるユーザー。
50個のステートフルなゲートウェイノードと、アリスへのメッセージがあるとします。送信者は彼女のソケットを保持しているノードをどのように見つけ、彼女がオフラインの場合はどうなるのでしょうか?
Real-time(リアルタイム)
発生した瞬間にクライアントにアップデートをプッシュすること。
WebSockets
ブラウザとサーバー間の永続的な双方向接続。
コア機能
1つのTCP接続でのフルデュプレックス
サーバープッシュ、ポーリングなし
メッセージあたりのオーバーヘッドが低い
ステートフル: スティッキー、ロードバランシングが難しい
使用するケース
チャット、ライブコラボレーション、マルチプレイヤー
ライブフィード、プレゼンス、通知
サーバーは要求されずにプッシュする必要がある場合
Cassandra
多数のノードにわたる大量の書き込みのために構築されたワイドカラムデータベース。
コア機能
非常に高速な書き込み(LSMツリー)
マスターレス、単一障害点なし
ノードを追加することによる線形スケーリング
クエリごとの整合性の調整
マルチデータセンターレプリケーション
使用するケース
書き込み負荷の高い時系列データやアクティビティフィード
常時稼働、マルチリージョンデータ
キーによるアクセスパターンが事前にわかっている場合
Idempotency(冪等性)
リクエストを繰り返しても、一度実行するのと同じ効果があること。
URL短縮サービス
1日あたり1億リンク、読み取りスキューが100対1。古典的な見積もりウォームアップ。
中央のボトルネックなしに、短く、ユニークで、推測不可能なキーを生成すること — そしてこれがデータベースの問題ではなく、キャッシュの問題であると認識すること。
Estimation(見積もり)
トラフィック、ストレージ、容量に関する概算計算。
Caching(キャッシング)
遅いルックアップをスキップするために、ホットなデータを高速なストレージに保持すること。
Redis
キャッシュ、カウンター、キュー、Pub/Subに使用されるインメモリデータストア。
コア機能
サブミリ秒の読み書き
リッチな型: ソート済みセット、ハッシュ、ストリーム
キーごとのTTL(有効期限)
アトミック操作とLuaスクリプト
オプションの永続化とレプリカ
使用するケース
データベースの前にホットな読み取りをキャッシュする
カウンター、レートリミット、リーダーボード
TTLを持つセッションや短命なデータ
Sharding(シャーディング)
データをマシンに分割し、単一ノードがすべてを保持しないようにすること。
分散レートリミッター
毎秒100万リクエストのレートで、ステートレスAPIサーバーのフリート全体にわたって強制されるグローバルな制限。
すべてのリクエストで同期Redisラウンドトリップなしにグローバル制限を強制すること — そしてリミッター自体のストアがダウンした場合に何が起こるかを決定すること。
Rate limiting(レート制限)
クライアントが時間ウィンドウあたりに送信できるリクエスト数を制限すること。
Redis
キャッシュ、カウンター、キュー、Pub/Subに使用されるインメモリデータストア。
コア機能
サブミリ秒の読み書き
リッチな型: ソート済みセット、ハッシュ、ストリーム
キーごとのTTL(有効期限)
アトミック操作とLuaスクリプト
オプションの永続化とレプリカ
使用するケース
データベースの前にホットな読み取りをキャッシュする
カウンター、レートリミット、リーダーボード
TTLを持つセッションや短命なデータ
Concurrency(並行性)
多くのリクエストが同時にアクセスする際にデータを正しく保つこと。
Reliability(信頼性)
システムの部品が故障した場合でも、稼働し続け、正しい状態を保つこと。
通知システム
多くのプロデューサーからのイベントが、受信者にマッチングされ、アプリ内、メール、プッシュで配信され、どれも失われないようにする。
サードパーティの配信チャネルは常に失敗し、レート制限されます。何も失われず、目に見えて重複せず、1つの不安定なプロバイダーが残りをダウンさせることは許されません。
Event-driven(イベント駆動)
サービスは互いに呼び出すのではなく、発行されたイベントに反応する。
Kafka
サービス間でイベントストリーミングするための、分散・パーティション化されたコミットログ。
コア機能
リプレイ可能性: コンシューマーがオフセットを巻き戻せる
耐久性があり、レプリケートされたパーティション
耐障害性: リーダーフェイルオーバー
高スループット、パーティションでスケールする
パーティション内の順序
使用するケース
多くのサービス間でイベントをストリーミングする
履歴をリプレイして再構築またはバックフィルする
大量のログ、メトリクス、クリックストリーム
Fan-out(ファンアウト)
イベントを多くの受信者に配信すること。例: 全フォロワーへの投稿。
Idempotency(冪等性)
リクエストを繰り返しても、一度実行するのと同じ効果があること。
Circuit breaker(サーキットブレーカー)
障害のある依存関係が回復するまで、呼び出しを停止すること。
検索とタイプアヘッド
10億ドキュメント、毎秒10万クエリ、そしてキーストロークごとに発火するオートコンプリート。
検索は散布・収集(scatter-gather)なので、レイテンシは最も遅いシャードに依存します。そしてインデックスは真実の源ではありません — それがどのように同期を保ち、遅延しているのかを説明する必要があります。
Search(検索)
テキストでドキュメントを見つけること。通常は転置インデックスを使用。
Elasticsearch
転置インデックス上に構築された分散検索エンジン。
コア機能
関連性ランキング付き全文検索
ニアリアルタイムインデックス作成
シャーディングおよびレプリケーション
集計とファセット
あいまいマッチングとオートコンプリート
使用するケース
全文検索とタイプアヘッド
ログの検索と分析
多くのフィールドにわたるフィルタリングとファセット
Sharding(シャーディング)
データをマシンに分割し、単一ノードがすべてを保持しないようにすること。
Caching(キャッシング)
遅いルックアップをスキップするために、ホットなデータを高速なストレージに保持すること。
Uber / 配達追跡
500万人のドライバーが4秒ごとに位置情報を公開し、リアルタイムでライダーとマッチング。
2つの問題が結合されています: 毎秒125万件の位置情報書き込みがディスクベースのインデックスを破壊し、2人のライダーが決して同じドライバーを受け取らないマッチングステップ。
Geospatial(ジオスペースシャル)
地図上の場所によってインデックス付けおよびクエリすること。
Redis
キャッシュ、カウンター、キュー、Pub/Subに使用されるインメモリデータストア。
コア機能
サブミリ秒の読み書き
リッチな型: ソート済みセット、ハッシュ、ストリーム
キーごとのTTL(有効期限)
アトミック操作とLuaスクリプト
オプションの永続化とレプリカ
使用するケース
データベースの前にホットな読み取りをキャッシュする
カウンター、レートリミット、リーダーボード
TTLを持つセッションや短命なデータ
Concurrency(並行性)
多くのリクエストが同時にアクセスする際にデータを正しく保つこと。
Real-time(リアルタイム)
発生した瞬間にクライアントにアップデートをプッシュすること。
Saga(サガ)
失敗時に補償ステップによって取り消されるマルチステップトランザクション。
動画ストリーミング
毎秒25テラビットのエグラスで動画をアップロード、トランスコード、配信。
動画バイトはアプリケーションサーバーに触れることはありません — アップロード時も、再生時も。実際に構築するのはメタデータサービスとトランスコーディングパイプラインです。
Object storage(オブジェクトストレージ)
S3のような、ファイルやブロブのための安価で耐久性のあるストレージ。
コア機能
極めて高い耐久性(11ナイン)
事実上無制限のスケール
GBあたりの低コスト、ストレージ階層
直接アップロードのためのプリサインURL
オブジェクト全体の書き込み、インプレース編集なし
使用するケース
ユーザーアップロード、メディア、バックアップ
クエリ可能なレコードよりも大きなファイル
データレイクと長期アーカイブ
CDN
ユーザーの近くからコンテンツを提供するエッジサーバー。
コア機能
近くのエッジからの低レイテンシ
オリジンからのトラフィックをオフロードする
静的ファイルをキャッシュする
トラフィックスパイクとDDoSを吸収する
使用するケース
静的アセット、画像、動画
オリジンから遠く離れたユーザー
エッジでのキャッシュ可能なAPIレスポンス
Chunking(チャンキング)
大きなファイルをアップロード、重複排除、同期のために分割すること。
Stream processing(ストリーム処理)
無限のイベントストリームで継続的に結果を計算すること。
Webクローラー
100億ページ、毎秒1万回のフェッチ、単一ドメインを過度に負荷かけることなく。
丁寧さ。速くクロールするのは簡単です。速くクロールしながら単一ホストに負荷をかけないようにするには、FIFOではなくホストごとにグループ化されたキュー設計が必要です。そして、見たものを保存できない規模での重複排除が必要です。
Bloom filter(ブルームフィルター)
「絶対にない」または「おそらくはい」と答えるコンパクトなセットチェック。
Deduplication(重複排除)
繰り返しアイテムやメッセージを検出してドロップすること。
Consistent hashing(一貫性ハッシュ)
ノードにキーをマッピングし、ノードを追加したときに少数のキーのみを移動させること。
Rate limiting(レート制限)
クライアントが時間ウィンドウあたりに送信できるリクエスト数を制限すること。
決済システム
信頼性の低い外部プロセッサを介した請求、キャプチャ、返金、支払い。バランスが取れなければならない元帳付き。
可用性よりも整合性が優先される唯一のデザインであり、「少なくとも1回」と「冪等性」がスローガンではなく、二重請求を防ぐメカニズムになる場合。
Consistency(整合性)
すべてのリーダーが最新の書き込みをいつ、どれだけ早く見るか。
Idempotency(冪等性)
リクエストを繰り返しても、一度実行するのと同じ効果があること。
Saga(サガ)
失敗時に補償ステップによって取り消されるマルチステップトランザクション。
Outbox(アウトボックス)
イベントをデータと共にデータベースに書き込み、その後発行すること。
Postgres
リレーショナルSQLデータベース。トランザクションデータの安全なデフォルト。
コア機能
ACIDトランザクション
JOIN、制約、外部キー
強い整合性
拡張機能: JSONB、PostGIS、全文検索
ストリーミングレプリケーションによるリードレプリカ
使用するケース
お金、注文、トランザクションが必要なものすべて
JOINでクエリされるリレーショナルデータ
スケールが強制されるまでのデフォルト
Ticketmaster / 予約
5万人が同じ秒に同じ100席を欲しがっている。
これはスケールではなく、競合です。行ロックの競合が最初に壊れます、スループットではありません — だから、より大きなクラスターではなく、アプリケーションティアの前にアドミッションコントロールが必要です。
Concurrency(並行性)
多くのリクエストが同時にアクセスする際にデータを正しく保つこと。
Consistency(整合性)
すべてのリーダーが最新の書き込みをいつ、どれだけ早く見るか。
Postgres
リレーショナルSQLデータベース。トランザクションデータの安全なデフォルト。
コア機能
ACIDトランザクション
JOIN、制約、外部キー
強い整合性
拡張機能: JSONB、PostGIS、全文検索
ストリーミングレプリケーションによるリードレプリカ
使用するケース
お金、注文、トランザクションが必要なものすべて
JOINでクエリされるリレーショナルデータ
スケールが強制されるまでのデフォルト
Saga(サガ)
失敗時に補償ステップによって取り消されるマルチステップトランザクション。
Dropbox / ファイル同期
2ギガバイトのファイルを1つの段落が変わっただけで再アップロードすることなく、デバイス間でファイルを同期する。
コンテンツ定義チャンキングとデルタ同期による帯域幅効率 — さらに、オフラインで同じファイルを編集した2つのクライアントのための整合性の取れたストーリー。
Chunking(チャンキング)
大きなファイルをアップロード、重複排除、同期のために分割すること。
Deduplication(重複排除)
繰り返しアイテムやメッセージを検出してドロップすること。
Object storage(オブジェクトストレージ)
S3のような、ファイルやブロブのための安価で耐久性のあるストレージ。
コア機能
極めて高い耐久性(11ナイン)
事実上無制限のスケール
GBあたりの低コスト、ストレージ階層
直接アップロードのためのプリサインURL
オブジェクト全体の書き込み、インプレース編集なし
使用するケース
ユーザーアップロード、メディア、バックアップ
クエリ可能なレコードよりも大きなファイル
データレイクと長期アーカイブ
Consistency(整合性)
すべてのリーダーが最新の書き込みをいつ、どれだけ早く見るか。
広告クリック集計
毎秒100万イベントを、高速なダッシュボードと正確な請求数値に集計する。
イベント時間。クリックは遅れて、順不同で、重複して到着します。到着時間で集計するのは簡単で間違っており、広告主はこれらの数値から請求されます。
Stream processing(ストリーム処理)
無限のイベントストリームで継続的に結果を計算すること。
Flink
ステートフルなリアルタイム計算のためのストリームプロセッサ。
コア機能
チェックポイントによるExactly-once状態
イベント時間ウィンドウとウォーターマーク
低レイテンシ処理
大規模キー付き状態、耐障害性
使用するケース
リアルタイム集計とアラート
ストリーム上の不正行為または異常検出
イベントストリームの結合とウィンドウ処理
OLAP
巨大なデータセットの集計に最適化された分析データベース。
コア機能
カラム型ストレージと圧縮
数十億行にわたる高速集計
マテリアライズドビューとロールアップ
例: ClickHouse, Druid, BigQuery
使用するケース
巨大なイベントテーブル上のダッシュボード
アドホック分析クエリ
行ごとの更新ではなく集計
Kafka
サービス間でイベントストリーミングするための、分散・パーティション化されたコミットログ。
コア機能
リプレイ可能性: コンシューマーがオフセットを巻き戻せる
耐久性があり、レプリケートされたパーティション
耐障害性: リーダーフェイルオーバー
高スループット、パーティションでスケールする
パーティション内の順序
使用するケース
多くのサービス間でイベントをストリーミングする
履歴をリプレイして再構築またはバックフィルする
大量のログ、メトリクス、クリックストリーム
Deduplication(重複排除)
繰り返しアイテムやメッセージを検出してドロップすること。
分散キャッシュ
Redisの構築: 100ノードが1テラバイトのホットデータをサブミリ秒の読み取りで保持する。
再バランシング。単純なモジュロハッシュは、ノードを追加したときにキャッシュの80%を無効にし、オリジンにスタンプします。そして一貫性ハッシュはホットキーを解決しません。
Consistent hashing(一貫性ハッシュ)
ノードにキーをマッピングし、ノードを追加したときに少数のキーのみを移動させること。
Caching(キャッシング)
遅いルックアップをスキップするために、ホットなデータを高速なストレージに保持すること。
Redis
キャッシュ、カウンター、キュー、Pub/Subに使用されるインメモリデータストア。
コア機能
サブミリ秒の読み書き
リッチな型: ソート済みセット、ハッシュ、ストリーム
キーごとのTTL(有効期限)
アトミック操作とLuaスクリプト
オプションの永続化とレプリカ
使用するケース
データベースの前にホットな読み取りをキャッシュする
カウンター、レートリミット、リーダーボード
TTLを持つセッションや短命なデータ
Replication(レプリケーション)
耐久性と読み取りスケールのために、複数のノードにデータのコピーを保持すること。
Google Docs
多くの人が1つのドキュメントに同時に入力し、知覚できる遅延なし、編集の消失なし。
収束。2人のユーザーが調整なしに同じ文を編集します。両者は同一のドキュメントで終わる必要があり、どちらの編集もサイレントに失われることは許されません — だから「最後に書いたものが勝つ」は壊滅的に間違っています。
CRDT / OT
競合する編集をマージし、すべてのコピーが同じ状態に収束するようにすること。
Consistency(整合性)
すべてのリーダーが最新の書き込みをいつ、どれだけ早く見るか。
WebSockets
ブラウザとサーバー間の永続的な双方向接続。
コア機能
1つのTCP接続でのフルデュプレックス
サーバープッシュ、ポーリングなし
メッセージあたりのオーバーヘッドが低い
ステートフル: スティッキー、ロードバランシングが難しい
使用するケース
チャット、ライブコラボレーション、マルチプレイヤー
ライブフィード、プレゼンス、通知
サーバーは要求されずにプッシュする必要がある場合
Real-time(リアルタイム)
発生した瞬間にクライアントにアップデートをプッシュすること。