英語 ∙ 日本語 ∙ 简体中文 ∙ 繁體中文 |العَرَبِيَّة ∙ বাংলা ∙ ポルトガル語 do Brasil ∙ ドイツ語 ∙ ελληνικά ∙ עברית ∙ イタリア語 ∙ 한국어 ∙ فارسی ∙ Polski ∙ русский язык ∙ スペイン語 ∙ ภาษาไทย ∙ Türkçe ∙ tiếng Việt ∙ Français |翻訳の追加
このガイドの翻訳を手伝ってください!
大規模システムの設計方法を学びます。
システム設計面接の準備。
スケーラブルなシステムの設計方法を学ぶことは、より良いエンジニアになるのに役立ちます。
システム設計は幅広いトピックです。システム設計の原則に関する膨大な量のリソースがWeb全体に散らばっています。
このリポジトリは、大規模なシステムを構築する方法を学習するのに役立つリソースの整理されたコレクションです。
これは継続的に更新されるオープンソースプロジェクトです。
貢献は大歓迎です!
インタビューのコーディングに加えて、システム設計は、多くのテクノロジー企業でのテクニカルインタビュープロセスの必須コンポーネントです。
一般的なシステム設計の面接の質問を練習し、結果をサンプルソリューション(ディスカッション、コード、図)と比較します。
面接準備に関する追加トピック:
提供されているAnkiフラッシュカードデッキは、間隔を空けた繰り返しを使用して、主要なシステム設計コンセプトを保持するのに役立ちます。
外出先での使用に最適です。
コーディング面接の準備に役立つリソースをお探しですか?
追加のAnkiデッキを含む姉妹リポジトリのインタラクティブコーディングチャレンジをチェックしてください。
コミュニティから学びましょう。
プルリクエストを送信して、以下を確認してください。
ある程度の推敲が必要なコンテンツは開発中です。
投稿ガイドラインを確認します。
長所と短所を含むさまざまなシステム設計トピックの要約。 すべてがトレードオフです。
各セクションには、より詳細なリソースへのリンクが含まれています。
面接のタイムラインに基づいて確認する推奨トピック(短、中、長)。
Q:面接のために、私はここですべてを知る必要がありますか?
A:いいえ、面接の準備をするためにここですべてを知る必要はありません。
面接で尋ねられる内容は、次のような変数によって異なります。
経験豊富な候補者は、一般的にシステム設計についてもっと知っていることが期待されます。アーキテクトやチーム リーダーは、個々のコントリビューターよりも多くのことを知っていることが期待される場合があります。トップテクノロジー企業は、1回以上のデザイン面接ラウンドを行う可能性があります。
幅広く始めて、いくつかの分野で深く掘り下げてください。さまざまな主要なシステム設計トピックについて少し知っておくと役立ちます。タイムライン、経験、面接するポジション、面接する企業に基づいて、次のガイドを調整してください。
短い | 中程度 | 長い | |
---|---|---|---|
システム設計のトピックを読んで、システムがどのように機能するかを幅広く理解してください | |||
あなたがインタビューしている会社の会社のエンジニアリングブログのいくつかの記事を読んでください | |||
いくつかの実世界のアーキテクチャを読む | |||
システム設計面接の質問へのアプローチ方法を確認する | |||
ソリューションを使用したシステム設計の面接の質問に取り組む | 幾 | 多い | 最も |
オブジェクト指向設計の面接の質問をソリューションで解決する | 幾 | 多い | 最も |
システム設計に関するその他の面接の質問を確認する | 幾 | 多い | 最も |
システム設計の面接の質問に取り組む方法。
システム設計インタビューは自由形式の会話です。あなたはそれを導くことが期待されています。
次の手順を使用して、ディスカッションをガイドできます。このプロセスを固めるには、次の手順を使用して、ソリューションを使用したシステム設計面接の質問セクションに取り組みます。
要件を収集し、問題の範囲を特定します。ユースケースと制約を明確にするために質問をします。仮定について話し合います。
すべての重要なコンポーネントを含む高レベルの設計の概要を説明します。
各コアコンポーネントの詳細を詳しく説明してください。たとえば、URL 短縮サービスの設計を依頼された場合は、以下について話し合います。
制約を考慮して、ボトルネックを特定して対処します。たとえば、スケーラビリティの問題に対処するには、次のものが必要ですか?
考えられる解決策とトレードオフについて話し合います。すべてがトレードオフです。スケーラブルなシステム設計の原則を使用してボトルネックに対処します。
手作業で見積もりを行うように求められる場合があります。次のリソースについては、付録を参照してください。
次のリンクをチェックして、何を期待できるかをよりよく理解してください。
一般的なシステム設計面接の質問と、サンプルディスカッション、コード、および図。
フォルダー内のコンテンツにリンクされたソリューション。
solutions/
質問 | |
---|---|
設計 Pastebin.com(または Bit.ly) | 解決 |
Twitterのタイムラインと検索(またはFacebookのフィードと検索)をデザインする | 解決 |
Web クローラーを設計する | 解決 |
設計 Mint.com | 解決 |
ソーシャル ネットワークのデータ構造を設計する | 解決 |
検索エンジンのキーと値のストアを設計する | 解決 |
Amazonのカテゴリー別売上ランキング機能のデザイン | 解決 |
AWS 上の数百万人のユーザーに拡張できるシステムを設計する | 解決 |
システム設計の質問を追加する | 貢献する |
一般的なオブジェクト指向設計の面接の質問と、サンプルのディスカッション、コード、および図。
フォルダー内のコンテンツにリンクされたソリューション。
solutions/
注:このセクションは開発中です
質問 | |
---|---|
ハッシュ マップを設計する | 解決 |
最も長く使用されていないキャッシュを設計する | 解決 |
コール センターを設計する | 解決 |
カードのデッキをデザインする | 解決 |
駐車場を設計する | 解決 |
チャット サーバーを設計する | 解決 |
循環配列を設計する | 貢献する |
オブジェクト指向設計の質問を追加する | 貢献する |
システム設計は初めてですか?
まず、一般的な原則の基本的な理解、それらが何であるか、それらがどのように使用されるか、およびそれらの長所と短所について学ぶ必要があります。
次に、高レベルのトレードオフを見ていきます。
すべてがトレードオフであることに注意してください。
次に、DNS、CDN、ロードバランサーなどのより具体的なトピックについて詳しく説明します。
サービスは、追加されたリソースに比例してパフォーマンスが向上する場合、スケーラブルです。一般に、パフォーマンスの向上は、より多くの作業単位を提供することを意味しますが、データセットが大きくなる場合など、より大きな作業単位を処理することもできます。1
パフォーマンスとスケーラビリティを見る別の方法:
レイテンシーは、何らかのアクションを実行したり、何らかの結果を生成したりする時間です。
スループットは、単位時間あたりのそのようなアクションまたは結果の数です。
一般に、許容可能な待機時間で最大のスループットを目指す必要があります。
分散コンピューター システムでは、次の保証のうち 2 つだけをサポートできます。
ネットワークは信頼できないため、パーティションの許容範囲をサポートする必要があります。一貫性と可用性の間でソフトウェアのトレードオフを行う必要があります。
パーティション・ノードからの応答を待機すると、タイムアウト・エラーが発生する可能性があります。CPは、ビジネスニーズにアトミックな読み取りと書き込みが必要な場合に適しています。
応答は、任意のノードで使用可能なデータの最も簡単に利用できるバージョンを返しますが、最新ではない可能性があります。パーティションが解決されると、書き込みが反映されるまでに時間がかかる場合があります。
APは、ビジネスが最終的な一貫性を考慮する必要がある場合、または外部エラーにもかかわらずシステムが動作し続ける必要がある場合に適しています。
同じデータの複数のコピーがある場合、クライアントがデータの一貫したビューを持つように、それらを同期する方法に関するオプションに直面しています。CAP定理から一貫性の定義を思い出してください-すべての読み取りは最新の書き込みまたはエラーを受け取ります。
書き込み後、読み取りでは表示される場合と表示されない場合があります。ベストエフォートアプローチが取られます。
このアプローチは、memcachedなどのシステムで見られます。弱い一貫性は、VoIP、ビデオチャット、リアルタイムマルチプレイヤーゲームなどのリアルタイムユースケースでうまく機能します。たとえば、通話中に数秒間受信が途絶えた場合、接続を回復しても、接続が失われたときに話された内容が聞こえません。
書き込み後、読み取りは最終的にそれを確認します (通常はミリ秒以内)。データは非同期的にレプリケートされます。
このアプローチは、DNSや電子メールなどのシステムで見られます。最終的な整合性は、高可用性システムで適切に機能します。
書き込み後、読み取りはそれを認識します。データは同期的にレプリケートされます。
このアプローチは、ファイルシステムとRDBMSで見られます。強力な一貫性は、トランザクションを必要とするシステムで適切に機能します。
高可用性をサポートするには、フェールオーバーとレプリケーションという 2 つの補完的なパターンがあります。
アクティブ/パッシブ フェールオーバーでは、スタンバイ状態のアクティブ サーバーとパッシブ サーバーの間でハートビートが送信されます。ハートビートが中断されると、パッシブ サーバーがアクティブ サーバーの IP アドレスを引き継ぎ、サービスを再開します。
ダウンタイムの長さは、パッシブ サーバーが既に "ホット" スタンバイで実行されているかどうか、または "コールド" スタンバイから起動する必要があるかどうかによって決まります。アクティブなサーバーのみがトラフィックを処理します。
アクティブ/パッシブフェイルオーバーは、マスター/スレーブフェイルオーバーとも呼ばれます。
アクティブ/アクティブでは、両方のサーバーがトラフィックを管理しており、サーバー間で負荷を分散しています。
サーバーが公開されている場合、DNS は両方のサーバーのパブリック IP について認識する必要があります。サーバーが内部向けである場合、アプリケーション ロジックは両方のサーバーについて認識する必要があります。
アクティブ/アクティブ フェールオーバーは、マスター/マスター フェールオーバーとも呼ばれます。
このトピックについては、「データベース」セクションで詳しく説明します。
可用性は、多くの場合、サービスが利用可能な時間の割合としてのアップタイム (またはダウンタイム) によって定量化されます。可用性は通常、9 の数で測定され、99.99% の可用性を持つサービスは 9 つの <> を持つと説明されます。
期間 | 許容可能なダウンタイム |
---|---|
年間ダウンタイム | 8時間45分57秒 |
月あたりのダウンタイム | 43メートル49.7秒 |
週あたりのダウンタイム | 10メートル4.8秒 |
1 日あたりのダウンタイム | 1メートル26.4秒 |
期間 | 許容可能なダウンタイム |
---|---|
年間ダウンタイム | 52分35秒7 |
月あたりのダウンタイム | 4メートル23秒 |
週あたりのダウンタイム | 1メートル5秒 |
1 日あたりのダウンタイム | 8.6秒 |
サービスが障害が発生しやすい複数のコンポーネントで構成されている場合、サービスの全体的な可用性は、コンポーネントが順番に並んでいるか並列になっているかによって異なります。
全体的な可用性は、可用性が 100% < <> つのコンポーネントが順番に存在する場合に低下します。
Availability (Total) = Availability (Foo) * Availability (Bar)
両方とそれぞれの可用性が 99.9% の場合、シーケンスの合計可用性は 99.8% になります。
Foo
Bar
全体的な可用性は、可用性が 100% < <> つのコンポーネントが並列になっている場合に増加します。
Availability (Total) = 1 - (1 - Availability (Foo)) * (1 - Availability (Bar))
両方とそれぞれの可用性が 99.9% の場合、並列での合計可用性は 99.9999% になります。
Foo
Bar
ドメイン ネーム システム (DNS) は、www.example.com などのドメイン名を IP アドレスに変換します。
DNSは階層構造になっており、トップレベルにはいくつかの権限のあるサーバーがあります。ルーターまたはISPは、ルックアップを実行するときに接続するDNSサーバーに関する情報を提供します。下位レベルの DNS サーバーはマッピングをキャッシュしますが、DNS 伝達の遅延が原因で古くなる可能性があります。DNS の結果は、ブラウザーまたは OS によって、有効期限 (TTL) によって決定される一定期間キャッシュすることもできます。
CNAME
A
CloudFlareやRoute 53などのサービスは、マネージドDNSサービスを提供します。一部の DNS サービスでは、さまざまな方法でトラフィックをルーティングできます。
コンテンツ配信ネットワーク (CDN) は、プロキシ サーバーのグローバルに分散されたネットワークであり、ユーザーに近い場所からコンテンツを提供します。一般に、HTML/CSS/JS、PHOTOS、ビデオなどの静的ファイルはCDNから提供されますが、AmazonのCloudFrontなどの一部のCDNは動的コンテンツをサポートしています。サイトのDNS解決は、どのサーバーに接続するかをクライアントに通知します。
CDN からコンテンツを提供すると、次の 2 つの方法でパフォーマンスが大幅に向上します。
プッシュCDNは、サーバーで変更が発生するたびに新しいコンテンツを受け取ります。コンテンツの提供、CDN への直接アップロード、および CDN を指すように URL を書き換えることについては、お客様が全責任を負います。コンテンツの有効期限が切れるタイミングと更新されるタイミングを構成できます。コンテンツは新規または変更された場合にのみアップロードされるため、トラフィックは最小限に抑えられますが、ストレージは最大化されます。
トラフィック量が少ないサイトや、頻繁に更新されないコンテンツを含むサイトは、プッシュCDNでうまく機能します。 コンテンツは、定期的に再プルされるのではなく、CDNに一度配置されます。
プルCDNは、最初のユーザーがコンテンツを要求したときにサーバーから新しいコンテンツを取得します。コンテンツをサーバーに残し、CDN を指すように URL を書き換えます。これにより、コンテンツが CDN にキャッシュされるまで、要求が遅くなります。
有効期限 (TTL) は、コンテンツがキャッシュされる期間を決定します。プル CDN は CDN のストレージ領域を最小限に抑えますが、ファイルの有効期限が切れ、実際に変更される前にプルされると、冗長なトラフィックが発生する可能性があります。
トラフィックの多いサイトは、トラフィックがより均等に分散され、最近要求されたコンテンツのみがCDNに残るため、プルCDNでうまく機能します。
ロードバランサーは、受信クライアント要求をアプリケーションサーバーやデータベースなどのコンピューティングリソースに分散します。いずれの場合も、ロード バランサーはコンピューティング リソースからの応答を適切なクライアントに返します。ロードバランサーは、次の場合に効果的です。
ロードバランサーは、ハードウェア(高価)またはHAProxyなどのソフトウェアを使用して実装できます。
その他の利点は次のとおりです。
障害から保護するために、アクティブ/パッシブモードまたはアクティブ/アクティブモードで複数のロードバランサーを設定するのが一般的です。
ロードバランサーは、次のようなさまざまなメトリックに基づいてトラフィックをルーティングできます。
レイヤー 4 ロードバランサーは、トランスポートレイヤーの情報を参照して、リクエストの分散方法を決定します。通常、これにはヘッダー内の送信元、宛先 IP アドレス、およびポートが含まれますが、パケットの内容は含まれません。レイヤー 4 ロードバランサーは、ネットワークアドレス変換 (NAT) を実行して、アップストリームサーバーとの間でネットワークパケットを転送します。
レイヤー 7 ロードバランサーは、アプリケーションレイヤーを参照して、リクエストの分散方法を決定します。これには、ヘッダー、メッセージ、および Cookie の内容が含まれる場合があります。レイヤー 7 ロードバランサーは、ネットワークトラフィックを終了し、メッセージを読み取り、負荷分散の決定を行ってから、選択したサーバーへの接続を開きます。たとえば、レイヤー 7 ロード バランサーは、ビデオ トラフィックをビデオをホストするサーバーに転送し、より機密性の高いユーザーの課金トラフィックをセキュリティが強化されたサーバーに転送できます。
柔軟性を犠牲にして、レイヤー4のロードバランシングはレイヤー7よりも少ない時間とコンピューティングリソースを必要としますが、最新のコモディティハードウェアではパフォーマンスへの影響を最小限に抑えることができます。
ロードバランサーは、水平スケーリングにも役立ち、パフォーマンスと可用性を向上させます。コモディティ マシンを使用したスケール アウトは、垂直スケーリングと呼ばれる、より高価なハードウェア上の単一のサーバーをスケール アップするよりもコスト効率が高く、可用性も高くなります。また、特殊なエンタープライズシステムよりも、コモディティハードウェアで作業する人材を採用する方が簡単です。
リバースプロキシは、内部サービスを集中化し、統一されたインターフェイスを一般に提供するWebサーバーです。クライアントからの要求は、リバース プロキシがサーバーの応答をクライアントに返す前に、それを実行できるサーバーに転送されます。
その他の利点は次のとおりです。
Web レイヤーをアプリケーションレイヤー (プラットフォームレイヤーとも呼ばれます) から分離すると、両方のレイヤーを個別にスケーリングおよび構成できます。新しい API を追加すると、必ずしも Web サーバーを追加することなく、アプリケーションサーバーが追加されます。単一責任の原則は、連携する小規模で自律的なサービスを提唱しています。小規模なサービスを持つ小規模なチームは、急速な成長のためにより積極的に計画を立てることができます。
アプリケーション層のワーカーは、非同期の有効化にも役立ちます。
この説明に関連するマイクロサービスは、独立してデプロイ可能な小規模なモジュラーサービスのスイートとして説明できます。各サービスは独自のプロセスを実行し、明確に定義された軽量のメカニズムを介して通信して、ビジネス目標を達成します。1
たとえば、Pinterestには、ユーザープロファイル、フォロワー、フィード、検索、写真のアップロードなどのマイクロサービスを含めることができます。
Consul、etcd、Zookeeperなどのシステムは、登録名、住所、およびポートを追跡することにより、サービスがお互いを見つけるのに役立ちます。ヘルスチェックはサービスの整合性の検証に役立ち、多くの場合、HTTP エンドポイントを使用して行われます。Consulとetcdの両方に、構成値やその他の共有データを格納するのに役立つキーバリューストアが組み込まれています。
ソース: 最初の 10,<> 万人のユーザーへのスケールアップ
SQLのようなリレーショナルデータベースは、テーブルに編成されたデータ項目のコレクションです。
ACID は、リレーショナル データベース トランザクションのプロパティのセットです。
リレーショナル データベースのスケーリングには、マスター/スレーブ レプリケーション、マスター/マスター レプリケーション、フェデレーション、シャーディング、非正規化、SQL チューニングなど、さまざまな手法があります。
マスターは読み取りと書き込みを処理し、読み取りのみを提供する1つ以上のスレーブに書き込みを複製します。スレーブは、ツリーのような方法で追加のスレーブに複製することもできます。マスターがオフラインになった場合、システムは、スレーブがマスターに昇格するか、新しいマスターがプロビジョニングされるまで、読み取り専用モードで動作し続けることができます。
両方のマスターは、読み取りと書き込みを行い、書き込み時に相互に調整します。いずれかのマスターがダウンした場合、システムは読み取りと書き込みの両方で動作を継続できます。
ソース: 最初の 10,<> 万人のユーザーへのスケールアップ
フェデレーション (または機能パーティション分割) は、データベースを機能別に分割します。たとえば、単一のモノリシック データベースの代わりに、フォーラム、ユーザー、製品の 3 つのデータベースを使用して、各データベースへの読み取りおよび書き込みトラフィックを減らし、レプリケーションの遅延を減らすことができます。データベースが小さいほど、メモリに収まるデータが多くなり、キャッシュの局所性が向上するため、キャッシュヒットが増加します。書き込みをシリアル化する中央マスターが 1 つないため、並列で書き込みを行うことができ、スループットが向上します。
シャーディングは、各データベースがデータのサブセットのみを管理できるように、データを異なるデータベースに分散します。ユーザー データベースを例にとると、ユーザー数が増えると、クラスターにシャードが追加されます。
フェデレーションの利点と同様に、シャーディングにより、読み取りと書き込みのトラフィック、レプリケーション、キャッシュ ヒットが増加します。インデックス サイズも小さくなり、一般にクエリが高速になり、パフォーマンスが向上します。1 つのシャードがダウンしても、他のシャードは引き続き動作しますが、データの損失を防ぐために何らかの形式のレプリケーションを追加する必要があります。フェデレーションと同様に、書き込みをシリアル化する単一の中央マスターは存在しないため、スループットを向上させながら並列に書き込むことができます。
ユーザーのテーブルをシャード化する一般的な方法は、ユーザーの姓のイニシャルまたはユーザーの地理的な場所を使用することです。
非正規化は、書き込みパフォーマンスをいくらか犠牲にして、読み取りパフォーマンスの向上を試みます。データの冗長コピーは、コストのかかる結合を回避するために複数のテーブルに書き込まれます。PostgreSQLやOracleなどの一部のRDBMSは、冗長な情報を格納し、冗長なコピーの一貫性を維持する作業を処理するマテリアライズドビューをサポートしています。
フェデレーションやシャーディングなどの手法を使用してデータが分散されると、データセンター間での結合の管理はさらに複雑になります。非正規化は、このような複雑な結合の必要性を回避する可能性があります。
ほとんどのシステムでは、読み取りは書き込み数を 100:1 または 1000:1 で大幅に上回る可能性があります。読み取りによってデータベースが複雑になると、非常にコストがかかり、ディスク操作にかなりの時間が費やされる可能性があります。
SQLチューニングは幅広いトピックであり、多くの本が参照として書かれています。
ベンチマークとプロファイリングを行い、ボトルネックをシミュレートして発見することが重要です。
ベンチマークとプロファイリングでは、次の最適化が示される場合があります。
CHAR
VARCHAR
CHAR高速のランダムアクセスを効果的に可能にしますが、 では、次の文字列に進む前に文字列の末尾を見つける必要があります。
VARCHAR
TEXT
TEXT
TEXT
INT
DECIMAL
BLOBS
VARCHAR(255)は、8ビットの数値でカウントできる最大文字数であり、多くの場合、一部のRDBMSではバイトの使用を最大化します。
NOT NULL
SELECT
GROUP BY
ORDER BY
JOIN
NoSQL は、キー値ストア、ドキュメント ストア、ワイド列ストア、またはグラフ データベースで表されるデータ項目のコレクションです。データは非正規化され、結合は通常、アプリケーション コードで行われます。ほとんどの NoSQL ストアには真の ACID トランザクションがなく、最終的な一貫性が優先されます。
BASEは、NoSQLデータベースのプロパティを記述するためによく使用されます。CAP定理と比較して、BASEは一貫性よりも可用性を選択します。
SQLまたはNoSQLのどちらかを選択することに加えて、ユースケースに最適なNoSQLデータベースのタイプを理解することは役立ちます。次のセクションでは、キー値ストア、ドキュメント ストア、ワイド列ストア、グラフ データベースを確認します。
抽象化:ハッシュテーブル
キーバリューストアは通常、O(1)の読み取りと書き込みを可能にし、多くの場合、メモリまたはSSDによってバックアップされます。データ ストアは、キーを辞書順に保持できるため、キー範囲を効率的に取得できます。キー値ストアでは、値を持つメタデータを格納できます。
キー値ストアは高いパフォーマンスを提供し、単純なデータ モデルや、メモリ内キャッシュ レイヤーなどの急速に変化するデータによく使用されます。提供される操作のセットは限られているため、追加の操作が必要な場合は、複雑さがアプリケーション層に移ります。
キー値ストアは、ドキュメントストアや、場合によってはグラフデータベースなどのより複雑なシステムの基礎となります。
抽象化:値として保存されたドキュメントを持つキーバリューストア
ドキュメントストアはドキュメント(XML、JSON、バイナリなど)を中心にしており、ドキュメントには特定のオブジェクトのすべての情報が格納されます。ドキュメント ストアは、ドキュメント自体の内部構造に基づいてクエリを実行するための API またはクエリ言語を提供します。多くのキーバリューストアには、値のメタデータを操作する機能が含まれているため、これら 2 つのストレージタイプの境界線があいまいになっています。
基になる実装に基づいて、ドキュメントはコレクション、タグ、メタデータ、またはディレクトリ別に編成されます。ドキュメントは整理またはグループ化できますが、ドキュメントには互いに完全に異なるフィールドが含まれる場合があります。
MongoDB や CouchDB などの一部のドキュメント ストアでは、複雑なクエリを実行するための SQL に似た言語も用意されています。DynamoDB は、キー値とドキュメントの両方をサポートしています。
ドキュメント ストアは高い柔軟性を提供し、頻繁に変更されるデータの操作によく使用されます。
Source: SQL & NoSQL, a brief history
Abstraction: nested map
ColumnFamily<RowKey, Columns<ColKey, Value, Timestamp>>
A wide column store's basic unit of data is a column (name/value pair). A column can be grouped in column families (analogous to a SQL table). Super column families further group column families. You can access each column independently with a row key, and columns with the same row key form a row. Each value contains a timestamp for versioning and for conflict resolution.
Google introduced Bigtable as the first wide column store, which influenced the open-source HBase often-used in the Hadoop ecosystem, and Cassandra from Facebook. Stores such as BigTable, HBase, and Cassandra maintain keys in lexicographic order, allowing efficient retrieval of selective key ranges.
Wide column stores offer high availability and high scalability. They are often used for very large data sets.
Abstraction: graph
In a graph database, each node is a record and each arc is a relationship between two nodes. Graph databases are optimized to represent complex relationships with many foreign keys or many-to-many relationships.
Graphs databases offer high performance for data models with complex relationships, such as a social network. They are relatively new and are not yet widely-used; it might be more difficult to find development tools and resources. Many graphs can only be accessed with REST APIs.
Source: Transitioning from RDBMS to NoSQL
Reasons for SQL:
Reasons for NoSQL:
Sample data well-suited for NoSQL:
Source: Scalable system design patterns
Caching improves page load times and can reduce the load on your servers and databases. In this model, the dispatcher will first lookup if the request has been made before and try to find the previous result to return, in order to save the actual execution.
Databases often benefit from a uniform distribution of reads and writes across its partitions. Popular items can skew the distribution, causing bottlenecks. Putting a cache in front of a database can help absorb uneven loads and spikes in traffic.
Caches can be located on the client side (OS or browser), server side, or in a distinct cache layer.
CDNs are considered a type of cache.
Reverse proxies and caches such as Varnish can serve static and dynamic content directly. Web servers can also cache requests, returning responses without having to contact application servers.
Your database usually includes some level of caching in a default configuration, optimized for a generic use case. Tweaking these settings for specific usage patterns can further boost performance.
In-memory caches such as Memcached and Redis are key-value stores between your application and your data storage. Since the data is held in RAM, it is much faster than typical databases where data is stored on disk. RAM is more limited than disk, so cache invalidation algorithms such as least recently used (LRU) can help invalidate 'cold' entries and keep 'hot' data in RAM.
Redis has the following additional features:
There are multiple levels you can cache that fall into two general categories: database queries and objects:
Generally, you should try to avoid file-based caching, as it makes cloning and auto-scaling more difficult.
Whenever you query the database, hash the query as a key and store the result to the cache. This approach suffers from expiration issues:
See your data as an object, similar to what you do with your application code. Have your application assemble the dataset from the database into a class instance or a data structure(s):
Suggestions of what to cache:
Since you can only store a limited amount of data in cache, you'll need to determine which cache update strategy works best for your use case.
Source: From cache to in-memory data grid
The application is responsible for reading and writing from storage. The cache does not interact with storage directly. The application does the following:
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
Memcached is generally used in this manner.
Subsequent reads of data added to cache are fast. Cache-aside is also referred to as lazy loading. Only requested data is cached, which avoids filling up the cache with data that isn't requested.
Source: Scalability, availability, stability, patterns
The application uses the cache as the main data store, reading and writing data to it, while the cache is responsible for reading and writing to the database:
Application code:
set_user(12345, {"foo":"bar"})
Cache code:
def set_user(user_id, values):
user = db.query("UPDATE Users WHERE id = {0}", user_id, values)
cache.set(user_id, user)
Write-through is a slow overall operation due to the write operation, but subsequent reads of just written data are fast. Users are generally more tolerant of latency when updating data than reading data. Data in the cache is not stale.
Source: Scalability, availability, stability, patterns
In write-behind, the application does the following:
Source: From cache to in-memory data grid
You can configure the cache to automatically refresh any recently accessed cache entry prior to its expiration.
Refresh-ahead can result in reduced latency vs read-through if the cache can accurately predict which items are likely to be needed in the future.
Source: Intro to architecting systems for scale
Asynchronous workflows help reduce request times for expensive operations that would otherwise be performed in-line. They can also help by doing time-consuming work in advance, such as periodic aggregation of data.
Message queues receive, hold, and deliver messages. If an operation is too slow to perform inline, you can use a message queue with the following workflow:
The user is not blocked and the job is processed in the background. During this time, the client might optionally do a small amount of processing to make it seem like the task has completed. For example, if posting a tweet, the tweet could be instantly posted to your timeline, but it could take some time before your tweet is actually delivered to all of your followers.
Redis is useful as a simple message broker but messages can be lost.
RabbitMQ is popular but requires you to adapt to the 'AMQP' protocol and manage your own nodes.
Amazon SQS is hosted but can have high latency and has the possibility of messages being delivered twice.
Tasks queues receive tasks and their related data, runs them, then delivers their results. They can support scheduling and can be used to run computationally-intensive jobs in the background.
Celery has support for scheduling and primarily has python support.
If queues start to grow significantly, the queue size can become larger than memory, resulting in cache misses, disk reads, and even slower performance. Back pressure can help by limiting the queue size, thereby maintaining a high throughput rate and good response times for jobs already in the queue. Once the queue fills up, clients get a server busy or HTTP 503 status code to try again later. Clients can retry the request at a later time, perhaps with exponential backoff.
HTTP is a method for encoding and transporting data between a client and a server. It is a request/response protocol: clients issue requests and servers issue responses with relevant content and completion status info about the request. HTTP is self-contained, allowing requests and responses to flow through many intermediate routers and servers that perform load balancing, caching, encryption, and compression.
A basic HTTP request consists of a verb (method) and a resource (endpoint). Below are common HTTP verbs:
Verb | Description | Idempotent* | Safe | Cacheable |
---|---|---|---|---|
GET | Reads a resource | Yes | Yes | Yes |
POST | Creates a resource or trigger a process that handles data | No | No | Yes if response contains freshness info |
PUT | Creates or replace a resource | Yes | No | No |
PATCH | Partially updates a resource | No | No | Yes if response contains freshness info |
DELETE | Deletes a resource | Yes | No | No |
*Can be called many times without different outcomes.
HTTP is an application layer protocol relying on lower-level protocols such as TCP and UDP.
Source: How to make a multiplayer game
TCP is a connection-oriented protocol over an IP network. Connection is established and terminated using a handshake. All packets sent are guaranteed to reach the destination in the original order and without corruption through:
If the sender does not receive a correct response, it will resend the packets. If there are multiple timeouts, the connection is dropped. TCP also implements flow control and congestion control. These guarantees cause delays and generally result in less efficient transmission than UDP.
To ensure high throughput, web servers can keep a large number of TCP connections open, resulting in high memory usage. It can be expensive to have a large number of open connections between web server threads and say, a memcached server. Connection pooling can help in addition to switching to UDP where applicable.
TCP is useful for applications that require high reliability but are less time critical. Some examples include web servers, database info, SMTP, FTP, and SSH.
Use TCP over UDP when:
Source: How to make a multiplayer game
UDP is connectionless. Datagrams (analogous to packets) are guaranteed only at the datagram level. Datagrams might reach their destination out of order or not at all. UDP does not support congestion control. Without the guarantees that TCP support, UDP is generally more efficient.
UDP can broadcast, sending datagrams to all devices on the subnet. This is useful with DHCP because the client has not yet received an IP address, thus preventing a way for TCP to stream without the IP address.
UDP is less reliable but works well in real time use cases such as VoIP, video chat, streaming, and realtime multiplayer games.
Use UDP over TCP when:
Source: Crack the system design interview
In an RPC, a client causes a procedure to execute on a different address space, usually a remote server. The procedure is coded as if it were a local procedure call, abstracting away the details of how to communicate with the server from the client program. Remote calls are usually slower and less reliable than local calls so it is helpful to distinguish RPC calls from local calls. Popular RPC frameworks include Protobuf, Thrift, and Avro.
RPC is a request-response protocol:
Sample RPC calls:
GET /someoperation?data=anId POST /anotheroperation { "data":"anId"; "anotherdata": "another value" }
RPC is focused on exposing behaviors. RPCs are often used for performance reasons with internal communications, as you can hand-craft native calls to better fit your use cases.
Choose a native library (aka SDK) when:
HTTP APIs following REST tend to be used more often for public APIs.
REST is an architectural style enforcing a client/server model where the client acts on a set of resources managed by the server. The server provides a representation of resources and actions that can either manipulate or get a new representation of resources. All communication must be stateless and cacheable.
There are four qualities of a RESTful interface:
Sample REST calls:
GET /someresources/anId PUT /someresources/anId {"anotherdata": "another value"}
REST is focused on exposing data. It minimizes the coupling between client/server and is often used for public HTTP APIs. REST uses a more generic and uniform method of exposing resources through URIs, representation through headers, and actions through verbs such as GET, POST, PUT, DELETE, and PATCH. Being stateless, REST is great for horizontal scaling and partitioning.
Operation | RPC | REST |
---|---|---|
Signup | POST /signup | POST /persons |
Resign |
POST /resign { "personid": "1234" } |
DELETE /persons/1234 |
Read a person | GET /readPerson?personid=1234 | GET /persons/1234 |
Read a person’s items list | GET /readUsersItemsList?personid=1234 | GET /persons/1234/items |
Add an item to a person’s items |
POST /addItemToUsersItemsList { "personid": "1234"; "itemid": "456" } |
POST /persons/1234/items { "itemid": "456" } |
Update an item |
POST /modifyItem { "itemid": "456"; "key": "value" } |
PUT /items/456 { "key": "value" } |
Delete an item |
POST /removeItem { "itemid": "456" } |
DELETE /items/456 |
Source: Do you really know why you prefer REST over RPC
This section could use some updates. Consider contributing!
Security is a broad topic. Unless you have considerable experience, a security background, or are applying for a position that requires knowledge of security, you probably won't need to know more than the basics:
You'll sometimes be asked to do 'back-of-the-envelope' estimates. For example, you might need to determine how long it will take to generate 100 image thumbnails from disk or how much memory a data structure will take. The Powers of two table and Latency numbers every programmer should know are handy references.
Power Exact Value Approx Value Bytes --------------------------------------------------------------- 7 128 8 256 10 1024 1 thousand 1 KB 16 65,536 64 KB 20 1,048,576 1 million 1 MB 30 1,073,741,824 1 billion 1 GB 32 4,294,967,296 4 GB 40 1,099,511,627,776 1 trillion 1 TB
Latency Comparison Numbers -------------------------- L1 cache reference 0.5 ns Branch mispredict 5 ns L2 cache reference 7 ns 14x L1 cache Mutex lock/unlock 25 ns Main memory reference 100 ns 20x L2 cache, 200x L1 cache Compress 1K bytes with Zippy 10,000 ns 10 us Send 1 KB bytes over 1 Gbps network 10,000 ns 10 us Read 4 KB randomly from SSD* 150,000 ns 150 us ~1GB/sec SSD Read 1 MB sequentially from memory 250,000 ns 250 us Round trip within same datacenter 500,000 ns 500 us Read 1 MB sequentially from SSD* 1,000,000 ns 1,000 us 1 ms ~1GB/sec SSD, 4X memory HDD seek 10,000,000 ns 10,000 us 10 ms 20x datacenter roundtrip Read 1 MB sequentially from 1 Gbps 10,000,000 ns 10,000 us 10 ms 40x memory, 10X SSD Read 1 MB sequentially from HDD 30,000,000 ns 30,000 us 30 ms 120x memory, 30X SSD Send packet CA->Netherlands->CA 150,000,000 ns 150,000 us 150 ms Notes ----- 1 ns = 10^-9 seconds 1 us = 10^-6 seconds = 1,000 ns 1 ms = 10^-3 seconds = 1,000 us = 1,000,000 ns
Handy metrics based on numbers above:
Common system design interview questions, with links to resources on how to solve each.
Question | Reference(s) |
---|---|
Design a file sync service like Dropbox | youtube.com |
Design a search engine like Google |
queue.acm.org stackexchange.com ardendertat.com stanford.edu |
Design a scalable web crawler like Google | quora.com |
Design Google docs |
code.google.com neil.fraser.name |
Design a key-value store like Redis | slideshare.net |
Design a cache system like Memcached | slideshare.net |
Design a recommendation system like Amazon's |
hulu.com ijcai13.org |
Design a tinyurl system like Bitly | n00tc0d3r.blogspot.com |
Design a chat app like WhatsApp | highscalability.com |
Design a picture sharing system like Instagram |
highscalability.com highscalability.com |
Design the Facebook news feed function |
quora.com quora.com slideshare.net |
Design the Facebook timeline function |
facebook.com highscalability.com |
Design the Facebook chat function |
erlang-factory.com facebook.com |
Design a graph search function like Facebook's |
facebook.com facebook.com facebook.com |
Design a content delivery network like CloudFlare | figshare.com |
Design a trending topic system like Twitter's |
michael-noll.com snikolov .wordpress.com |
Design a random ID generation system |
blog.twitter.com github.com |
Return the top k requests during a time interval |
cs.ucsb.edu wpi.edu |
Design a system that serves data from multiple data centers | highscalability.com |
Design an online multiplayer card game |
indieflashblog.com buildnewgames.com |
Design a garbage collection system |
stuffwithstuff.com washington.edu |
Design an API rate limiter | https://stripe.com/blog/ |
Design a Stock Exchange (like NASDAQ or Binance) |
Jane Street Golang Implementation Go Implementation |
Add a system design question | Contribute |
Articles on how real world systems are designed.
Source: Twitter timelines at scale
Don't focus on nitty gritty details for the following articles, instead:
Type | System | Reference(s) |
---|---|---|
Data processing | MapReduce - Distributed data processing from Google | research.google.com |
Data processing | Spark - Distributed data processing from Databricks | slideshare.net |
Data processing | Storm - Distributed data processing from Twitter | slideshare.net |
Data store | Bigtable - Distributed column-oriented database from Google | harvard.edu |
Data store | HBase - Open source implementation of Bigtable | slideshare.net |
Data store | Cassandra - Distributed column-oriented database from Facebook | slideshare.net |
Data store | DynamoDB - Document-oriented database from Amazon | harvard.edu |
Data store | MongoDB - Document-oriented database | slideshare.net |
Data store | Spanner - Globally-distributed database from Google | research.google.com |
Data store | Memcached - Distributed memory caching system | slideshare.net |
Data store | Redis - Distributed memory caching system with persistence and value types | slideshare.net |
File system | Google File System (GFS) - Distributed file system | research.google.com |
File system | Hadoop File System (HDFS) - Open source implementation of GFS | apache.org |
Misc | Chubby - Lock service for loosely-coupled distributed systems from Google | research.google.com |
Misc | Dapper - Distributed systems tracing infrastructure | research.google.com |
Misc | Kafka - Pub/sub message queue from LinkedIn | slideshare.net |
Misc | Zookeeper - Centralized infrastructure and services enabling synchronization | slideshare.net |
Add an architecture | Contribute |
Architectures for companies you are interviewing with.
Questions you encounter might be from the same domain.
Looking to add a blog? To avoid duplicating work, consider adding your company blog to the following repo:
Interested in adding a section or helping complete one in-progress? Contribute!
クレジットとソースは、このリポジトリ全体で提供されます。
特別な感謝:
問題、質問、コメントについて話し合うために私に連絡してください。
私の連絡先情報は私のGitHubページにあります。
私はこのリポジトリのコードとリソースをオープンソースライセンスの下であなたに提供しています。これは私の個人的なリポジトリであるため、私のコードとリソースに対して受け取るライセンスは、私の雇用主(Facebook)ではなく、私からのものです。
Copyright 2017 Donne Martin Creative Commons Attribution 4.0 International License (CC BY 4.0) http://creativecommons.org/licenses/by/4.0/