diff --git a/.gitignore b/.gitignore index 200a617d78e..5ca2fa242d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # Byte-compiled / optimized / DLL files +*.epub __pycache__/ *.py[cod] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7dfb1c96657..eddc2684577 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -65,6 +65,7 @@ Translations to new languages are always welcome, especially if you can maintain * Invite friends to review if possible. If desired, feel free to invite friends to help your original translation by letting them fork your repo, then merging their PRs. * Add links to your translation at the top of every README*.md file. (For consistency, the link should be added in alphabetical order by ISO code, and the anchor text should be in the native language.) * When done, indicate on the PR that it's ready to be merged into the main repo. +* Once accepted, your PR will be squashed into a single commit into the `master` branch. ### Translation template credits diff --git a/LICENSE.txt b/LICENSE.txt index 81901d37c39..5a04d642d61 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,3 +1,9 @@ +I am providing code and resources in this repository to you under an open source +license. Because this is my personal repository, the license you receive to my +code and resources is from me and not my employer (Facebook). + +Copyright 2017 Donne Martin + Creative Commons Attribution 4.0 International License (CC BY 4.0) http://creativecommons.org/licenses/by/4.0/ diff --git a/README-ja.md b/README-ja.md new file mode 100644 index 00000000000..eba4d0349aa --- /dev/null +++ b/README-ja.md @@ -0,0 +1,1787 @@ +*[English](README.md) ∙ [日本語](README-ja.md) ∙ [简体中文](README-zh-Hans.md) ∙ [繁體中文](README-zh-TW.md) | [العَرَبِيَّة‎](https://github.com/donnemartin/system-design-primer/issues/170) ∙ [বাংলা](https://github.com/donnemartin/system-design-primer/issues/220) ∙ [Português do Brasil](https://github.com/donnemartin/system-design-primer/issues/40) ∙ [Deutsch](https://github.com/donnemartin/system-design-primer/issues/186) ∙ [ελληνικά](https://github.com/donnemartin/system-design-primer/issues/130) ∙ [עברית](https://github.com/donnemartin/system-design-primer/issues/272) ∙ [Italiano](https://github.com/donnemartin/system-design-primer/issues/104) ∙ [韓國語](https://github.com/donnemartin/system-design-primer/issues/102) ∙ [فارسی](https://github.com/donnemartin/system-design-primer/issues/110) ∙ [Polski](https://github.com/donnemartin/system-design-primer/issues/68) ∙ [русский язык](https://github.com/donnemartin/system-design-primer/issues/87) ∙ [Español](https://github.com/donnemartin/system-design-primer/issues/136) ∙ [ภาษาไทย](https://github.com/donnemartin/system-design-primer/issues/187) ∙ [Türkçe](https://github.com/donnemartin/system-design-primer/issues/39) ∙ [tiếng Việt](https://github.com/donnemartin/system-design-primer/issues/127) ∙ [Français](https://github.com/donnemartin/system-design-primer/issues/250) | [Add Translation](https://github.com/donnemartin/system-design-primer/issues/28)* + +# システム設計入門 + +

+ +
+

+ +## 動機・目的 + +> 大規模システムのシステム設計を学ぶ +> +> システム設計面接課題に備える + +### 大規模システムの設計を学ぶ + +スケーラブルなシステムのシステム設計を学ぶことは、より良いエンジニアになることに資するでしょう。 + +システム設計はとても広範なトピックを含みます。システム設計原理については **インターネット上には膨大な量の文献が散らばっています。** + +このリポジトリは大規模システム構築に必要な知識を学ぶことができる **文献リストを体系的にまとめたもの** です。 + +### オープンソースコミュニティから学ぶ + +このプロジェクトは、これからもずっと更新されていくオープンソースプロジェクトの初期段階にすぎません。 + +[Contributions](#contributing) は大歓迎です! + +### システム設計面接課題に備える + +コード技術面接に加えて、システム設計に関する知識は、多くのテック企業における **技術採用面接プロセス** で **必要不可欠な要素** です。 + +**システム設計面接での頻出質問に備え**、自分の解答と*模範解答*:ディスカッション、コードそして図表などを*比較*して学びましょう。 + +面接準備に役立つその他のトピック: + +* [学習指針](#学習指針) +* [システム設計面接課題にどのように準備するか](#システム設計面接にどのようにして臨めばいいか) +* [システム設計課題例 **とその解答**](#システム設計課題例とその解答) +* [オブジェクト指向設計課題例、 **とその解答**](#オブジェクト指向設計問題と解答) +* [その他のシステム設計面接課題例](#他のシステム設計面接例題) + +## 暗記カード + +

+ +
+

+ +この[Anki用フラッシュカードデッキ](https://apps.ankiweb.net/) は、間隔反復を活用して、システム設計のキーコンセプトの学習を支援します。 + +* [システム設計デッキ](resources/flash_cards/System%20Design.apkg) +* [システム設計練習課題デッキ](resources/flash_cards/System%20Design%20Exercises.apkg) +* [オブジェクト指向練習課題デッキ](resources/flash_cards/OO%20Design.apkg) + +外出先や移動中の勉強に役立つでしょう。 + +### コーディング技術課題用の問題: 練習用インタラクティブアプリケーション + +コード技術面接用の問題を探している場合は[**こちら**](https://github.com/donnemartin/interactive-coding-challenges) + +

+ +
+

+ +姉妹リポジトリの [**Interactive Coding Challenges**](https://github.com/donnemartin/interactive-coding-challenges)も見てみてください。追加の暗記デッキカードも入っています。 + +* [Coding deck](https://github.com/donnemartin/interactive-coding-challenges/tree/master/anki_cards/Coding.apkg) + +## コントリビュート + +> コミュニティから学ぶ + +プルリクエスト等の貢献は積極的にお願いします: + +* エラー修正 +* セクション内容改善 +* 新規セクション追加 +* [翻訳する](https://github.com/donnemartin/system-design-primer/issues/28) + +現在、内容の改善が必要な作業中のコンテンツは[こちら](#進行中の作業)です。 + +コントリビュートの前に[Contributing Guidelines](CONTRIBUTING.md)を読みましょう。 + +## システム設計目次 + +> 賛否も含めた様々なシステム設計の各トピックの概要。 **全てはトレードオフの関係にあります。** +> +> それぞれのセクションはより学びを深めるような他の文献へのリンクが貼られています。 + +

+ +
+

+ +* [システム設計トピック: まずはここから](#システム設計トピックス-まずはここから) + * [Step 1: スケーラビリティに関する動画を見る](#ステップ-1-スケーラビリティに関する動画を観て復習する) + * [Step 2: スケーラビリティに関する記事を読む](#ステップ-2-スケーラビリティに関する資料を読んで復習する) + * [次のステップ](#次のステップ) +* [パフォーマンス vs スケーラビリティ](#パフォーマンス-vs-スケーラビリティ) +* [レイテンシー vs スループット](#レイテンシー-vs-スループット) +* [可用性 vs 一貫性](#可用性-vs-一貫性) + * [CAP理論](#cap-理論) + * [CP - 一貫性(consistency)と分割性(partition)耐性](#cp---一貫性と分断耐性consistency-and-partition-tolerance) + * [AP - 可用性(availability)と分割性(partition)耐性](#ap---可用性と分断耐性availability-and-partition-tolerance) +* [一貫性 パターン](#一貫性パターン) + * [弱い一貫性](#弱い一貫性) + * [結果整合性](#結果整合性) + * [強い一貫性](#強い一貫性) +* [可用性 パターン](#可用性パターン) + * [フェイルオーバー](#フェイルオーバー) + * [レプリケーション](#レプリケーション) +* [ドメインネームシステム(DNS)](#ドメインネームシステム) +* [コンテンツデリバリーネットワーク(CDN)](#コンテンツデリバリーネットワークcontent-delivery-network) + * [プッシュCDN](#プッシュcdn) + * [プルCDN](#プルcdn) +* [ロードバランサー](#ロードバランサー) + * [アクティブ/パッシブ構成](#アクティブパッシブ) + * [アクティブ/アクティブ構成](#アクティブアクティブ) + * [Layer 4 ロードバランシング](#layer-4-ロードバランシング) + * [Layer 7 ロードバランシング](#layer-7-ロードバランシング) + * [水平スケーリング](#水平スケーリング) +* [リバースプロキシ (WEBサーバー)](#リバースプロキシwebサーバー) + * [ロードバランサー vs リバースプロキシ](#ロードバランサー-vs-リバースプロキシ) +* [アプリケーションレイヤー](#アプリケーション層) + * [マイクロサービス](#マイクロサービス) + * [サービスディスカバリー](#service-discovery) +* [データベース](#データベース) + * [リレーショナルデータベースマネジメントシステム (RDBMS)](#リレーショナルデータベースマネジメントシステム-rdbms) + * [マスター/スレーブ レプリケーション](#マスタースレーブ-レプリケーション) + * [マスター/マスター レプリケーション](#マスターマスター-レプリケーション) + * [フェデレーション](#federation) + * [シャーディング](#シャーディング) + * [デノーマライゼーション](#非正規化) + * [SQL チューニング](#sqlチューニング) + * [NoSQL](#nosql) + * [キー/バリューストア](#キーバリューストア) + * [ドキュメントストア](#ドキュメントストア) + * [ワイドカラムストア](#ワイドカラムストア) + * [グラフ データベース](#グラフデータベース) + * [SQL or NoSQL](#sqlかnosqlか) +* [キャッシュ](#キャッシュ) + * [クライアントキャッシング](#クライアントキャッシング) + * [CDNキャッシング](#cdnキャッシング) + * [Webサーバーキャッシング](#webサーバーキャッシング) + * [データベースキャッシング](#データベースキャッシング) + * [アプリケーションキャッシング](#アプリケーションキャッシング) + * [データベースクエリレベルでキャッシングする](#データベースクエリレベルでのキャッシング) + * [オブジェクトレベルでキャッシングする](#オブジェクトレベルでのキャッシング) + * [いつキャッシュを更新するのか](#いつキャッシュを更新するか) + * [キャッシュアサイド](#キャッシュアサイド) + * [ライトスルー](#ライトスルー) + * [ライトビハインド (ライトバック)](#ライトビハインド-ライトバック) + * [リフレッシュアヘッド](#リフレッシュアヘッド) +* [非同期処理](#非同期処理) + * [メッセージキュー](#メッセージキュー) + * [タスクキュー](#タスクキュー) + * [バックプレッシャー](#バックプレッシャー) +* [通信](#通信) + * [伝送制御プロトコル (TCP)](#伝送制御プロトコル-tcp) + * [ユーザデータグラムプロトコル (UDP)](#ユーザデータグラムプロトコル-udp) + * [遠隔手続呼出 (RPC)](#遠隔手続呼出-rpc) + * [Representational state transfer (REST)](#representational-state-transfer-rest) +* [セキュリティ](#セキュリティ) +* [補遺](#補遺) + * [2の乗数表](#2の乗数表) + * [全てのプログラマーが知るべきレイテンシー値](#全てのプログラマーが知るべきレイテンシー値) + * [他のシステム設計面接例題](#他のシステム設計面接例題) + * [実世界でのアーキテクチャ](#実世界のアーキテクチャ) + * [各企業のアーキテクチャ](#各企業のアーキテクチャ) + * [企業のエンジニアブログ](#企業のエンジニアブログ) +* [作業中](#進行中の作業) +* [クレジット](#クレジット) +* [連絡情報](#contact-info) +* [ライセンス](#license) + +## 学習指針 + +> 学習スパンに応じてみるべきトピックス (short, medium, long) + +![Imgur](http://i.imgur.com/OfVllex.png) + +**Q: 面接のためには、ここにあるものすべてをやらないといけないのでしょうか?** + +**A: いえ、ここにあるすべてをやる必要はありません。** + +面接で何を聞かれるかは以下の条件によって変わってきます: + +* どれだけの技術経験があるか +* あなたの技術背景が何であるか +* どのポジションのために面接を受けているか +* どの企業の面接を受けているか +* 運 + +より経験のある候補者は一般的にシステム設計についてより深い知識を有していることを要求されるでしょう。システムアーキテクトやチームリーダーは各メンバーの持つような知識よりは深い見識を持っているべきでしょう。一流テック企業では複数回の設計面接を課されることが多いです。 + +まずは広く始めて、そこからいくつかの分野に絞って深めていくのがいいでしょう。様々なシステム設計のトピックについて少しずつ知っておくことはいいことです。以下の学習ガイドを自分の学習に当てられる時間、技術経験、どの職位、どの会社に応募しているかなどを加味して自分用に調整して使うといいでしょう。 + +* **短期間** - **幅広く** システム設計トピックを学ぶ。**いくつかの** 面接課題を解くことで対策する。 +* **中期間** - **幅広く** そして **それなりに深く**システム設計トピックを学ぶ。**多くの** 面接課題を解くことで対策する。 +* **長期間** - **幅広く** そして **もっと深く**システム設計トピックを学ぶ。**ほぼ全ての** 面接課題を解くことで対策する。 + +| | 短期間 | 中期間 | 長期間 | +|---|---|---|---| +| [システム設計トピック](#システム設計目次) を読み、システム動作機序について広く知る | :+1: | :+1: | :+1: | +| 次のリンク先のいくつかのページを読んで [各企業のエンジニアリングブログ](#企業のエンジニアブログ) 応募する会社について知る | :+1: | :+1: | :+1: | +| 次のリンク先のいくつかのページを読む [実世界でのアーキテクチャ](#実世界のアーキテクチャ) | :+1: | :+1: | :+1: | +| 復習する [システム設計面接課題にどのように準備するか](#システム設計面接にどのようにして臨めばいいか) | :+1: | :+1: | :+1: | +| とりあえず一周する [システム設計課題例](#システム設計課題例とその解答) | Some | Many | Most | +| とりあえず一周する [オブジェクト指向設計問題と解答](#オブジェクト指向設計問題と解答) | Some | Many | Most | +| 復習する [その他システム設計面接での質問例](#他のシステム設計面接例題) | Some | Many | Most | + +## システム設計面接にどのようにして臨めばいいか + +> システム設計面接試験問題にどのように取り組むか + +システム設計面接は **open-ended conversation(Yes/Noでは答えられない口頭質問)です**。 自分で会話を組み立てることを求められます。 + +以下のステップに従って議論を組み立てることができるでしょう。この過程を確かなものにするために、次のセクション[システム設計課題例とその解答](#system-design-interview-questions-with-solutions) を以下の指針に従って読み込むといいでしょう。 + +### ステップ 1: そのシステム使用例の概要、制約、推計値等を聞き出し、まとめる + +システム仕様の要求事項を聞き出し、問題箇所を特定しましょう。使用例と制約を明確にするための質問を投げかけましょう。要求する推計値についても議論しておきましょう。 + +* 誰がそのサービスを使うのか? +* どのように使うのか? +* 何人のユーザーがいるのか? +* システムはどのような機能を果たすのか? +* システムへの入力と出力は? +* どれだけの容量のデータを捌く必要があるのか? +* 一秒間に何リクエストの送信が想定されるか? +* 読み書き比率の推定値はいくら程度か? + +### ステップ 2: より高レベルのシステム設計を組み立てる + +重要なコンポーネントを全て考慮した高レベルのシステム設計概要を組み立てる。 + +* 主要なコンポーネントと接続をスケッチして書き出す +* 考えの裏付けをする + +### ステップ 3: 核となるコンポーネントを設計する + +それぞれの主要なコンポーネントについての詳細を学ぶ。例えば、[url短縮サービス](solutions/system_design/pastebin/README.md)の設計を問われた際には次のようにするといいでしょう: + +* 元のURLのハッシュ化したものを作り、それを保存する + * [MD5](solutions/system_design/pastebin/README.md) と [Base62](solutions/system_design/pastebin/README.md) + * ハッシュ衝突 + * SQL もしくは NoSQL + * データベーススキーマ +* ハッシュ化されたURLを元のURLに再翻訳する + * データベース参照 +* API & オブジェクト指向の設計 + +### ステップ 4: システム設計のスケール + +与えられた制約条件からボトルネックとなりそうなところを割り出し、明確化する。 例えば、スケーラビリティの問題解決のために以下の要素を考慮する必要があるだろうか? + +* ロードバランサー +* 水平スケーリング +* キャッシング +* データベースシャーディング + +取りうる解決策とそのトレードオフについて議論をしよう。全てのことはトレードオフの関係にある。ボトルネックについては[スケーラブルなシステム設計の原理](#システム設計目次)を読むといいでしょう。 + +### ちょっとした暗算問題 + +ちょっとした推計値を手計算ですることを求められることもあるかもしれません。[補遺](#補遺)の以下の項目が役に立つでしょう: + +* [チラ裏計算でシステム設計する](http://highscalability.com/blog/2011/1/26/google-pro-tip-use-back-of-the-envelope-calculations-to-choo.html) +* [2の乗数表](#2の乗数表) +* [全てのプログラマーが知っておくべきレイテンシの参考値](#全てのプログラマーが知るべきレイテンシー値) + +### 文献とその他の参考資料 + +以下のリンク先ページを見てどのような質問を投げかけられるか概要を頭に入れておきましょう: + +* [システム設計面接で成功するには?](https://www.palantir.com/2011/10/how-to-rock-a-systems-design-interview/) +* [システム設計面接](http://www.hiredintech.com/system-design) +* [アーキテクチャ、システム設計面接への導入](https://www.youtube.com/watch?v=ZgdS0EUmn70) + +## システム設計課題例とその解答 + +> 頻出のシステム設計面接課題と参考解答、コード及びダイアグラム +> +> 解答は `solutions/` フォルダ以下にリンクが貼られている + +| 問題 | | +|---|---| +| Pastebin.com (もしくは Bit.ly) を設計する| [解答](solutions/system_design/pastebin/README.md) | +| Twitterタイムライン (もしくはFacebookフィード)を設計する
Twitter検索(もしくはFacebook検索)機能を設計する | [解答](solutions/system_design/twitter/README.md) | +| ウェブクローラーを設計する | [解答](solutions/system_design/web_crawler/README.md) | +| Mint.comを設計する | [解答](solutions/system_design/mint/README.md) | +| SNSサービスのデータ構造を設計する | [解答](solutions/system_design/social_graph/README.md) | +| 検索エンジンのキー/バリュー構造を設計する | [解答](solutions/system_design/query_cache/README.md) | +| Amazonのカテゴリ毎の売り上げランキングを設計する | [解答](solutions/system_design/sales_rank/README.md) | +| AWS上で100万人規模のユーザーを捌くサービスを設計する | [解答](solutions/system_design/scaling_aws/README.md) | +| システム設計問題を追加する | [Contribute](#contributing) | + +### Pastebin.com (もしくは Bit.ly) を設計する + +[問題と解答を見る](solutions/system_design/pastebin/README.md) + +![Imgur](http://i.imgur.com/4edXG0T.png) + +### Twitterタイムライン&検索 (もしくはFacebookフィード&検索)を設計する + +[問題と解答を見る](solutions/system_design/twitter/README.md) + +![Imgur](http://i.imgur.com/jrUBAF7.png) + +### ウェブクローラーの設計 + +[問題と解答を見る](solutions/system_design/web_crawler/README.md) + +![Imgur](http://i.imgur.com/bWxPtQA.png) + +### Mint.comの設計 + +[問題と解答を見る](solutions/system_design/mint/README.md) + +![Imgur](http://i.imgur.com/V5q57vU.png) + +### SNSサービスのデータ構造を設計する + +[問題と解答を見る](solutions/system_design/social_graph/README.md) + +![Imgur](http://i.imgur.com/cdCv5g7.png) + +### 検索エンジンのキー/バリュー構造を設計する + +[問題と解答を見る](solutions/system_design/query_cache/README.md) + +![Imgur](http://i.imgur.com/4j99mhe.png) + +### Amazonのカテゴリ毎の売り上げランキングを設計する + +[問題と解答を見る](solutions/system_design/sales_rank/README.md) + +![Imgur](http://i.imgur.com/MzExP06.png) + +### AWS上で100万人規模のユーザーを捌くサービスを設計する + +[問題と解答を見る](solutions/system_design/scaling_aws/README.md) + +![Imgur](http://i.imgur.com/jj3A5N8.png) + +## オブジェクト指向設計問題と解答 + +> 頻出のオブジェクト指向システム設計面接課題と参考解答、コード及びダイアグラム +> +> 解答は `solutions/` フォルダ以下にリンクが貼られている + +>**備考: このセクションは作業中です** + +| 問題 | | +|---|---| +| ハッシュマップの設計 | [解答](solutions/object_oriented_design/hash_table/hash_map.ipynb) | +| LRUキャッシュの設計 | [解答](solutions/object_oriented_design/lru_cache/lru_cache.ipynb) | +| コールセンターの設計 | [解答](solutions/object_oriented_design/call_center/call_center.ipynb) | +| カードのデッキの設計 | [解答](solutions/object_oriented_design/deck_of_cards/deck_of_cards.ipynb) | +| 駐車場の設計 | [解答](solutions/object_oriented_design/parking_lot/parking_lot.ipynb) | +| チャットサーバーの設計 | [解答](solutions/object_oriented_design/online_chat/online_chat.ipynb) | +| 円形配列の設計 | [Contribute](#contributing) | +| オブジェクト指向システム設計問題を追加する | [Contribute](#contributing) | + +## システム設計トピックス: まずはここから + +システム設計の勉強は初めて? + +まず初めに、よく使われる設計原理について、それらが何であるか、どのように用いられるか、長所短所について基本的な知識を得る必要があります + +### ステップ 1: スケーラビリティに関する動画を観て復習する + +[Harvardでのスケーラビリティの講義](https://www.youtube.com/watch?v=-W9F__D3oY4) + +* ここで触れられているトピックス: + * 垂直スケーリング + * 水平スケーリング + * キャッシング + * ロードバランシング + * データベースレプリケーション + * データベースパーティション + +### ステップ 2: スケーラビリティに関する資料を読んで復習する + +[スケーラビリティ](http://www.lecloud.net/tagged/scalability/chrono) + +* ここで触れられているトピックス: + * [クローン](http://www.lecloud.net/post/7295452622/scalability-for-dummies-part-1-clones) + * [データベース](http://www.lecloud.net/post/7994751381/scalability-for-dummies-part-2-database) + * [キャッシュ](http://www.lecloud.net/post/9246290032/scalability-for-dummies-part-3-cache) + * [非同期](http://www.lecloud.net/post/9699762917/scalability-for-dummies-part-4-asynchronism) + +### 次のステップ + +次に、ハイレベルでのトレードオフについてみていく: + +* **パフォーマンス** vs **スケーラビリティ** +* **レイテンシ** vs **スループット** +* **可用性** vs **一貫性** + +**全てはトレードオフの関係にある**というのを肝に命じておきましょう。 + +それから、より深い内容、DNSやCDNそしてロードバランサーなどについて学習を進めていきましょう。 + +## パフォーマンス vs スケーラビリティ + +リソースが追加されるのにつれて **パフォーマンス** が向上する場合そのサービスは **スケーラブル** であると言えるでしょう。一般的に、パフォーマンスを向上させるというのはすなわち計算処理を増やすことを意味しますが、データセットが増えた時などより大きな処理を捌けるようになることでもあります。1 + +パフォーマンスvsスケーラビリティをとらえる他の考え方: + +* **パフォーマンス** での問題を抱えている時、あなたのシステムは一人のユーザーにとって遅いと言えるでしょう。 +* **スケーラビリティ** での問題を抱えているとき、一人のユーザーにとっては速いですが、多くのリクエストがある時には遅くなってしまうでしょう。 + +### その他の参考資料、ページ + +* [スケーラビリティについて](http://www.allthingsdistributed.com/2006/03/a_word_on_scalability.html) +* [スケーラビリティ、可用性、安定性、パターン](http://www.slideshare.net/jboner/scalability-availability-stability-patterns/) + +## レイテンシー vs スループット + +**レイテンシー** とはなにがしかの動作を行う、もしくは結果を算出するのに要する時間 + +**スループット** とはそのような動作や結果算出が単位時間に行われる回数 + +一般的に、 **最大限のスループット** を **許容範囲内のレイテンシー** で実現することを目指すのが普通だ。 + +### その他の参考資料、ページ + +* [レイテンシー vs スループットを理解する](https://community.cadence.com/cadence_blogs_8/b/sd/archive/2010/09/13/understanding-latency-vs-throughput) + +## 可用性 vs 一貫性 + +### CAP 理論 + +

+ +
+ Source: CAP theorem revisited +

+ +分散型コンピュータシステムにおいては下の三つのうち二つまでしか同時に保証することはできない。: + +* **一貫性** - 全ての読み込みは最新の書き込みもしくはエラーを受け取る +* **可用性** - 受け取る情報が最新のものだという保証はないが、全てのリクエストはレスポンスを必ず受け取る +* **分断耐性** - ネットワーク問題によって順不同の分断が起きてもシステムが動作を続ける + +*ネットワークは信頼できないので、分断耐性は必ず保証しなければなりません。つまりソフトウェアシステムとしてのトレードオフは、一貫性を取るか、可用性を取るかを考えなければなりません。* + +#### CP - 一貫性と分断耐性(consistency and partition tolerance) + +分断されたノードからのレスポンスを待ち続けているとタイムアウトエラーに陥る可能性があります。CPはあなたのサービスがアトミックな読み書き(不可分操作)を必要とする際にはいい選択肢でしょう。 + +#### AP - 可用性と分断耐性(availability and partition tolerance) + +レスポンスはノード上にあるデータで最新のものを返します。つまり、最新版のデータが返されるとは限りません。分断が解消された後も、書き込みが反映されるのには時間がかかります。 + +[結果整合性](#結果整合性) を求めるサービスの際にはAPを採用するのがいいでしょう。もしくは、外部エラーに関わらずシステムが稼働する必要がある際にも同様です。 + +### その他の参考資料、ページ + +* [CAP 理論を振り返る](http://robertgreiner.com/2014/08/cap-theorem-revisited/) +* [平易な英語でのCAP 理論のイントロ](http://ksat.me/a-plain-english-introduction-to-cap-theorem/) +* [CAP FAQ](https://github.com/henryr/cap-faq) + +## 一貫性パターン + +同じデータの複製が複数ある状態では、クライアントが一貫したデータ表示を受け取るために、どのようにそれらを同期すればいいのかという課題があります。 [CAP 理論](#cap-理論) における一貫性の定義を思い出してみましょう。全ての読み取りは最新の書き込みデータもしくはエラーを受け取るはずです。 + +### 弱い一貫性 + +書き込み後の読み取りでは、その最新の書き込みを読めたり読めなかったりする。ベストエフォート型のアプローチに基づく。 + +このアプローチはmemcachedなどのシステムに見られます。弱い一貫性はリアルタイム性が必要なユースケース、例えばVoIP、ビデオチャット、リアルタイムマルチプレイヤーゲームなどと相性がいいでしょう。例えば、電話に出ているときに数秒間音声が受け取れなくなったとしたら、その後に接続が回復してもその接続が切断されていた間に話されていたことは聞き取れないというような感じです。 + +### 結果整合性 + +書き込みの後、読み取りは最終的にはその結果を読み取ることができる(ミリ秒ほど遅れてというのが一般的です)。データは非同期的に複製されます。 + +このアプローチはDNSやメールシステムなどに採用されています。結果整合性は多くのリクエストを捌くサービスと相性がいいでしょう。 + +### 強い一貫性 + +書き込みの後、読み取りはそれを必ず読むことができます。データは同期的に複製されます。 + +このアプローチはファイルシステムやRDBMSなどで採用されています。トランザクションを扱うサービスでは強い一貫性が必要でしょう。 + +### その他の参考資料、ページ + +* [データセンター間でのトランザクション](http://snarfed.org/transactions_across_datacenters_io.html) + +## 可用性パターン + +高い可用性を担保するには主に次の二つのパターンがあります: **フェイルオーバー** と **レプリケーション** です。 + +### フェイルオーバー + +#### アクティブ・パッシブ + +アクティブ・パッシブフェイルオーバーにおいては、周期信号はアクティブもしくはスタンバイ中のパッシブなサーバーに送られます。周期信号が中断された時には、パッシブだったサーバーがアクティブサーバーのIPアドレスを引き継いでサービスを再開します。 + +起動までのダウンタイムはパッシブサーバーが「ホット」なスタンバイ状態にあるか、「コールド」なスタンバイ状態にあるかで変わります。アクティブなサーバーのみがトラフィックを捌きます。 + +アクティブ・パッシブフェイルオーバーはマスター・スレーブフェイルオーバーと呼ばれることもあります。 + +#### アクティブ・アクティブ + +アクティブアクティブ構成では両方のサーバーがトラフィックを捌くことで負荷を分散します。 + +これらのサーバーがパブリックなものの場合、DNSは両方のサーバーのパブリックIPを知っている必要があります。もし、プライベートなものな場合、アプリケーションロジックが両方のサーバーの情報について知っている必要があります。 + +アクティブ・アクティブなフェイルオーバーはマスター・マスターフェイルオーバーと呼ばれることもあります。 + +### 短所: フェイルオーバー + +* フェイルオーバーではより多くのハードウェアを要し、複雑さが増します。 +* 最新の書き込みがパッシブサーバーに複製される前にアクティブが落ちると、データ欠損が起きる潜在可能性があります。 + +### レプリケーション + +#### マスター・スレーブ と マスター・マスター + +このトピックは [データベース](#データベース) セクションにおいてより詳細に解説されています: + +* [マスター・スレーブ レプリケーション](#マスタースレーブ-レプリケーション) +* [マスター・マスター レプリケーション](#マスターマスター-レプリケーション) + +## ドメインネームシステム + +

+ +
+ Source: DNS security presentation +

+ +ドメインネームシステム (DNS) は www.example.com などのドメインネームをIPアドレスへと翻訳します。 + +DNSは少数のオーソライズされたサーバーが上位に位置する階層的構造です。あなたのルーターもしくはISPは検索をする際にどのDNSサーバーに接続するかという情報を提供します。低い階層のDNSサーバーはその経路マップをキャッシュします。ただ、この情報は伝搬遅延によって陳腐化する可能性があります。DNSの結果はあなたのブラウザもしくはOSに一定期間([time to live (TTL)](https://en.wikipedia.org/wiki/Time_to_live)に設定された期間)キャッシュされます。 + +* **NS record (name server)** - あなたのドメイン・サブドメインでのDNSサーバーを特定します。 +* **MX record (mail exchange)** - メッセージを受け取るメールサーバーを特定します。 +* **A record (address)** - IPアドレスに名前をつけます。 +* **CNAME (canonical)** - 他の名前もしくは `CNAME` (example.com を www.example.com) もしくは `A` recordへと名前を指し示す。 + +[CloudFlare](https://www.cloudflare.com/dns/) や [Route 53](https://aws.amazon.com/route53/) などのサービスはマネージドDNSサービスを提供しています。いくつかのDNSサービスでは様々な手法を使ってトラフィックを捌くことができます: + +* [加重ラウンドロビン](http://g33kinfo.com/info/archives/2657) + * トラフィックがメンテナンス中のサーバーに行くのを防ぎます + * 様々なクラスターサイズに応じて調整します + * A/B テスト +* レイテンシーベース +* 地理ベース + +### 欠点: DNS + +* 上記で示されているようなキャッシングによって緩和されているとはいえ、DNSサーバーへの接続には少し遅延が生じる。 +* DNSサーバーは、[政府、ISP企業,そして大企業](http://superuser.com/questions/472695/who-controls-the-dns-servers/472729)に管理されているが、それらの管理は複雑である。 +* DNSサービスは[DDoS attack](http://dyn.com/blog/dyn-analysis-summary-of-friday-october-21-attack/)の例で、IPアドレスなしにユーザーがTwitterなどにアクセスできなくなったように、攻撃を受ける可能性がある。 + +### その他の参考資料、ページ + +* [DNS アーキテクチャ](https://technet.microsoft.com/en-us/library/dd197427(v=ws.10).aspx) +* [Wikipedia](https://en.wikipedia.org/wiki/Domain_Name_System) +* [DNS 記事](https://support.dnsimple.com/categories/dns/) + +## コンテンツデリバリーネットワーク(Content delivery network) + +

+ +
+ Source: Why use a CDN +

+ +コンテンツデリバリーネットワーク(CDN)は世界中に配置されたプロキシサーバーのネットワークがユーザーに一番地理的に近いサーバーからコンテンツを配信するシステムのことです。AmazonのCloudFrontなどは例外的にダイナミックなコンテンツも配信しますが、一般的に、HTML/CSS/JS、写真、そして動画などの静的ファイルがCDNを通じて配信されます。そのサイトのDNSがクライアントにどのサーバーと交信するかという情報を伝えます。 + +CDNを用いてコンテンツを配信することで以下の二つの理由でパフォーマンスが劇的に向上します: + +* ユーザーは近くにあるデータセンターから受信できる +* バックエンドサーバーはCDNが処理してくれるリクエストに関しては処理する必要がなくなります + +### プッシュCDN + +プッシュCDNではサーバーデータに更新があった時には必ず、新しいコンテンツを受け取る方式です。コンテンツを用意し、CDNに直接アップロードし、URLをCDNを指すように指定するところまで、全て自分で責任を負う形です。コンテンツがいつ期限切れになるのか更新されるのかを設定することができます。コンテンツは新規作成時、更新時のみアップロードされることでトラフィックは最小化される一方、ストレージは最大限消費されてしまいます。 + +トラフィックの少ない、もしくは頻繁にはコンテンツが更新されないサイトの場合にはプッシュCDNと相性がいいでしょう。コンテンツは定期的に再びプルされるのではなく、CDNに一度のみ配置されます。 + +### プルCDN + +プルCDNでは一人目のユーザーがリクエストした時に、新しいコンテンツをサービスのサーバーから取得します。コンテンツは自分のサーバーに保存して、CDNを指すURLを書き換えます。結果として、CDNにコンテンツがキャッシュされるまではリクエスト処理が遅くなります。 + +[time-to-live (TTL)](https://en.wikipedia.org/wiki/Time_to_live) はコンテンツがどれだけの期間キャッシュされるかを規定します。プルCDNはCDN 上でのストレージスペースを最小化しますが、有効期限が切れたファイルが更新前にプルされてしまうことで冗長なトラフィックに繋がってしまう可能性があります。 + +大規模なトラフィックのあるサイトではプルCDNが相性がいいでしょう。というのも、トラフィックの大部分は最近リクエストされ、CDNに残っているコンテンツにアクセスするものであることが多いからです。 + +### 欠点: CDN + +* CDNのコストはトラフィック量によって変わります。もちろん、CDNを使わない場合のコストと比較するべきでしょう。 +* TTLが切れる前にコンテンツが更新されると陳腐化する恐れがあります。 +* CDNでは静的コンテンツがCDNを指すようにURLを更新する必要があります。 + +### その他の参考資料、ページ + +* [グローバルに分散されたコンテンツデリバリーネットワーク](http://repository.cmu.edu/cgi/viewcontent.cgi?article=2112&context=compsci) +* [プッシュCDNとプルCDNの違い](http://www.travelblogadvice.com/technical/the-differences-between-push-and-pull-cdns/) +* [Wikipedia](https://en.wikipedia.org/wiki/Content_delivery_network) + +## ロードバランサー + +

+ +
+ Source: Scalable system design patterns +

+ +ロードバランサーは入力されるクライアントのリクエストをアプリケーションサーバーやデータベースへと分散させる。どのケースでもロードバランサーはサーバー等計算リソースからのレスポンスを適切なクライアントに返す。ロードバランサーは以下のことに効果的です: + +* リクエストが状態の良くないサーバーに行くのを防ぐ +* リクエストを過剰に送るのを防ぐ +* 特定箇所の欠陥でサービスが落ちることを防ぐ + +ロードバランサーは (費用の高い) ハードウェアもしくはHAProxyなどのソフトウェアで実現できる。 + +他の利点としては: + +* **SSL termination** - 入力されるリクエストを解読する、また、サーバーレスポンスを暗号化することでバックエンドのサーバーがこのコストが高くつきがちな処理を請け負わなくていいように肩代わりします。 + * [X.509 certificates](https://en.wikipedia.org/wiki/X.509) をそれぞれのサーバーにインストールする必要をなくします +* **セッション管理** - クッキーを取り扱うウェブアプリがセッション情報を保持していない時などに、特定のクライアントのリクエストを同じインスタンスへと流します。 + +障害に対応するために、[アクティブ・パッシブ](#アクティブパッシブ) もしくは [アクティブ・アクティブ](#アクティブアクティブ) モードのどちらにおいても、複数のロードバランサーを配置するのが一般的です。 + +ロードバランサーは以下のような種々のメトリックを用いてトラフィックルーティングを行うことができます: + +* ランダム +* Least loaded +* セッション/クッキー +* [ラウンドロビンもしくは加重ラウンドロビン](http://g33kinfo.com/info/archives/2657) +* [Layer 4](#layer-4-ロードバランシング) +* [Layer 7](#layer-7-ロードバランシング) + +### Layer 4 ロードバランシング + +Layer 4 ロードバランサーは [トランスポートレイヤー](#通信) を参照してどのようにリクエストを配分するか判断します。一般的に、トランスポートレイヤーとしては、ソース、送信先IPアドレス、ヘッダーに記述されたポート番号が含まれますが、パケットの中身のコンテンツは含みません。 Layer 4 ロードバランサーはネットワークパケットを上流サーバーへ届け、上流サーバーから配信することでネットワークアドレス変換 [Network Address Translation (NAT)](https://www.nginx.com/resources/glossary/layer-4-load-balancing/) を実現します。 + +### Layer 7 ロードバランシング + +Layer 7 ロードバランサーは [アプリケーションレイヤー](#通信) を参照してどのようにリクエストを配分するか判断します。ヘッダー、メッセージ、クッキーなどのコンテンツのことです。Layer 7 ロードバランサーはネットワークトラフィックの終端を受け持ち メッセージを読み込み、ロードバランシングの判断をし、選択したサーバーとの接続を繋ぎます。例えば layer 7 ロードバランサーは動画のトラフィックを直接、そのデータをホストしているサーバーにつなぐと同時に、決済処理などのより繊細なトラフィックをセキュリティ強化されたサーバーに流すということもできる。 + +柔軟性とのトレードオフになりますが、 layer 4 ロードバランサーではLayer 7ロードバランサーよりも所要時間、計算リソースを少なく済ませることができます。ただし、昨今の汎用ハードウェアではパフォーマンスは最小限のみしか発揮できないでしょう。 + +### 水平スケーリング + +ロードバランサーでは水平スケーリングによってパフォーマンスと可用性を向上させることができます。手頃な汎用マシンを追加することによってスケールアウトさせる方が、一つのサーバーをより高価なマシンにスケールアップする(**垂直スケーリング**)より費用対効果も高くなり、結果的に可用性も高くなります。また、汎用ハードウェアを扱える人材を雇う方が、特化型の商用ハードウェアを扱える人材を雇うよりも簡単でしょう。 + +#### 欠点: 水平スケーリング + +* 水平的にスケーリングしていくと、複雑さが増す上に、サーバーのクローニングが必要になる。 + * サーバーはステートレスである必要がある: ユーザーに関連するセッションや、プロフィール写真などのデータを持ってはいけない + * セッションは一元的な[データベース](#データベース) (SQL、 NoSQL)などのデータストアにストアされるか [キャッシュ](#キャッシュ) (Redis、 Memcached)に残す必要があります。 +* キャッシュやデータベースなどの下流サーバーは上流サーバーがスケールアウトするにつれてより多くの同時接続を保たなければなりません。 + +### 欠点: ロードバランサー + +* ロードバランサーはリソースが不足していたり、設定が適切でない場合、システム全体のボトルネックになる可能性があります。 +* 単一障害点を除こうとしてロードバランサーを導入した結果、複雑さが増してしまうことになります。 +* ロードバランサーが一つだけだとそこが単一障害点になってしまいます。一方で、ロードバランサーを複数にすると、さらに複雑さが増してしまいます。 + +### その他の参考資料、ページ + +* [NGINX アーキテクチャ](https://www.nginx.com/blog/inside-nginx-how-we-designed-for-performance-scale/) +* [HAProxy アーキテクチャガイド](http://www.haproxy.org/download/1.2/doc/architecture.txt) +* [スケーラビリティ](http://www.lecloud.net/post/7295452622/scalability-for-dummies-part-1-clones) +* [Wikipedia](https://en.wikipedia.org/wiki/Load_balancing_(computing)) +* [Layer 4 ロードバランシング](https://www.nginx.com/resources/glossary/layer-4-load-balancing/) +* [Layer 7 ロードバランシング](https://www.nginx.com/resources/glossary/layer-7-load-balancing/) +* [ELB listener config](http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-listener-config.html) + +## リバースプロキシ(webサーバー) + +

+ +
+ Source: Wikipedia +
+

+ +リバースプロキシサーバーは内部サービスをまとめて外部に統一されたインターフェースを提供するウェブサーバーです。クライアントからのリクエストはそれに対応するサーバーに送られて、その後レスポンスをリバースプロキシがクライアントに返します。 + +他には以下のような利点があります: + +* **より堅牢なセキュリティ** - バックエンドサーバーの情報を隠したり、IPアドレスをブラックリスト化したり、クライアントごとの接続数を制限したりできます。 +* **スケーラビリティや柔軟性が増します** - クライアントはリバースプロキシのIPしか見ないので、裏でサーバーをスケールしたり、設定を変えやすくなります。 +* **SSL termination** - 入力されるリクエストを解読し、サーバーのレスポンスを暗号化することでサーバーがこのコストのかかりうる処理をしなくて済むようになります。 + * [X.509 証明書](https://en.wikipedia.org/wiki/X.509) を各サーバーにインストールする必要がなくなります。 +* **圧縮** - サーバーレスポンスを圧縮できます +* **キャッシング** - キャッシュされたリクエストに対して、レスポンスを返します +* **静的コンテンツ** - 静的コンテンツを直接送信することができます。 + * HTML/CSS/JS + * 写真 + * 動画 + * などなど + +### ロードバランサー vs リバースプロキシ + +* 複数のサーバーがある時にはロードバランサーをデプロイすると役に立つでしょう。 しばしば、ロードバランサーは同じ機能を果たすサーバー群へのトラフィックを捌きます。 +* リバースプロキシでは、上記に述べたような利点を、単一のウェブサーバーやアプリケーションレイヤーに対しても示すことができます。 +* NGINX や HAProxy などの技術はlayer 7 リバースプロキシとロードバランサーの両方をサポートします。 + +### 欠点: リバースプロキシ + +* リバースプロキシを導入するとシステムの複雑性が増します。 +* 単一のリバースプロキシは単一障害点になりえます。一方で、複数のリバースプロキシを導入すると(例: [フェイルオーバー](https://en.wikipedia.org/wiki/Failover)) 複雑性はより増します。 + +### その他の参考資料、ページ + +* [リバースプロキシ vs ロードバランサー](https://www.nginx.com/resources/glossary/reverse-proxy-vs-load-balancer/) +* [NGINX アーキテクチャ](https://www.nginx.com/blog/inside-nginx-how-we-designed-for-performance-scale/) +* [HAProxy アーキテクチャ ガイド](http://www.haproxy.org/download/1.2/doc/architecture.txt) +* [Wikipedia](https://en.wikipedia.org/wiki/Reverse_proxy) + +## アプリケーション層 + +

+ +
+ Source: Intro to architecting systems for scale +

+ +ウェブレイヤーをアプリケーション層 (プラットフォーム層とも言われる) と分離することでそれぞれの層を独立にスケール、設定することができるようになります。新しいAPIをアプリケーション層に追加する際に、不必要にウェブサーバーを追加する必要がなくなります。 + + **単一責任の原則** では、小さい自律的なサービスが協調して動くように提唱しています。小さいサービスの小さいチームが急成長のためにより積極的な計画を立てられるようにするためです。 + +アプリケーション層は[非同期処理](#非同期処理)もサポートします。 + +### マイクロサービス + +独立してデプロイできる、小規模なモジュール様式である[マイクロサービス](https://en.wikipedia.org/wiki/Microservices)もこの議論に関係してくる技術でしょう。それぞれのサービスは独自のプロセスを処理し、明確で軽量なメカニズムで通信して、その目的とする機能を実現します。1 + +例えばPinterestでは以下のようなマイクロサービスに分かれています。ユーザープロフィール、フォロワー、フィード、検索、写真アップロードなどです。 + +### サービスディスカバリー + +[Consul](https://www.consul.io/docs/index.html)、 [Etcd](https://coreos.com/etcd/docs/latest)、 [Zookeeper](http://www.slideshare.net/sauravhaloi/introduction-to-apache-zookeeper) などのシステムでは、登録されているサービスの名前、アドレス、ポートの情報を監視することで、サービス同士が互いを見つけやすくしています。サービスの完全性の確認には [Health checks](https://www.consul.io/intro/getting-started/checks.html) が便利で、これには [HTTP](#hypertext-transfer-protocol-http) エンドポイントがよく使われます。 Consul と Etcd のいずれも組み込みの [key-value store](#キーバリューストア) を持っており、設定データや共有データなどのデータを保存しておくことに使われます。 + +### 欠点: アプリケーション層 + +* アーキテクチャ、運用、そしてプロセスを考慮すると、緩く結び付けられたアプリケーション層を追加するには、モノリシックなシステムとは異なるアプローチが必要です。 +* マイクロサービスはデプロイと運用の点から見ると複雑性が増すことになります。 + +### その他の参考資料、ページ + +* [スケールするシステムアーキテクチャを設計するためのイントロ](http://lethain.com/introduction-to-architecting-systems-for-scale) +* [システム設計インタビューを紐解く](http://www.puncsky.com/blog/2016-02-13-crack-the-system-design-interview) +* [サービス指向アーキテクチャ](https://en.wikipedia.org/wiki/Service-oriented_architecture) +* [Zookeeperのイントロダクション](http://www.slideshare.net/sauravhaloi/introduction-to-apache-zookeeper) +* [マイクロサービスを作るために知っておきたいこと](https://cloudncode.wordpress.com/2016/07/22/msa-getting-started/) + +## データベース + +

+ +
+ Source: Scaling up to your first 10 million users +

+ +### リレーショナルデータベースマネジメントシステム (RDBMS) + +SQLなどのリレーショナルデータベースはテーブルに整理されたデータの集合である。 + +**ACID** はリレーショナルデータベースにおける[トランザクション](https://en.wikipedia.org/wiki/Database_transaction)のプロパティの集合である + +* **不可分性** - それぞれのトランザクションはあるかないかのいずれかである +* **一貫性** - どんなトランザクションもデータベースをある確かな状態から次の状態に遷移させる。 +* **独立性** - 同時にトランザクションを処理することは、連続的にトランザクションを処理するのと同じ結果をもたらす。 +* **永続性** - トランザクションが処理されたら、そのように保存される + +リレーショナルデータベースをスケールさせるためにはたくさんの技術がある: **マスター・スレーブ レプリケーション**、 **マスター・マスター レプリケーション**、 **federation**、 **シャーディング**、 **非正規化**、 そして **SQL チューニング** + +#### マスタースレーブ レプリケーション + +マスターデータベースが読み取りと書き込みを処理し、書き込みを一つ以上のスレーブデータベースに複製します。スレーブデータベースは読み取りのみを処理します。スレーブデータベースは木構造のように追加のスレーブにデータを複製することもできます。マスターデータベースがオフラインになった場合には、いずれかのスレーブがマスターに昇格するか、新しいマスターデータベースが追加されるまでは読み取り専用モードで稼働します。 + +

+ +
+ Source: Scalability, availability, stability, patterns +

+ +##### 欠点: マスタースレーブ レプリケーション + +* スレーブをマスターに昇格させるには追加のロジックが必要になる。 +* マスタースレーブ レプリケーション、マスターマスター レプリケーションの **両方** の欠点は[欠点: レプリケーション](#欠点-マスタースレーブ-レプリケーション)を参照 + +#### マスターマスター レプリケーション + +いずれのマスターも読み取り書き込みの両方に対応する。書き込みに関してはそれぞれ協調する。いずれかのマスターが落ちても、システム全体としては読み書き両方に対応したまま運用できる。 + +

+ +
+ Source: Scalability, availability, stability, patterns +

+ +##### 欠点: マスターマスター レプリケーション + +* ロードバランサーを導入するか、アプリケーションロジックを変更することでどこに書き込むかを指定しなければならない。 +* 大体のマスターマスターシステムは、一貫性が緩い(ACID原理を守っていない)もしくは、同期する時間がかかるために書き込みのレイテンシーが増加してしまっている。 +* 書き込みノードが追加され、レイテンシーが増加するにつれ書き込みの衝突の可能性が増える。 +* マスタースレーブ レプリケーション、マスターマスター レプリケーションの **両方** の欠点は[欠点: レプリケーション](#欠点-マスタースレーブ-レプリケーション) を参照 + +##### 欠点: レプリケーション + +* 新しいデータ書き込みを複製する前にマスターが落ちた場合にはそのデータが失われてしまう可能性がある。 +* 書き込みは読み取りレプリカにおいてリプレイされる。書き込みが多い場合、複製ノードが書き込みの処理のみで行き詰まって、読み取りの処理を満足に行えない可能性がある。 +* 読み取りスレーブノードの数が多ければ多いほど、複製しなければならない数も増え、複製時間が伸びてしまいます。 +* システムによっては、マスターへの書き込みはマルチスレッドで並列処理できる一方、スレーブへの複製は単一スレッドで連続的に処理しなければならない場合があります。 +* レプリケーションでは追加のハードウェアが必要になり、複雑性も増します。 + +##### その他の参考資料、ページ: レプリケーション + +* [スケーラビリティ、 可用性、 スタビリティ パターン](http://www.slideshare.net/jboner/scalability-availability-stability-patterns/) +* [マルチマスター レプリケーション](https://en.wikipedia.org/wiki/Multi-master_replication) + +#### Federation + +

+ +
+ Source: Scaling up to your first 10 million users +

+ +フェデレーション (もしくは機能分割化とも言う) はデータベースを機能ごとに分割する。例えば、モノリシックな単一データベースの代わりに、データベースを **フォーラム**、 **ユーザー**、 **プロダクト** のように三つにすることで、データベース一つあたりの書き込み・読み取りのトラフィックが減り、その結果レプリケーションのラグも短くなります。データベースが小さくなることで、メモリーに収まるデータが増えます。キャッシュの局所性が高まるため、キャッシュヒット率も上がります。単一の中央マスターで書き込みを直列化したりしないため、並列で書き込みを処理することができ、スループットの向上が期待できます。 + +##### 欠点: federation + +* 大規模な処理やテーブルを要するスキーマの場合、フェデレーションは効果的とは言えないでしょう。 +* どのデータベースに読み書きをするのかを指定するアプリケーションロジックを更新しなければなりません。 +* [server link](http://stackoverflow.com/questions/5145637/querying-data-by-joining-two-tables-in-two-database-on-different-servers)で二つのデータベースからのデータを連結するのはより複雑になるでしょう。 +* フェデレーションでは追加のハードウェアが必要になり、複雑性も増します。 + +##### その他の参考資料、ページ: federation + +* [Scaling up to your first 10 million users](https://www.youtube.com/watch?v=w95murBkYmU) + +#### シャーディング + +

+ +
+ Source: Scalability, availability, stability, patterns +

+ +シャーディングでは異なるデータベースにそれぞれがデータのサブセット断片のみを持つようにデータを分割します。ユーザーデータベースを例にとると、ユーザー数が増えるにつれてクラスターにはより多くの断片が加えられることになります。 + +[federation](#federation)の利点に似ていて、シャーディングでは読み書きのトラフィックを減らし、レプリケーションを減らし、キャッシュヒットを増やすことができます。インデックスサイズも減らすことができます。一般的にはインデックスサイズを減らすと、パフォーマンスが向上しクエリ速度が速くなります。なにがしかのデータを複製する機能がなければデータロスにつながりますが、もし、一つのシャードが落ちても、他のシャードが動いていることになります。フェデレーションと同じく、単一の中央マスターが書き込みの処理をしなくても、並列で書き込みを処理することができ、スループットの向上が期待できます。 + +ユーザーテーブルをシャードする一般的な方法は、ユーザーのラストネームイニシャルでシャードするか、ユーザーの地理的配置でシャードするなどです。 + +##### 欠点: シャーディング + +* シャードに対応するようにアプリケーションロジックを変更しなければなりません。結果としてSQLクエリが複雑になります。 +* シャードではデータ配分がいびつになってしまう可能性があります。例えば、標準ユーザーの集合を持つシャードがある場合、そのシャードが他のシャードよりも重い負荷を負うことになります。 + * リバランシングをすると複雑性がより増します。[consistent hashing](http://www.paperplanes.de/2011/12/9/the-magic-of-consistent-hashing.html) に基づいたシャーディングでは、通信データを削減することもできます。 +* 複数のシャードからのデータを連結するのはより複雑です。 +* シャーディングでは追加のハードウェアが必要になり、複雑性も増します。 + +##### その他の参考資料、ページ: シャーディング + +* [シャードの登場](http://highscalability.com/blog/2009/8/6/an-unorthodox-approach-to-database-design-the-coming-of-the.html) +* [シャードデータベースアーキテクチャ](https://en.wikipedia.org/wiki/Shard_(database_architecture)) +* [Consistent hashing](http://www.paperplanes.de/2011/12/9/the-magic-of-consistent-hashing.html) + +#### 非正規化 + +非正規化では、書き込みのパフォーマンスをいくらか犠牲にして読み込みのパフォーマンスを向上させようとします。計算的に重いテーブルの結合などをせずに、複数のテーブルに冗長なデータのコピーが書き込まれるのを許容します。いくつかのRDBMS例えば、[PostgreSQL](https://en.wikipedia.org/wiki/PostgreSQL) やOracleはこの冗長な情報を取り扱い、一貫性を保つための[materialized views](https://en.wikipedia.org/wiki/Materialized_view) という機能をサポートしています。 + +[フェデレーション](#federation) や [シャーディング](#シャーディング)などのテクニックによってそれぞれのデータセンターに分配されたデータを合一させることはとても複雑な作業です。非正規化によってそのような複雑な処理をしなくて済むようになります。 + +多くのシステムで、100対1あるいは1000対1くらいになるくらい読み取りの方が、書き込みのトラフィックよりも多いことでしょう。読み込みを行うために、複雑なデータベースのジョイン処理が含まれるものは計算的に高価につきますし、ディスクの処理時間で膨大な時間を費消してしまうことになります。 + +##### 欠点: 非正規化 + +* データが複製される。 +* 冗長なデータの複製が同期されるように制約が存在し、そのことでデータベース全体の設計が複雑化する。 +* 非正規化されたデータベースは過大な書き込みを処理しなければならない場合、正規化されているそれよりもパフォーマンスにおいて劣る可能性がある。 + +###### その他の参考資料、ページ: 非正規化 + +* [Denormalization](https://en.wikipedia.org/wiki/Denormalization) + +#### SQLチューニング + +SQLチューニングは広範な知識を必要とする分野で多くの [本](https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=sql+tuning) が書かれています。 + +ボトルネックを明らかにし、シミュレートする上で、 **ベンチマーク** を定め、 **プロファイル** することはとても重要です。 + +* **ベンチマーク** - [ab](http://httpd.apache.org/docs/2.2/programs/ab.html)などのツールを用いて、高負荷の状況をシミュレーションしてみましょう。 +* **プロファイル** - [slow query log](http://dev.mysql.com/doc/refman/5.7/en/slow-query-log.html) などのツールを用いて、パフォーマンス状況の確認をしましょう。 + +ベンチマークとプロファイルをとることで以下のような効率化の選択肢をとることになるでしょう。 + +##### スキーマを絞る + +* より早い接続を得るために、連続したブロックの中のディスクにMySQLをダンプする。 +* 長さの決まったフィールドに対しては `VARCHAR` よりも `CHAR` を使うようにしましょう。 + * `CHAR` の方が効率的に速くランダムにデータにアクセスできます。 一方、 `VARCHAR` では次のデータに移る前にデータの末尾を検知しなければならないために速度が犠牲になります。 +* ブログ投稿などの大きなテキスト `TEXT` を使いましょう。 `TEXT` ではブーリアン型の検索も可能です。 `TEXT` フィールドを使うことは、テキストブロックを配置するのに用いたポインターをディスク上に保存することになります。 +* 2の32乗や40億を超えてくる数に関しては `INT` を使いましょう +* 通貨に関しては小数点表示上のエラーを避けるために `DECIMAL` を使いましょう。 +* 大きな `BLOBS` を保存するのは避けましょう。どこからそのオブジェクトを取ってくることができるかの情報を保存しましょう。 +* `VARCHAR(255)` は8ビットで数えることができる中で最大の文字数ですが、このフィールドがしばしばRDBMSの中で大きな容量を食います。 +* [検索性能を向上させる](http://stackoverflow.com/questions/1017239/how-do-null-values-affect-performance-in-a-database-search) ことが可能な箇所については `NOT NULL` 制約を設定しましょう + +##### インデックスを効果的に用いる + +* クエリ(`SELECT`、 `GROUP BY`、 `ORDER BY`、 `JOIN`) を用いて取得する列はインデックスを用いると速度を向上できる。 +* インデックスは通常、対数的にデータを検索、挿入、削除する際に用いる[B-tree](https://en.wikipedia.org/wiki/B-tree)として表現されています。 +* インデックスを配置することはデータをメモリーに残すことにつながりより容量を必要とします。 +* インデックスの更新も必要になるため書き込みも遅くなります。 +* 大きなデータを読み込む際には、インデックスを切ってからデータをロードして再びインデックスをビルドした方が速いことがあります。 + +##### 高負荷なジョインを避ける + +* パフォーマンスが必要なところには[非正規化](#非正規化)を適用する + +##### テーブルのパーティション + +* メモリー内に保つために、分離されたテーブルを分割してそれぞれにホットスポットを設定する。 + +##### クエリキャッシュを調整する + +* 場合によっては[クエリキャッシュ](http://dev.mysql.com/doc/refman/5.7/en/query-cache) が[パフォーマンス問題](https://www.percona.com/blog/2014/01/28/10-mysql-performance-tuning-settings-after-installation/) を引き起こす可能性がある + +##### その他の参考資料、ページ: SQLチューニング + +* [MySQLクエリを最適化するためのTips](http://20bits.com/article/10-tips-for-optimizing-mysql-queries-that-dont-suck) +* [VARCHAR(255)をそんなにたくさん使う必要ある?](http://stackoverflow.com/questions/1217466/is-there-a-good-reason-i-see-varchar255-used-so-often-as-opposed-to-another-l) +* [null値はどのようにパフォーマンスに影響するのか?](http://stackoverflow.com/questions/1017239/how-do-null-values-affect-performance-in-a-database-search) +* [Slow query log](http://dev.mysql.com/doc/refman/5.7/en/slow-query-log.html) + +### NoSQL + +NoSQL は **key-value store**、 **document-store**、 **wide column store**、 もしくは **graph database**によって表現されるデータアイテムの集合です。データは一般的に正規化されておらず、アプリケーション側でジョインが行われます。大部分のNoSQLは真のACIDトランザクションを持たず、 [結果整合性](#結果整合性) 的な振る舞いの方を好みます。 + +**BASE** はしばしばNoSQLデータベースのプロパティを説明するために用いられます。[CAP Theorem](#cap-理論) と対照的に、BASEは一貫性よりも可用性を優先します。 + +* **Basically available** - システムは可用性を保証します。 +* **Soft state** - システムの状態は入力がなくても時間経過とともに変化する可能性があります。 +* **結果整合性** - システム全体は時間経過とともにその間に入力がないという前提のもと、一貫性が達成されます。 + +[SQLか?NoSQLか?](#sqlかnosqlか) を選択するのに加えて、どのタイプのNoSQLがどの使用例に最も適するかを理解するのはとても有益です。このセクションでは **キーバリューストア**、 **ドキュメントストア**、 **ワイドカラムストア**、 と **グラフデータベース** について触れていきます。 + +#### キーバリューストア + +> 概要: ハッシュテーブル + +キーバリューストアでは一般的にO(1)の読み書きができ、それらはメモリないしSSDで裏付けられています。データストアはキーを [辞書的順序](https://en.wikipedia.org/wiki/Lexicographical_order) で保持することでキーの効率的な取得を可能にしています。キーバリューストアではメタデータを値とともに保持することが可能です。 + +キーバリューストアはハイパフォーマンスな挙動が可能で、単純なデータモデルやインメモリーキャッシュレイヤーなどのデータが急速に変わる場合などに使われます。単純な処理のみに機能が制限されているので、追加の処理機能が必要な場合にはその複雑性はアプリケーション層に載せることになります。 + +キーバリューストアはもっと複雑なドキュメントストアや、グラフデータベースなどの基本です。 + +##### その他の参考資料、ページ: キーバリューストア + +* [キーバリューデータベース](https://en.wikipedia.org/wiki/Key-value_database) +* [キーバリューストアの欠点](http://stackoverflow.com/questions/4056093/what-are-the-disadvantages-of-using-a-key-value-table-over-nullable-columns-or) +* [Redisアーキテクチャ](http://qnimate.com/overview-of-redis-architecture/) +* [メムキャッシュアーキテクチャ](https://www.adayinthelifeof.nl/2011/02/06/memcache-internals/) + +#### ドキュメントストア + +> 概要: ドキュメントがバリューとして保存されたキーバリューストア + +ドキュメントストアはオブジェクトに関する全ての情報を持つドキュメント(XML、 JSON、 binaryなど)を中心に据えたシステムです。ドキュメントストアでは、ドキュメント自身の内部構造に基づいた、APIもしくはクエリ言語を提供します。 *メモ:多くのキーバリューストアでは、値のメタデータを扱う機能を含んでいますが、そのことによって二つドキュメントストアとの境界線が曖昧になってしまっています。* + +以上のことを実現するために、ドキュメントはコレクション、タグ、メタデータやディレクトリなどとして整理されています。ドキュメント同士はまとめてグループにできるものの、それぞれで全く異なるフィールドを持つ可能性があります。 + +[MongoDB](https://www.mongodb.com/mongodb-architecture) や [CouchDB](https://blog.couchdb.org/2016/08/01/couchdb-2-0-architecture/) などのドキュメントストアも、複雑なクエリを処理するためのSQLのような言語を提供しています。[DynamoDB](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/decandia07dynamo.pdf) はキーバリューとドキュメントの両方をサポートしています。 + +ドキュメントストアは高い柔軟性を担保するので、頻繁に変化するデータを扱う時に用いられます。 + +##### その他の参考資料、ページ: ドキュメントストア + +* [ドキュメント指向 データベース](https://en.wikipedia.org/wiki/Document-oriented_database) +* [MongoDB アーキテクチャ](https://www.mongodb.com/mongodb-architecture) +* [CouchDB アーキテクチャ](https://blog.couchdb.org/2016/08/01/couchdb-2-0-architecture/) +* [Elasticsearch アーキテクチャ](https://www.elastic.co/blog/found-elasticsearch-from-the-bottom-up) + +#### ワイドカラムストア + +

+ +
+ Source: SQL & NoSQL, a brief history +

+ +> 概要: ネストされたマップ `カラムファミリー<行キー、 カラム>` + +ワイドカラムストアのデータの基本単位はカラム(ネーム・バリューのペア)です。それぞれのカラムはカラムファミリーとして(SQLテーブルのように)グループ化することができます。スーパーカラムファミリーはカラムファミリーの集合です。それぞれのカラムには行キーでアクセスすることができます。同じ行キーを持つカラムは同じ行として認識されます。それぞれの値は、バージョン管理とコンフリクトが起きた時のために、タイムスタンプを含みます。 + +Googleは[Bigtable](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/chang06bigtable.pdf)を初のワイドカラムストアとして発表しました。それがオープンソースでHadoopなどでよく使われる[HBase](https://www.mapr.com/blog/in-depth-look-hbase-architecture) やFacebookによる[Cassandra](http://docs.datastax.com/en/archived/cassandra/2.0/cassandra/architecture/architectureIntro_c.html) などのプロジェクトに影響を与えました。BigTable、HBaseやCassandraなどのストアはキーを辞書形式で保持することで選択したキーレンジでのデータ取得を効率的にします。 + +ワイドカラムストアは高い可用性とスケーラビリティを担保します。これらはとても大規模なデータセットを扱うことによく使われます。 + +##### その他の参考資料、ページ: ワイドカラムストア + +* [SQL & NoSQL簡単に歴史をさらう](http://blog.grio.com/2015/11/sql-nosql-a-brief-history.html) +* [Bigtable アーキテクチャ](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/chang06bigtable.pdf) +* [HBase アーキテクチャ](https://www.mapr.com/blog/in-depth-look-hbase-architecture) +* [Cassandra アーキテクチャ](http://docs.datastax.com/en/archived/cassandra/2.0/cassandra/architecture/architectureIntro_c.html) + +#### グラフデータベース + +

+ +
+ Source: Graph database +

+ +> 概要: グラフ + +グラフデータベースでは、それぞれのノードがレコードで、それぞれのアークは二つのノードを繋ぐ関係性として定義されます。グラフデータベースは多数の外部キーや多対多などの複雑な関係性を表すのに最適です。 + +グラフデータベースはSNSなどのサービスの複雑な関係性モデルなどについて高いパフォーマンスを発揮します。比較的新しく、まだ一般的には用いられていないので、開発ツールやリソースを探すのが他の方法に比べて難しいかもしれません。多くのグラフは[REST APIs](#representational-state-transfer-rest)を通じてのみアクセスできます。 + +##### その他の参考資料、ページ: グラフ + +* [Graphデータベース](https://en.wikipedia.org/wiki/Graph_database) +* [Neo4j](https://neo4j.com/) +* [FlockDB](https://blog.twitter.com/2010/introducing-flockdb) + +#### その他の参考資料、ページ: NoSQL + +* [基本用語の説明](http://stackoverflow.com/questions/3342497/explanation-of-base-terminology) +* [NoSQLデータベースについて調査と選択ガイド](https://medium.com/baqend-blog/nosql-databases-a-survey-and-decision-guidance-ea7823a822d#.wskogqenq) +* [スケーラビリティ](http://www.lecloud.net/post/7994751381/scalability-for-dummies-part-2-database) +* [NoSQLのイントロダクション](https://www.youtube.com/watch?v=qI_g07C_Q5I) +* [NoSQLパターン](http://horicky.blogspot.com/2009/11/nosql-patterns.html) + +### SQLか?NoSQLか? + +

+ +
+ Source: Transitioning from RDBMS to NoSQL +

+ +**SQL** を選ぶ理由: + +* 構造化されたデータ +* 厳格なスキーマ +* リレーショナルデータ +* 複雑なジョインをする必要性 +* トランザクション +* スケールする際のパターンが明確なとき +* 開発者の数、コミュニティ、コード等がより充実している +* インデックスによるデータ探索はとても速い + +**NoSQL** を選ぶ理由: + +* 準構造化されたデータ +* ダイナミックないし、フレキシブルなスキーマ +* ノンリレーショナルなデータ +* 複雑なジョインをする必要がない +* データの多くのTB (もしくは PB) を保存する +* 集中的、大規模なデータ負荷に耐えられる +* IOPSについては極めて高いスループットを示す + +NoSQLに適するサンプルデータ: + +* 急激なクリックストリームやログデータの収集 +* リーダーボードやスコアリングデータ +* ショッピングカートなどの一時的情報 +* 頻繁にアクセスされる ('ホットな') テーブル +* メタデータやルックアップテーブル + +##### その他の参考資料、ページ:  SQLもしくはNoSQL + +* [最初の1000万ユーザーにスケールアップするために](https://www.youtube.com/watch?v=w95murBkYmU) +* [SQLとNoSQLの違い](https://www.sitepoint.com/sql-vs-nosql-differences/) + +## キャッシュ + +

+ +
+ Source: Scalable system design patterns +

+ +キャッシュはページの読み込み時間を削減し、サーバーやデータベースへの負荷を低減することができます。このモデルでは、実際の処理を保存するために、ディスパッチャーがまず以前にリクエストが送信されたかどうかを確認し、直前の結果を受け取ります。 + +データベースはそのパーティションに渡って統合された読み取り書き込みの分配を要求しますが、人気アイテムはその分配を歪めてシステム全体のボトルネックになってしまうことがあります。データベースの前にキャッシュを差し込むことでこのように、均一でない負荷やトラフィックの急激な増加を吸収することができます。 + +### クライアントキャッシング + +キャッシュはOSやブラウザーなどのクライアントサイド、[サーバーサイド](#リバースプロキシwebサーバー) もしくは独立のキャッシュレイヤーに設置することができます。 + +### CDNキャッシング + +[CDN](#コンテンツデリバリーネットワークcontent-delivery-network) もキャッシュの一つとして考えることができます。 + +### Webサーバーキャッシング + +[リバースプロキシ](#リバースプロキシwebサーバー) や [Varnish](https://www.varnish-cache.org/) などのキャッシュは静的そして動的なコンテンツを直接配信することができます。 webサーバーもリクエストをキャッシュしてアプリケーションサーバーに接続することなしにレスポンスを返すことができます。 + +### データベースキャッシング + +データベースは普通、一般的な使用状況に適するようなキャッシングの設定を初期状態で持っています。この設定を特定の仕様に合わせて調整することでパフォーマンスを向上させることができます。 + +### アプリケーションキャッシング + +メムキャッシュなどのIn-memoryキャッシュやRedisはアプリケーションとデータストレージの間のキーバリューストアです。データはRAMで保持されるため、データがディスクで保存される一般的なデータベースよりもだいぶ速いです。RAM容量はディスクよりも限られているので、[least recently used (LRU)](https://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used)などの[cache invalidation](https://en.wikipedia.org/wiki/Cache_algorithms) アルゴリズムが 'コールド' なエントリを弾き、'ホット' なデータをRAMに保存します。 + +Redisはさらに以下のような機能を備えています: + +* パージステンス設定 +* ソート済みセット、リストなどの組み込みデータ構造 + +キャッシュには様々なレベルのものがありますが、いずれも大きく二つのカテゴリーのいずれかに分類することができます: **データベースクエリ** と **オブジェクト** です: + +* 行レベル +* クエリレベル +* Fully-formed serializable objects +* Fully-rendered HTML + +一般的に、ファイルベースキャッシングはクローンを作り出してオートスケーリングを難しくしてしまうので避けるべきです。 + +### データベースクエリレベルでのキャッシング + +データベースをクエリする際には必ずクエリをキーとしてハッシュして結果をキャッシュに保存しましょう。この手法はキャッシュ期限切れ問題に悩むことになります: + +* 複雑なクエリによりキャッシュされた結果を削除することが困難 +* テーブルセルなどのデータ断片が変化した時に、その変化したセルを含むかもしれない全てのキャッシュされたクエリを削除する必要がある。 + +### オブジェクトレベルでのキャッシング + +データをアプリケーションコードでそうするように、オブジェクトとして捉えてみましょう。アプリケーションに、データベースからのデータセットをクラスインスタンスやデータ構造として組み立てさせます。: + +* そのデータが変更されたら、オブジェクトをキャッシュから削除すること +* 非同期処理を許容します: ワーカーがキャッシュされたオブジェクトの中で最新のものを集めてきます + +何をキャッシュするか: + +* ユーザーのセッション +* 完全にレンダーされたウェブページ +* アクテビティストリーム +* ユーザーグラフデータ + +### いつキャッシュを更新するか + +キャッシュに保存できる容量は限られているため、自分のケースではどのキャッシュ手法が一番いいかは検討する必要があります。 + +#### キャッシュアサイド + +

+ +
+ Source: From cache to in-memory data grid +

+ +アプリケーションはストレージへの読み書きの処理をします。キャッシュはストレージとは直接やりとりをしません。アプリケーションは以下のことをします: + +* キャッシュの中のエントリを参照しますが、結果としてキャッシュミスになります +* データベースからエントリを取得します +* エントリをキャッシュに追加します +* エントリを返します + +```python +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](https://memcached.org/) は通常このように使われる。 + +その後のキャッシュデータ読み込みは速いです。キャッシュアサイドはレージーローディングであるとも言われます。リクエストされたデータのみがキャッシュされ、リクエストされていないデータでキャッシュが溢れるのを防止します。 + +##### 欠点: キャッシュアサイド + +* 各キャッシュミスは三つのトリップを呼び出すことになり、体感できるほどの遅延が起きてしまいます。 +* データベースのデータが更新されるとキャッシュデータは古いものになってしまいます。time-to-live (TTL)を設定することでキャッシュエントリの更新を強制的に行う、もしくはライトスルーを採用することでこの問題は緩和できます。 +* ノードが落ちると、新規の空のノードで代替されることでレイテンシーが増加することになります。 + +#### ライトスルー + +

+ +
+ Source: Scalability, availability, stability, patterns +

+ +アプリケーションはキャッシュをメインのデータストアとして使い、そこにデータの読み書きを行います。一方、キャッシュはデータベースへの読み書きを担当します。 + +* アプリケーションはキャッシュにあるエントリを追加・更新します +* キャッシュは同期的にデータストアに書き込みを行います +* エントリを返します + +アプリケーションコード: + +``` +set_user(12345, {"foo":"bar"}) +``` + +キャッシュコード: + +```python +def set_user(user_id, values): + user = db.query("UPDATE Users WHERE id = {0}", user_id, values) + cache.set(user_id, user) +``` + +ライトスルーは書き込み処理のせいで全体としては遅いオペレーションですが、書き込まれたばかりのデータに関する読み込みは速いです。ユーザー側は一般的にデータ更新時の方が読み込み時よりもレイテンシーに許容的です。キャッシュ内のデータは最新版で保たれます。 + +##### 欠点: ライトスルー + +* ノードが落ちたこと、もしくはスケーリングによって新しいノードが作成された時に、新しいノードはデータベース内のエントリーが更新されるまではエントリーをキャッシュしません。キャッシュアサイドとライトスルーを併用することでこの問題を緩和できます。 +* 書き込まれたデータの大部分は一度も読み込まれることはありません。このデータはTTLによって圧縮することができます。 + +#### ライトビハインド (ライトバック) + +

+ +
+ Source: Scalability, availability, stability, patterns +

+ +ライトビハインドではアプリケーションは以下のことをします: + +* キャッシュのエントリーを追加・更新します +* データストアへの書き込みを非同期的に行うことで、書き込みパフォーマンスを向上させます。 + +##### 欠点: ライトビハインド + +* キャッシュがデータストア内のコンテンツにヒットする前にキャッシュが落ちるとデータ欠損が起きる可能性があります。 +* キャッシュアサイドやライトスルーよりも実装が複雑になります。 + +#### リフレッシュアヘッド + +

+ +
+ Source: From cache to in-memory data grid +

+ +期限切れよりも前に、直近でアクセスされた全てのキャッシュエントリを自動的に更新するように設定することができます。 + +もしどのアイテムが将来必要になるのかを正確に予測することができるのならば、リードスルーよりもレイテンシーを削減することができます。 + +##### 欠点: リフレッシュアヘッド + +* どのアイテムが必要になるかの予測が正確でない場合にはリフレッシュアヘッドがない方がレイテンシーは良いという結果になってしまいます。 + +### 欠点: キャッシュ + +* [cache invalidation](https://en.wikipedia.org/wiki/Cache_algorithms)などを用いて、データベースなどの真のデータとキャッシュの間の一貫性を保つ必要があります。 +* Redisやmemcachedを追加することでアプリケーション構成を変更する必要があります。 +* Cache invalidationも難しいですがそれに加えて、いつキャッシュを更新するかという複雑な問題にも悩まされることになります。 + +### その他の参考資料、ページ + +* [From cache to in-memory data grid](http://www.slideshare.net/tmatyashovsky/from-cache-to-in-memory-data-grid-introduction-to-hazelcast) +* [スケーラブルなシステムデザインパターン](http://horicky.blogspot.com/2010/10/scalable-system-design-patterns.html) +* [スケールできるシステムを設計するためのイントロダクション](http://lethain.com/introduction-to-architecting-systems-for-scale/) +* [スケーラビリティ、可用性、安定性、パターン](http://www.slideshare.net/jboner/scalability-availability-stability-patterns/) +* [スケーラビリティ](http://www.lecloud.net/post/9246290032/scalability-for-dummies-part-3-cache) +* [AWS ElastiCacheのストラテジー](http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/Strategies.html) +* [Wikipedia](https://en.wikipedia.org/wiki/Cache_(computing)) + +## 非同期処理 + +

+ +
+ Source: Intro to architecting systems for scale +

+ +非同期のワークフローはもし、連続的に行われるとリクエスト時間を圧迫してしまうような重い処理を別で処理する手法です。また、定期的にデータを集合させるなどの時間がかかるような処理を前もって処理しておくことにも役立ちます。 + +### メッセージキュー + +メッセージキューはメッセージを受け取り、保存し、配信します。もし、処理がインラインで行うには遅すぎる場合、以下のようなワークフローでメッセージキューを用いるといいでしょう: + +* アプリケーションはジョブをキューに配信し、ユーザーにジョブステータスを伝えます。 +* ワーカーがジョブキューから受け取って、処理を行い、終了したらそのシグナルを返します。 + +ユーザーの処理が止まることはなく、ジョブはバックグラウンドで処理されます。この間に、クライアントはオプションとして、タスクが完了したかのように見せるために小規模の処理を行います。例えば、ツイートを投稿するときに、ツイートはすぐにあなたのタイムラインに反映されたように見えますが、そのツイートが実際に全てのフォロワーに配信されるまでにはもう少し時間がかかっているでしょう。 + +**Redis** はシンプルなメッセージ仲介としてはいいですが、メッセージが失われてしまう可能性があります。 + +**RabbitMQ** はよく使われていますが、'AMQP'プロトコルに対応して、自前のノードを立てる必要があります。 + +**Amazon SQS** という選択肢もありますが、レイテンシーが高く、メッセージが重複して配信されてしまう可能性があります。 + +### タスクキュー + +タスクキューはタスクとその関連するデータを受け取り、処理した上でその結果を返します。スケジュール管理をできるほか、バックグラウンドでとても重いジョブをこなすこともできます。 + +**Celery** はスケジューリングとpythonのサポートがあります。 + +### バックプレッシャー + +もし、キューが拡大しすぎると、メモリーよりもキューの方が大きくなりキャッシュミスが起こり、ディスク読み出しにつながり、パフォーマンスが低下することにつながります。[バックプレッシャー](http://mechanical-sympathy.blogspot.com/2012/05/apply-back-pressure-when-overloaded.html)はキューサイズを制限することで回避することができ、高いスループットを確保しキューにすでにあるジョブについてのレスポンス時間を短縮できます。キューがいっぱいになると、クライアントはサーバービジーもしくはHTTP 503をレスポンスとして受け取りまた後で時間をおいてアクセスするようにメッセージを受け取ります。クライアントは[exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff)などによって後ほど再度時間を置いてリクエストすることができます。 + +### 欠点: 非同期処理 + +* キューを用いることで遅延が起こり、複雑さも増すため、あまり重くない計算処理やリアルタイムワークフローにおいては同期処理の方がいいでしょう。 + +### その他の参考資料、ページ + +* [It's all a numbers game](https://www.youtube.com/watch?v=1KRYH75wgy4) +* [オーバーロードした時にバックプレッシャーを適用する](http://mechanical-sympathy.blogspot.com/2012/05/apply-back-pressure-when-overloaded.html) +* [Little's law](https://en.wikipedia.org/wiki/Little%27s_law) +* [メッセージキューとタスクキューの違いとは?](https://www.quora.com/What-is-the-difference-between-a-message-queue-and-a-task-queue-Why-would-a-task-queue-require-a-message-broker-like-RabbitMQ-Redis-Celery-or-IronMQ-to-function) + +## 通信 + +

+ +
+ Source: OSI 7 layer model +

+ +### Hypertext transfer protocol (HTTP) + +HTTP はクライアントとサーバー間でのデータをエンコードして転送するための手法です。リクエスト・レスポンスに関わるプロトコルです。クライアントがリクエストをサーバーに投げ、サーバーがリクエストに関係するコンテンツと完了ステータス情報をレスポンスとして返します。HTTPは自己完結するので、間にロードバランサー、キャッシュ、エンクリプション、圧縮などのどんな中間ルーターが入っても動くようにできています。 + +基本的なHTTPリクエストはHTTP動詞(メソッド)とリソース(エンドポイント)で成り立っています。以下がよくあるHTTP動詞です。: + +| 動詞 | 詳細 | 冪等性* | セーフ | キャッシュできるか | +|---|---|---|---|---| +| GET | リソースを読み取る | Yes | Yes | Yes | +| POST | リソースを作成するもしくはデータを処理するトリガー | No | No | Yes レスポンスが新しい情報を含む場合 | +| PUT | リソースを作成もしくは入れ替える | Yes | No | No | +| PATCH | リソースを部分的に更新する | No | No | Yes レスポンスが新しい情報を含む場合 | +| DELETE | リソースを削除する | Yes | No | No | + +*何度呼んでも同じ結果が返ってくること* + +HTTPは**TCP** や **UDP** などの低級プロトコルに依存しているアプリケーションレイヤーのプロトコルである。 + +#### その他の参考資料、ページ: HTTP + +* [HTTPってなに?](https://www.nginx.com/resources/glossary/http/) +* [HTTP と TCPの違い](https://www.quora.com/What-is-the-difference-between-HTTP-protocol-and-TCP-protocol) +* [PUT と PATCHの違い](https://laracasts.com/discuss/channels/general-discussion/whats-the-differences-between-put-and-patch?page=1) + +### 伝送制御プロトコル (TCP) + +

+ +
+ Source: How to make a multiplayer game +

+ +TCPは[IP network](https://en.wikipedia.org/wiki/Internet_Protocol)の上で成り立つ接続プロトコルです。接続は[handshake](https://en.wikipedia.org/wiki/Handshaking)によって開始、解除されます。全ての送信されたパケットは欠損なしで送信先に送信された順番で到達するように以下の方法で保証されています: + +* シーケンス番号と[checksum fields](https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Checksum_computation)が全てのパケットに用意されている +* [Acknowledgement](https://en.wikipedia.org/wiki/Acknowledgement_(data_networks))パケットと自動再送信 + +もし送信者が正しいレスポンスを受け取らなかったとき、パケットを再送信します。複数のタイムアウトがあったとき、接続は解除されます。TCP は[フロー制御](https://en.wikipedia.org/wiki/Flow_control_(data)) と [輻輳制御](https://en.wikipedia.org/wiki/Network_congestion#Congestion_control)も実装しています。これらの機能によって速度は低下し、一般的にUDPよりも非効率な転送手段になっています。 + +ハイスループットを実現するために、ウェブサーバーはかなり大きな数のTCP接続を開いておくことがあり、そのことでメモリー使用が圧迫されます。ウェブサーバスレッドと例えば[memcached](#memcached) サーバーの間で多数のコネクションを保っておくことは高くつくかもしれません。可能なところではUDPに切り替えるだけでなく[コネクションプーリング](https://en.wikipedia.org/wiki/Connection_pool)なども役立つかもしれません。 + +TCPは高い依存性を要し、時間制約が厳しくないものに適しているでしょう。ウェブサーバー、データベース情報、SMTP、FTPやSSHなどの例に適用されます。 + +以下の時にUDPよりもTCPを使うといいでしょう: + +* 全てのデータが欠損することなしに届いてほしい +* ネットワークスループットの最適な自動推測をしてオペレーションしたい + +### ユーザデータグラムプロトコル (UDP) + +

+ +
+ Source: How to make a multiplayer game +

+ +UDPはコネクションレスです。データグラム(パケットのようなもの)はデータグラムレベルでの保証しかされません。データグラムは順不同で受け取り先に到着したりそもそも着かなかったりします。UDPは輻輳制御をサポートしません。TCPにおいてはサポートされているこれらの保証がないため、UDPは一般的に、TCPよりも効率的です。 + +UDPはサブネット上のすべての機器にデータグラムを送信することができます。これは[DHCP](https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol) において役に立ちます。というのも、クライアントはまだIPアドレスを取得していないので、IPアドレスを必要とするTCPによるストリームができないからです。 + +UDPは信頼性の面では劣りますが、VoIP、ビデオチャット、ストリーミングや同時通信マルチプレイヤーゲームなどのリアルタイム性が重視される時にはとても効果的です。 + +TCPよりもUDPを使うのは: + +* レイテンシーを最低限に抑えたい時 +* データ欠損よりも、データ遅延を重視するとき +* エラー修正を自前で実装したいとき + +#### その他の参考資料、ページ: TCP と UDP + +* [ゲームプログラミングのためのネットワーク](http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/) +* [TCP と UDP プロトコルの主な違い](http://www.cyberciti.biz/faq/key-differences-between-tcp-and-udp-protocols/) +* [TCP と UDPの違い](http://stackoverflow.com/questions/5970383/difference-between-tcp-and-udp) +* [Transmission control protocol](https://en.wikipedia.org/wiki/Transmission_Control_Protocol) +* [User datagram protocol](https://en.wikipedia.org/wiki/User_Datagram_Protocol) +* [Facebookのメムキャッシュスケーリング](http://www.cs.bu.edu/~jappavoo/jappavoo.github.com/451/papers/memcache-fb.pdf) + +### 遠隔手続呼出 (RPC) + +

+ +
+ Source: Crack the system design interview +

+ +RPCではクライアントがリモートサーバーなどの異なるアドレス空間でプロシージャーが処理されるようにします。プロシージャーはローカルでのコールのように、クライアントからサーバーにどのように通信するかという詳細を省いた状態でコードが書かれます。リモートのコールは普通、ローカルのコールよりも遅く、信頼性に欠けるため、RPCコールをローカルコールと区別させておくことが好ましいでしょう。人気のRPCフレームワークは以下です。[Protobuf](https://developers.google.com/protocol-buffers/)、 [Thrift](https://thrift.apache.org/)、[Avro](https://avro.apache.org/docs/current/) + +RPC は リクエストレスポンスプロトコル: + +* **クライアントプログラム** - クライアントスタブプロシージャーを呼び出します。パラメータはローカルでのプロシージャーコールのようにスタックへとプッシュされていきます。 +* **クライアントスタブプロシージャー** - プロシージャIDとアーギュメントをパックしてリクエストメッセージにします。 +* **クライアント通信モジュール** - OSがクライアントからサーバーへとメッセージを送ります。 +* **サーバー通信モジュール** - OSが受け取ったパケットをサーバースタブプロシージャーに受け渡します。 +* **サーバースタブプロシージャー** - 結果を展開し、プロシージャーIDにマッチするサーバープロシージャーを呼び出し、結果を返します。 +* サーバーレスポンスは上記のステップを逆順で繰り返します。 + +Sample RPC calls: + +``` +GET /someoperation?data=anId + +POST /anotheroperation +{ + "data":"anId"; + "anotherdata": "another value" +} +``` + +RPCは振る舞いを公開することに焦点を当てています。RPCは内部通信パフォーマンスを理由として使われることが多いです。というのも、使用する状況に合わせてネイティブコールを自作することができるからです。 + +ネイティブライブラリー (aka SDK) を呼ぶのは以下の時: + +* ターゲットのプラットフォームを知っている時 +* ロジックがどのようにアクセスされるのかを管理したいとき +* ライブラリー外でエラーがどのようにコントロールされるかを管理したい時 +* パフォーマンスとエンドユーザーエクスペリエンスが最優先の時 + +**REST** プロトコルに従うHTTP APIはパブリックAPIにおいてよく用いられます。 + +#### 欠点: RPC + +* RPCクライアントとはサービス実装により厳密に左右されることになります。 +* 新しいオペレーション、使用例があるたびに新しくAPIが定義されなければなりません。 +* RPCをデバッグするのは難しい可能性があります。 +* 既存のテクノロジーをそのまま使ってサービスを構築することはできないかもしれません。例えば、[Squid](http://www.squid-cache.org/)などのサーバーに[RPCコールが正しくキャッシュ](http://etherealbits.com/2012/12/debunking-the-myths-of-rpc-rest/) されるように追加で骨を折る必要があるかもしれません。 + +### Representational state transfer (REST) + +RESTは、クライアントがサーバーによってマネージされるリソースに対して処理を行うクライアント・サーバーモデルを支持するアーキテキチャスタイルです。サーバーは操作できるもしくは新しいリソースレプレゼンテーションを受け取ることができるようなリソースやアクションのレプレゼンテーションを提供します。すべての通信はステートレスでキャッシュ可能でなければなりません。 + +RESTful なインターフェースには次の四つの特徴があります: + +* **特徴的なリソース (URI in HTTP)** - どのオペレーションであっても同じURIを使う。 +* **HTTP動詞によって変わる (Verbs in HTTP)** - 動詞、ヘッダー、ボディを使う +* **自己説明的なエラーメッセージ (status response in HTTP)** - ステータスコードを使い、新しく作ったりしないこと。 +* **[HATEOAS](http://restcookbook.com/Basics/hateoas/) (HTML interface for HTTP)** - 自分のwebサービスがブラウザで完全にアクセスできること。 + +サンプル REST コール: + +``` +GET /someresources/anId + +PUT /someresources/anId +{"anotherdata": "another value"} +``` + +RESTはデータを公開することに焦点を当てています。クライアントとサーバーのカップリングを最小限にするもので、パブリックAPIなどによく用いられます。RESTはURI、 [representation through headers](https://github.com/for-GET/know-your-http-well/blob/master/headers.md)、そして、GET、POST、PUT、 DELETE、PATCHなどのHTTP動詞等のよりジェネリックで統一されたメソッドを用います。ステートレスであるのでRESTは水平スケーリングやパーティショニングに最適です。 + +#### 欠点: REST + +* RESTはデータ公開に焦点を当てているので、リソースが自然に整理されていなかったり、シンプルなヒエラルキーで表せられない時にはよい選択肢とは言えないかもしれません。例えば、とあるイベントのセットにマッチするすべての更新情報を返すと言った処理は簡単にはパスで表現することができません。RESTでは、URIパス、クエリパラメータ、そして場合によってはリクエストボディなどによって実装されることが多いでしょう。 +* RESTは少数の動詞に依存しています(GET、POST、PUT、DELETE、そして PATCH) が時には使いたい事例に合わないことがあります。例えば、期限の切れたドキュメントをアーカイブに移したい場合などはこれらの動詞の中には綺麗にはフィットしません。 +* ネストされたヒエラルキーの中にあるリソースをとってくるのはシングルビューを描画するのにクライアントとサーバー間で数回やりとりしなければなりません。例として、ブログエントリーのコンテンツとそれに対するコメントを表示する場合などです。様々なネットワーク環境で動作する可能性が考えられるモバイルアプリケーションにおいてはこのような複数のやり取りは好ましくありません。 +* 時が経つにつれて、APIレスポンスにより多くのフィールドが与えられて、古いクライアントはすでにいらないものも含めてすべてのデータフィールドを受け取ることになります。そのことで、ペイロードが大きくなりすぎて、レイテンシーも拡大することになります。 + +### RPCとREST比較 + +| Operation | RPC | REST | +|---|---|---| +| サインアップ | **POST** /signup | **POST** /persons | +| リザイン | **POST** /resign
{
"personid": "1234"
} | **DELETE** /persons/1234 | +| Person読み込み | **GET** /readPerson?personid=1234 | **GET** /persons/1234 | +| Personのアイテムリスト読み込み | **GET** /readUsersItemsList?personid=1234 | **GET** /persons/1234/items | +| Personのアイテムへのアイテム追加 | **POST** /addItemToUsersItemsList
{
"personid": "1234";
"itemid": "456"
} | **POST** /persons/1234/items
{
"itemid": "456"
} | +| アイテム更新 | **POST** /modifyItem
{
"itemid": "456";
"key": "value"
} | **PUT** /items/456
{
"key": "value"
} | +| アイテム削除 | **POST** /removeItem
{
"itemid": "456"
} | **DELETE** /items/456 | + +

+ Source: Do you really know why you prefer REST over RPC +

+ +#### その他の参考資料、ページ: REST と RPC + +* [Do you really know why you prefer REST over RPC](https://apihandyman.io/do-you-really-know-why-you-prefer-rest-over-rpc/) +* [When are RPC-ish approaches more appropriate than REST?](http://programmers.stackexchange.com/a/181186) +* [REST vs JSON-RPC](http://stackoverflow.com/questions/15056878/rest-vs-json-rpc) +* [Debunking the myths of RPC and REST](http://etherealbits.com/2012/12/debunking-the-myths-of-rpc-rest/) +* [What are the drawbacks of using REST](https://www.quora.com/What-are-the-drawbacks-of-using-RESTful-APIs) +* [Crack the system design interview](http://www.puncsky.com/blog/2016-02-13-crack-the-system-design-interview) +* [Thrift](https://code.facebook.com/posts/1468950976659943/) +* [Why REST for internal use and not RPC](http://arstechnica.com/civis/viewtopic.php?t=1190508) + +## セキュリティ + +このセクションは更新が必要です。[contributing](#contributing)してください! + +セキュリティは幅広いトピックです。十分な経験、セキュリティ分野のバックグラウンドがなくても、セキュリティの知識を要する職に応募するのでない限り、基本以上のことを知る必要はないでしょう。 + +* 情報伝達、保存における暗号化 +* [XSS](https://en.wikipedia.org/wiki/Cross-site_scripting) や [SQL injection](https://en.wikipedia.org/wiki/SQL_injection)を防ぐために、全てのユーザー入力もしくはユーザーに露出される入力パラメーターをサニタイズする +* SQL injectionを防ぐためにパラメータ化されたクエリを用いる。 +* [least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege)の原理を用いる + +### その他の参考資料、ページ: + +* [開発者のためのセキュリティガイド](https://github.com/FallibleInc/security-guide-for-developers) +* [OWASP top ten](https://www.owasp.org/index.php/OWASP_Top_Ten_Cheat_Sheet) + +## 補遺 + +暗算で、推計値を求める必要があることも時にはあります。例えば、ディスクから100枚イメージ分のサムネイルを作る時間を求めたり、その時にどれだけディスクメモリーが消費されるかなどの値です。**2の乗数表** と **全てのプログラマーが知るべきレイテンシー値** は良い参考になるでしょう。 + +### 2の乗数表 + +``` +乗数 厳密な値 約 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 +``` + +#### その他の参考資料、ページ: + +* [2の乗数表](https://en.wikipedia.org/wiki/Power_of_two) + +### 全てのプログラマーが知るべきレイテンシー値 + +``` +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 +Disk 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 disk 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 +``` + +上記表に基づいた役に立つ数値: + +* ディスクからの連続読み取り速度 30 MB/s +* 1 Gbps Ethernetからの連続読み取り速度 100 MB/s +* SSDからの連続読み取り速度 1 GB/s +* main memoryからの連続読み取り速度 4 GB/s +* 1秒で地球6-7周できる +* 1秒でデータセンターと2000周やりとりできる + +#### レイテンシーの視覚的表 + +![](https://camo.githubusercontent.com/77f72259e1eb58596b564d1ad823af1853bc60a3/687474703a2f2f692e696d6775722e636f6d2f6b307431652e706e67) + +#### その他の参考資料、ページ: + +* [全てのプログラマーが知るべきレイテンシー値 - 1](https://gist.github.com/jboner/2841832) +* [全てのプログラマーが知るべきレイテンシー値 - 2](https://gist.github.com/hellerbarde/2843375) +* [Designs, lessons, and advice from building large distributed systems](http://www.cs.cornell.edu/projects/ladis2009/talks/dean-keynote-ladis2009.pdf) +* [Software Engineering Advice from Building Large-Scale Distributed Systems](https://static.googleusercontent.com/media/research.google.com/en//people/jeff/stanford-295-talk.pdf) + +### 他のシステム設計面接例題 + +> 頻出のシステム設計面接課題とその解答へのリンク + +| 質問 | 解答 | +|---|---| +| Dropboxのようなファイル同期サービスを設計する | [youtube.com](https://www.youtube.com/watch?v=PE4gwstWhmc) | +| Googleのような検索エンジンの設計 | [queue.acm.org](http://queue.acm.org/detail.cfm?id=988407)
[stackexchange.com](http://programmers.stackexchange.com/questions/38324/interview-question-how-would-you-implement-google-search)
[ardendertat.com](http://www.ardendertat.com/2012/01/11/implementing-search-engines/)
[stanford.edu](http://infolab.stanford.edu/~backrub/google.html) | +| Googleのようなスケーラブルなwebクローラーの設計 | [quora.com](https://www.quora.com/How-can-I-build-a-web-crawler-from-scratch) | +| Google docsの設計 | [code.google.com](https://code.google.com/p/google-mobwrite/)
[neil.fraser.name](https://neil.fraser.name/writing/sync/) | +| Redisのようなキーバリューストアの設計 | [slideshare.net](http://www.slideshare.net/dvirsky/introduction-to-redis) | +| Memcachedのようなキャッシュシステムの設計 | [slideshare.net](http://www.slideshare.net/oemebamo/introduction-to-memcached) | +| Amazonのようなレコメンデーションシステムの設計 | [hulu.com](http://tech.hulu.com/blog/2011/09/19/recommendation-system.html)
[ijcai13.org](http://ijcai13.org/files/tutorial_slides/td3.pdf) | +| BitlyのようなURL短縮サービスの設計 | [n00tc0d3r.blogspot.com](http://n00tc0d3r.blogspot.com/) | +| WhatsAppのようなチャットアプリの設計 | [highscalability.com](http://highscalability.com/blog/2014/2/26/the-whatsapp-architecture-facebook-bought-for-19-billion.html) +| Instagramのような写真共有サービスの設計 | [highscalability.com](http://highscalability.com/flickr-architecture)
[highscalability.com](http://highscalability.com/blog/2011/12/6/instagram-architecture-14-million-users-terabytes-of-photos.html) | +| Facebookニュースフィードの設計 | [quora.com](http://www.quora.com/What-are-best-practices-for-building-something-like-a-News-Feed)
[quora.com](http://www.quora.com/Activity-Streams/What-are-the-scaling-issues-to-keep-in-mind-while-developing-a-social-network-feed)
[slideshare.net](http://www.slideshare.net/danmckinley/etsy-activity-feeds-architecture) | +| Facebookタイムラインの設計 | [facebook.com](https://www.facebook.com/note.php?note_id=10150468255628920)
[highscalability.com](http://highscalability.com/blog/2012/1/23/facebook-timeline-brought-to-you-by-the-power-of-denormaliza.html) | +| Facebookチャットの設計 | [erlang-factory.com](http://www.erlang-factory.com/upload/presentations/31/EugeneLetuchy-ErlangatFacebook.pdf)
[facebook.com](https://www.facebook.com/note.php?note_id=14218138919&id=9445547199&index=0) | +| Facebookのようなgraph検索の設計 | [facebook.com](https://www.facebook.com/notes/facebook-engineering/under-the-hood-building-out-the-infrastructure-for-graph-search/10151347573598920)
[facebook.com](https://www.facebook.com/notes/facebook-engineering/under-the-hood-indexing-and-ranking-in-graph-search/10151361720763920)
[facebook.com](https://www.facebook.com/notes/facebook-engineering/under-the-hood-the-natural-language-interface-of-graph-search/10151432733048920) | +| CloudFlareのようなCDNの設計 | [cmu.edu](http://repository.cmu.edu/cgi/viewcontent.cgi?article=2112&context=compsci) | +| Twitterのトレンド機能の設計 | [michael-noll.com](http://www.michael-noll.com/blog/2013/01/18/implementing-real-time-trending-topics-in-storm/)
[snikolov .wordpress.com](http://snikolov.wordpress.com/2012/11/14/early-detection-of-twitter-trends/) | +| ランダムID発行システムの設計 | [blog.twitter.com](https://blog.twitter.com/2010/announcing-snowflake)
[github.com](https://github.com/twitter/snowflake/) | +| 一定のインターバル時間での上位k件を返す | [ucsb.edu](https://icmi.cs.ucsb.edu/research/tech_reports/reports/2005-23.pdf)
[wpi.edu](http://davis.wpi.edu/xmdv/docs/EDBT11-diyang.pdf) | +| 複数のデータセンターからデータを配信するサービスの設計 | [highscalability.com](http://highscalability.com/blog/2009/8/24/how-google-serves-data-from-multiple-datacenters.html) | +| オンラインの複数プレイヤーカードゲームの設計 | [indieflashblog.com](http://www.indieflashblog.com/how-to-create-an-asynchronous-multiplayer-game.html)
[buildnewgames.com](http://buildnewgames.com/real-time-multiplayer/) | +| ガーベッジコレクションシステムの設計 | [stuffwithstuff.com](http://journal.stuffwithstuff.com/2013/12/08/babys-first-garbage-collector/)
[washington.edu](http://courses.cs.washington.edu/courses/csep521/07wi/prj/rick.pdf) | +| システム設計例題を追加する | [Contribute](#contributing) | + +### 実世界のアーキテクチャ + +> 世の中のシステムがどのように設計されているかについての記事 + +

+ +
+ Source: Twitter timelines at scale +

+ +**以下の記事の重箱の隅をつつくような細かい詳細にこだわらないこと。むしろ** + +* 共通の原理、技術、パターンを探ること +* それぞれのコンポーネントでどんな問題が解決され、コンポーネントはどこでうまく使えもしくは使えないかを知ること +* 学んだことを復習すること + +|種類 | システム | 参考ページ | +|---|---|---| +| データ処理 | **MapReduce** - Googleの分散データ処理システム | [research.google.com](http://static.googleusercontent.com/media/research.google.com/zh-CN/us/archive/mapreduce-osdi04.pdf) | +| データ処理 | **Spark** - Databricksの分散データ処理システム | [slideshare.net](http://www.slideshare.net/AGrishchenko/apache-spark-architecture) | +| データ処理 | **Storm** - Twitterの分散データ処理システム | [slideshare.net](http://www.slideshare.net/previa/storm-16094009) | +| | | | +| データストア | **Bigtable** - Googleのカラム指向分散データベース | [harvard.edu](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/chang06bigtable.pdf) | +| データストア | **HBase** - Bigtableのオープンソース実装 | [slideshare.net](http://www.slideshare.net/alexbaranau/intro-to-hbase) | +| データストア | **Cassandra** - Facebookのカラム指向分散データベース | [slideshare.net](http://www.slideshare.net/planetcassandra/cassandra-introduction-features-30103666) +| データストア | **DynamoDB** - Amazonのドキュメント指向分散データベース | [harvard.edu](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/decandia07dynamo.pdf) | +| データストア | **MongoDB** - ドキュメント指向分散データベース | [slideshare.net](http://www.slideshare.net/mdirolf/introduction-to-mongodb) | +| データストア | **Spanner** - Googleのグローバル分散データベース | [research.google.com](http://research.google.com/archive/spanner-osdi2012.pdf) | +| データストア | **Memcached** - 分散メモリーキャッシングシステム | [slideshare.net](http://www.slideshare.net/oemebamo/introduction-to-memcached) | +| データストア | **Redis** - 永続性とバリュータイプを兼ね備えた分散メモリーキャッシングシステム | [slideshare.net](http://www.slideshare.net/dvirsky/introduction-to-redis) | +| | | | +| ファイルシステム | **Google File System (GFS)** - 分散ファイルシステム | [research.google.com](http://static.googleusercontent.com/media/research.google.com/zh-CN/us/archive/gfs-sosp2003.pdf) | +| ファイルシステム | **Hadoop File System (HDFS)** - GFSのオープンソース実装 | [apache.org](https://hadoop.apache.org/docs/r1.2.1/hdfs_design.html) | +| | | | +| Misc | **Chubby** - 疎結合の分散システムをロックするGoogleのサービス | [research.google.com](http://static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/en/us/archive/chubby-osdi06.pdf) | +| Misc | **Dapper** - 分散システムを追跡するインフラ | [research.google.com](http://static.googleusercontent.com/media/research.google.com/en//pubs/archive/36356.pdf) +| Misc | **Kafka** - LinkedInによるPub/subメッセージキュー | [slideshare.net](http://www.slideshare.net/mumrah/kafka-talk-tri-hug) | +| Misc | **Zookeeper** - 同期を可能にする中央集権インフラとサービス | [slideshare.net](http://www.slideshare.net/sauravhaloi/introduction-to-apache-zookeeper) | +| | アーキテクチャを追加する | [Contribute](#contributing) | + +### 各企業のアーキテクチャ + +| 企業 | 参考ページ | +|---|---| +| Amazon | [Amazon architecture](http://highscalability.com/amazon-architecture) | +| Cinchcast | [Producing 1,500 hours of audio every day](http://highscalability.com/blog/2012/7/16/cinchcast-architecture-producing-1500-hours-of-audio-every-d.html) | +| DataSift | [Realtime datamining At 120,000 tweets per second](http://highscalability.com/blog/2011/11/29/datasift-architecture-realtime-datamining-at-120000-tweets-p.html) | +| DropBox | [How we've scaled Dropbox](https://www.youtube.com/watch?v=PE4gwstWhmc) | +| ESPN | [Operating At 100,000 duh nuh nuhs per second](http://highscalability.com/blog/2013/11/4/espns-architecture-at-scale-operating-at-100000-duh-nuh-nuhs.html) | +| Google | [Google architecture](http://highscalability.com/google-architecture) | +| Instagram | [14 million users, terabytes of photos](http://highscalability.com/blog/2011/12/6/instagram-architecture-14-million-users-terabytes-of-photos.html)
[What powers Instagram](http://instagram-engineering.tumblr.com/post/13649370142/what-powers-instagram-hundreds-of-instances) | +| Justin.tv | [Justin.Tv's live video broadcasting architecture](http://highscalability.com/blog/2010/3/16/justintvs-live-video-broadcasting-architecture.html) | +| Facebook | [Scaling memcached at Facebook](https://cs.uwaterloo.ca/~brecht/courses/854-Emerging-2014/readings/key-value/fb-memcached-nsdi-2013.pdf)
[TAO: Facebook’s distributed data store for the social graph](https://cs.uwaterloo.ca/~brecht/courses/854-Emerging-2014/readings/data-store/tao-facebook-distributed-datastore-atc-2013.pdf)
[Facebook’s photo storage](https://www.usenix.org/legacy/event/osdi10/tech/full_papers/Beaver.pdf) | +| Flickr | [Flickr architecture](http://highscalability.com/flickr-architecture) | +| Mailbox | [From 0 to one million users in 6 weeks](http://highscalability.com/blog/2013/6/18/scaling-mailbox-from-0-to-one-million-users-in-6-weeks-and-1.html) | +| Pinterest | [From 0 To 10s of billions of page views a month](http://highscalability.com/blog/2013/4/15/scaling-pinterest-from-0-to-10s-of-billions-of-page-views-a.html)
[18 million visitors, 10x growth, 12 employees](http://highscalability.com/blog/2012/5/21/pinterest-architecture-update-18-million-visitors-10x-growth.html) | +| Playfish | [50 million monthly users and growing](http://highscalability.com/blog/2010/9/21/playfishs-social-gaming-architecture-50-million-monthly-user.html) | +| PlentyOfFish | [PlentyOfFish architecture](http://highscalability.com/plentyoffish-architecture) | +| Salesforce | [How they handle 1.3 billion transactions a day](http://highscalability.com/blog/2013/9/23/salesforce-architecture-how-they-handle-13-billion-transacti.html) | +| Stack Overflow | [Stack Overflow architecture](http://highscalability.com/blog/2009/8/5/stack-overflow-architecture.html) | +| TripAdvisor | [40M visitors, 200M dynamic page views, 30TB data](http://highscalability.com/blog/2011/6/27/tripadvisor-architecture-40m-visitors-200m-dynamic-page-view.html) | +| Tumblr | [15 billion page views a month](http://highscalability.com/blog/2012/2/13/tumblr-architecture-15-billion-page-views-a-month-and-harder.html) | +| Twitter | [Making Twitter 10000 percent faster](http://highscalability.com/scaling-twitter-making-twitter-10000-percent-faster)
[Storing 250 million tweets a day using MySQL](http://highscalability.com/blog/2011/12/19/how-twitter-stores-250-million-tweets-a-day-using-mysql.html)
[150M active users, 300K QPS, a 22 MB/S firehose](http://highscalability.com/blog/2013/7/8/the-architecture-twitter-uses-to-deal-with-150m-active-users.html)
[Timelines at scale](https://www.infoq.com/presentations/Twitter-Timeline-Scalability)
[Big and small data at Twitter](https://www.youtube.com/watch?v=5cKTP36HVgI)
[Operations at Twitter: scaling beyond 100 million users](https://www.youtube.com/watch?v=z8LU0Cj6BOU) | +| Uber | [How Uber scales their real-time market platform](http://highscalability.com/blog/2015/9/14/how-uber-scales-their-real-time-market-platform.html) | +| WhatsApp | [The WhatsApp architecture Facebook bought for $19 billion](http://highscalability.com/blog/2014/2/26/the-whatsapp-architecture-facebook-bought-for-19-billion.html) | +| YouTube | [YouTube scalability](https://www.youtube.com/watch?v=w5WVu624fY8)
[YouTube architecture](http://highscalability.com/youtube-architecture) | + +### 企業のエンジニアブログ + +> 面接を受ける企業のアーキテクチャ +> +> 投げられる質問は同じ分野から来ることもあるでしょう + +* [Airbnb Engineering](http://nerds.airbnb.com/) +* [Atlassian Developers](https://developer.atlassian.com/blog/) +* [Autodesk Engineering](http://cloudengineering.autodesk.com/blog/) +* [AWS Blog](https://aws.amazon.com/blogs/aws/) +* [Bitly Engineering Blog](http://word.bitly.com/) +* [Box Blogs](https://www.box.com/blog/engineering/) +* [Cloudera Developer Blog](http://blog.cloudera.com/blog/) +* [Dropbox Tech Blog](https://tech.dropbox.com/) +* [Engineering at Quora](http://engineering.quora.com/) +* [Ebay Tech Blog](http://www.ebaytechblog.com/) +* [Evernote Tech Blog](https://blog.evernote.com/tech/) +* [Etsy Code as Craft](http://codeascraft.com/) +* [Facebook Engineering](https://www.facebook.com/Engineering) +* [Flickr Code](http://code.flickr.net/) +* [Foursquare Engineering Blog](http://engineering.foursquare.com/) +* [GitHub Engineering Blog](http://githubengineering.com/) +* [Google Research Blog](http://googleresearch.blogspot.com/) +* [Groupon Engineering Blog](https://engineering.groupon.com/) +* [Heroku Engineering Blog](https://engineering.heroku.com/) +* [Hubspot Engineering Blog](http://product.hubspot.com/blog/topic/engineering) +* [High Scalability](http://highscalability.com/) +* [Instagram Engineering](http://instagram-engineering.tumblr.com/) +* [Intel Software Blog](https://software.intel.com/en-us/blogs/) +* [Jane Street Tech Blog](https://blogs.janestreet.com/category/ocaml/) +* [LinkedIn Engineering](http://engineering.linkedin.com/blog) +* [Microsoft Engineering](https://engineering.microsoft.com/) +* [Microsoft Python Engineering](https://blogs.msdn.microsoft.com/pythonengineering/) +* [Netflix Tech Blog](http://techblog.netflix.com/) +* [Paypal Developer Blog](https://devblog.paypal.com/category/engineering/) +* [Pinterest Engineering Blog](http://engineering.pinterest.com/) +* [Quora Engineering](https://engineering.quora.com/) +* [Reddit Blog](http://www.redditblog.com/) +* [Salesforce Engineering Blog](https://developer.salesforce.com/blogs/engineering/) +* [Slack Engineering Blog](https://slack.engineering/) +* [Spotify Labs](https://labs.spotify.com/) +* [Twilio Engineering Blog](http://www.twilio.com/engineering) +* [Twitter Engineering](https://engineering.twitter.com/) +* [Uber Engineering Blog](http://eng.uber.com/) +* [Yahoo Engineering Blog](http://yahooeng.tumblr.com/) +* [Yelp Engineering Blog](http://engineeringblog.yelp.com/) +* [Zynga Engineering Blog](https://www.zynga.com/blogs/engineering) + +#### その他の参考資料、ページ: + +* [kilimchoi/engineering-blogs](https://github.com/kilimchoi/engineering-blogs) + +ここにあるリストは比較的小規模なものにとどめ、[kilimchoi/engineering-blogs](https://github.com/kilimchoi/engineering-blogs)により詳細に記すことで重複しないようにしておくことにする。エンジニアブログへのリンクを追加する場合はここではなく、engineering-blogsレボジトリに追加することを検討してください。 + +## 進行中の作業 + +セクションの追加や、進行中の作業を手伝っていただける場合は[こちら](#contributing)! + +* MapReduceによる分散コンピューティング +* Consistent hashing +* Scatter gather +* [Contribute](#contributing) + +## クレジット + +クレジット及び、参照ページは適時このリポジトリ内に記載してあります + +Special thanks to: + +* [Hired in tech](http://www.hiredintech.com/system-design/the-system-design-process/) +* [Cracking the coding interview](https://www.amazon.com/dp/0984782850/) +* [High scalability](http://highscalability.com/) +* [checkcheckzz/system-design-interview](https://github.com/checkcheckzz/system-design-interview) +* [shashank88/system_design](https://github.com/shashank88/system_design) +* [mmcgrana/services-engineering](https://github.com/mmcgrana/services-engineering) +* [System design cheat sheet](https://gist.github.com/vasanthk/485d1c25737e8e72759f) +* [A distributed systems reading list](http://dancres.github.io/Pages/) +* [Cracking the system design interview](http://www.puncsky.com/blog/2016-02-13-crack-the-system-design-interview) + +## Contact info + +Feel free to contact me to discuss any issues, questions, or comments. + +My contact info can be found on my [GitHub page](https://github.com/donnemartin). + +## License + +*I am providing code and resources in this repository to you under an open source license. Because this is my personal repository, the license you receive to my code and resources is from me and not my employer (Facebook).* + + Copyright 2017 Donne Martin + + Creative Commons Attribution 4.0 International License (CC BY 4.0) + + http://creativecommons.org/licenses/by/4.0/ diff --git a/README-zh-Hans.md b/README-zh-Hans.md index e50f17eed92..1ab9dd43361 100644 --- a/README-zh-Hans.md +++ b/README-zh-Hans.md @@ -3,10 +3,12 @@ > * 译者:[XatMassacrE](https://github.com/XatMassacrE)、[L9m](https://github.com/L9m)、[Airmacho](https://github.com/Airmacho)、[xiaoyusilen](https://github.com/xiaoyusilen)、[jifaxu](https://github.com/jifaxu) > * 这个 [链接](https://github.com/xitu/system-design-primer/compare/master...donnemartin:master) 用来查看本翻译与英文版是否有差别(如果你没有看到 README.md 发生变化,那就意味着这份翻译文档是最新的)。 +*[English](README.md) ∙ [日本語](README-ja.md) ∙ [简体中文](README-zh-Hans.md) ∙ [繁體中文](README-zh-TW.md) | [العَرَبِيَّة‎](https://github.com/donnemartin/system-design-primer/issues/170) ∙ [বাংলা](https://github.com/donnemartin/system-design-primer/issues/220) ∙ [Português do Brasil](https://github.com/donnemartin/system-design-primer/issues/40) ∙ [Deutsch](https://github.com/donnemartin/system-design-primer/issues/186) ∙ [ελληνικά](https://github.com/donnemartin/system-design-primer/issues/130) ∙ [עברית](https://github.com/donnemartin/system-design-primer/issues/272) ∙ [Italiano](https://github.com/donnemartin/system-design-primer/issues/104) ∙ [韓國語](https://github.com/donnemartin/system-design-primer/issues/102) ∙ [فارسی](https://github.com/donnemartin/system-design-primer/issues/110) ∙ [Polski](https://github.com/donnemartin/system-design-primer/issues/68) ∙ [русский язык](https://github.com/donnemartin/system-design-primer/issues/87) ∙ [Español](https://github.com/donnemartin/system-design-primer/issues/136) ∙ [ภาษาไทย](https://github.com/donnemartin/system-design-primer/issues/187) ∙ [Türkçe](https://github.com/donnemartin/system-design-primer/issues/39) ∙ [tiếng Việt](https://github.com/donnemartin/system-design-primer/issues/127) ∙ [Français](https://github.com/donnemartin/system-design-primer/issues/250) | [Add Translation](https://github.com/donnemartin/system-design-primer/issues/28)* + # 系统设计入门

- +

@@ -55,7 +57,7 @@ ## 抽认卡

- +

@@ -72,7 +74,7 @@ 你正在寻找资源以准备[**编程面试**](https://github.com/donnemartin/interactive-coding-challenges)吗?

- +

@@ -98,17 +100,17 @@ > 各种系统设计主题的摘要,包括优点和缺点。**每一个主题都面临着取舍和权衡**。 > -> 每个章节都包含着更的资源的链接。 +> 每个章节都包含着更多的资源的链接。

- +

* [系统设计主题:从这里开始](#系统设计主题从这里开始) * [第一步:回顾可扩展性的视频讲座](#第一步回顾可扩展性scalability的视频讲座) - * [第二步: 回顾可扩展性的文章](#第二步回顾可扩展性文章) + * [第二步:回顾可扩展性的文章](#第二步回顾可扩展性文章) * [接下来的步骤](#接下来的步骤) * [性能与拓展性](#性能与可扩展性) * [延迟与吞吐量](#延迟与吞吐量) @@ -207,11 +209,11 @@ 那些有经验的候选人通常会被期望了解更多的系统设计的知识。架构师或者团队负责人则会被期望了解更多除了个人贡献之外的知识。顶级的科技公司通常也会有一次或者更多的系统设计面试。 -面试会很宽泛的展开并在几个领域深入。这回帮助你了解一些关于系统设计的不同的主题。基于你的时间线,经验,面试的职位和面试的公司对下面的指导做出适当的调整。 +面试会很宽泛的展开并在几个领域深入。这会帮助你了解一些关于系统设计的不同的主题。基于你的时间线,经验,面试的职位和面试的公司对下面的指导做出适当的调整。 * **短期** - 以系统设计主题的**广度**为目标。通过解决**一些**面试题来练习。 * **中期** - 以系统设计主题的**广度**和**初级深度**为目标。通过解决**很多**面试题来练习。 -* **长期** - 以系统设计主题的**广度**和**高级深度**为目标。通过解决**大部分**面试题来联系。 +* **长期** - 以系统设计主题的**广度**和**高级深度**为目标。通过解决**大部分**面试题来练习。 | | 短期 | 中期 | 长期 | | ---------------------------------------- | ---- | ---- | ---- | @@ -242,9 +244,9 @@ * 我们希望每秒钟处理多少请求? * 我们希望的读写比率? -### 第二步:创造一个高级的设计 +### 第二步:创造一个高层级的设计 -使用所有重要的组件来描绘出一个高级的设计。 +使用所有重要的组件来描绘出一个高层级的设计。 * 画出主要的组件和连接 * 证明你的想法 @@ -262,22 +264,22 @@ * 数据库查找 * API 和面向对象设计 -### 第四步:度量设计 +### 第四步:扩展设计 -确认和处理瓶颈以及一些限制。举例来说就是你需要下面的这些来完成拓展性的议题吗? +确认和处理瓶颈以及一些限制。举例来说就是你需要下面的这些来完成扩展性的议题吗? * 负载均衡 -* 水平拓展 +* 水平扩展 * 缓存 * 数据库分片 -论述可能的解决办法和代价。每件事情需要取舍。可以使用[可拓展系统的设计原则](#系统设计主题的索引)来处理瓶颈。 +论述可能的解决办法和代价。每件事情需要取舍。可以使用[可扩展系统的设计原则](#系统设计主题的索引)来处理瓶颈。 -### 信封背面的计算 +### 预估计算量 -你或许会被要求通过手算进行一些估算。涉及到的[附录](#附录)涉及到的是下面的这些资源: +你或许会被要求通过手算进行一些估算。[附录](#附录)涉及到的是下面的这些资源: -* [使用信封的背面做计算](http://highscalability.com/blog/2011/1/26/google-pro-tip-use-back-of-the-envelope-calculations-to-choo.html) +* [使用预估计算量](http://highscalability.com/blog/2011/1/26/google-pro-tip-use-back-of-the-envelope-calculations-to-choo.html) * [2 的次方表](#2-的次方表) * [每个程序员都应该知道的延迟数](#每个程序员都应该知道的延迟数) @@ -298,7 +300,7 @@ | 问题 | | | ---------------------------------------- | ---------------------------------------- | -| 设计 Pastebin.com (或者 Bit.ly) | [解答](solutions/system_design/pastebin/README.md) | +| 设计 Pastebin.com (或者 Bit.ly) | [解答](solutions/system_design/pastebin/README-zh-Hans.md) | | 设计 Twitter 时间线和搜索 (或者 Facebook feed 和搜索) | [解答](solutions/system_design/twitter/README.md) | | 设计一个网页爬虫 | [解答](solutions/system_design/web_crawler/README.md) | | 设计 Mint.com | [解答](solutions/system_design/mint/README.md) | @@ -395,7 +397,7 @@ ### 第二步:回顾可扩展性文章 -[可扩展性](http://www.lecloud.net/tagged/scalability) +[可扩展性](http://www.lecloud.net/tagged/scalability/chrono) * 主题涵盖: * [Clones](http://www.lecloud.net/post/7295452622/scalability-for-dummies-part-1-clones) @@ -446,7 +448,7 @@ ### CAP 理论

- +
来源:再看 CAP 理论

@@ -541,7 +543,7 @@ DNS 和 email 等系统使用的是此种方式。最终一致性在高可用性 ## 域名系统

- +
来源:DNS 安全介绍

@@ -568,7 +570,7 @@ DNS 和 email 等系统使用的是此种方式。最终一致性在高可用性 * 虽说缓存可以减轻 DNS 延迟,但连接 DNS 服务器还是带来了轻微的延迟。 * 虽然它们通常由[政府,网络服务提供商和大公司](http://superuser.com/questions/472695/who-controls-the-dns-servers/472729)管理,但 DNS 服务管理仍可能是复杂的。 -* DNS 服务最近遭受 [DDoS 攻击](http://dyn.com/blog/dyn-analysis-summary-of-friday-october-21-attack/),阻止不知道 Twtter IP 地址的用户访问 Twiiter。 +* DNS 服务最近遭受 [DDoS 攻击](http://dyn.com/blog/dyn-analysis-summary-of-friday-october-21-attack/),阻止不知道 Twitter IP 地址的用户访问 Twitter。 ### 来源及延伸阅读 @@ -579,7 +581,7 @@ DNS 和 email 等系统使用的是此种方式。最终一致性在高可用性 ## 内容分发网络(CDN)

- +
来源:为什么使用 CDN

@@ -618,7 +620,7 @@ CDN 拉取是当第一个用户请求该资源时,从服务器上拉取资源 ## 负载均衡器

- +
来源:可扩展的系统设计模式

@@ -687,7 +689,7 @@ CDN 拉取是当第一个用户请求该资源时,从服务器上拉取资源 ## 反向代理(web 服务器)

- +
资料来源:维基百科
@@ -731,7 +733,7 @@ CDN 拉取是当第一个用户请求该资源时,从服务器上拉取资源 ## 应用层

- +
资料来源:可缩放系统构架介绍

@@ -761,7 +763,7 @@ CDN 拉取是当第一个用户请求该资源时,从服务器上拉取资源 ### 来源及延伸阅读 - [可缩放系统构架介绍](http://lethain.com/introduction-to-architecting-systems-for-scale) -- [破解系统设计面试](http://www.puncsky.com/blog/2016/02/14/crack-the-system-design-interview/) +- [破解系统设计面试](http://www.puncsky.com/blog/2016-02-13-crack-the-system-design-interview) - [面向服务架构](https://en.wikipedia.org/wiki/Service-oriented_architecture) - [Zookeeper 介绍](http://www.slideshare.net/sauravhaloi/introduction-to-apache-zookeeper) - [构建微服务,你所需要知道的一切](https://cloudncode.wordpress.com/2016/07/22/msa-getting-started/) @@ -769,9 +771,9 @@ CDN 拉取是当第一个用户请求该资源时,从服务器上拉取资源 ## 数据库

- +
- 资料来源:扩展你的用户数到第一个一千万 + 资料来源:扩展你的用户数到第一个一千万

### 关系型数据库管理系统(RDBMS) @@ -790,7 +792,7 @@ CDN 拉取是当第一个用户请求该资源时,从服务器上拉取资源 关系型数据库扩展包括许多技术:**主从复制**、**主主复制**、**联合**、**分片**、**非规范化**和 **SQL调优**。

- +
资料来源:可扩展性、可用性、稳定性、模式

@@ -805,7 +807,7 @@ CDN 拉取是当第一个用户请求该资源时,从服务器上拉取资源 - 参考[不利之处:复制](#不利之处复制)中,主从复制和主主复制**共同**的问题。

- +
资料来源:可扩展性、可用性、稳定性、模式

@@ -840,9 +842,9 @@ CDN 拉取是当第一个用户请求该资源时,从服务器上拉取资源 #### 联合

- +
- 资料来源:扩展你的用户数到第一个一千万 + 资料来源:扩展你的用户数到第一个一千万

联合(或按功能划分)将数据库按对应功能分割。例如,你可以有三个数据库:**论坛**、**用户**和**产品**,而不仅是一个单体数据库,从而减少每个数据库的读取和写入流量,减少复制延迟。较小的数据库意味着更多适合放入内存的数据,进而意味着更高的缓存命中几率。没有只能串行写入的中心化主库,你可以并行写入,提高负载能力。 @@ -857,12 +859,12 @@ CDN 拉取是当第一个用户请求该资源时,从服务器上拉取资源 ##### 来源及延伸阅读:联合 -- [扩展你的用户数到第一个一千万](https://www.youtube.com/watch?v=vg5onp8TU6Q) +- [扩展你的用户数到第一个一千万](https://www.youtube.com/watch?v=w95murBkYmU) #### 分片

- +
资料来源:可扩展性、可用性、稳定性、模式

@@ -889,7 +891,7 @@ CDN 拉取是当第一个用户请求该资源时,从服务器上拉取资源 #### 非规范化 -非规范化试图以写入性能为代价来换取读取性能。在多个表中冗余数据副本,以避免高成本的联结操作。一些关系型数据库,比如 [PostgreSQl](https://en.wikipedia.org/wiki/PostgreSQL) 和 Oracle 支持[物化视图](https://en.wikipedia.org/wiki/Materialized_view),可以处理冗余信息存储和保证冗余副本一致。 +非规范化试图以写入性能为代价来换取读取性能。在多个表中冗余数据副本,以避免高成本的联结操作。一些关系型数据库,比如 [PostgreSQL](https://en.wikipedia.org/wiki/PostgreSQL) 和 Oracle 支持[物化视图](https://en.wikipedia.org/wiki/Materialized_view),可以处理冗余信息存储和保证冗余副本一致。 当数据使用诸如[联合](#联合)和[分片](#分片)等技术被分割,进一步提高了处理跨数据中心的联结操作复杂度。非规范化可以规避这种复杂的联结操作。 @@ -1006,7 +1008,7 @@ MongoDB 和 CouchDB 等一些文档类型存储还提供了类似 SQL 语言的 #### 列型存储

- +
资料来源: SQL 和 NoSQL,一个简短的历史

@@ -1029,9 +1031,9 @@ Google 发布了第一个列型存储数据库 [Bigtable](http://www.read.seas.h #### 图数据库

- +
- 资料来源:图数据库 + 资料来源:图数据库

> 抽象模型: 图 @@ -1056,7 +1058,7 @@ Google 发布了第一个列型存储数据库 [Bigtable](http://www.read.seas.h ### SQL 还是 NoSQL

- +
资料来源:从 RDBMS 转换到 NoSQL

@@ -1092,12 +1094,12 @@ Google 发布了第一个列型存储数据库 [Bigtable](http://www.read.seas.h ##### 来源及延伸阅读:SQL 或 NoSQL -- [扩展你的用户数到第一个千万](https://www.youtube.com/watch?v=vg5onp8TU6Q) +- [扩展你的用户数到第一个千万](https://www.youtube.com/watch?v=w95murBkYmU) - [SQL 和 NoSQL 的不同](https://www.sitepoint.com/sql-vs-nosql-differences/) ## 缓存

- +
资料来源:可扩展的系统设计模式

@@ -1168,7 +1170,7 @@ Redis 有下列附加功能: #### 缓存模式

- +
资料来源:从缓存到内存数据网格

@@ -1180,7 +1182,7 @@ Redis 有下列附加功能: - 将查找到的结果存储到缓存中 - 返回所需内容 -``` +```python def get_user(self, user_id): user = cache.get("user.{0}", user_id) if user is None: @@ -1204,7 +1206,7 @@ def get_user(self, user_id): #### 直写模式

- +
资料来源:可扩展性、可用性、稳定性、模式

@@ -1223,7 +1225,7 @@ set_user(12345, {"foo":"bar"}) 缓存代码: -``` +```python def set_user(user_id, values): user = db.query("UPDATE Users WHERE id = {0}", user_id, values) cache.set(user_id, user) @@ -1239,7 +1241,7 @@ def set_user(user_id, values): #### 回写模式

- +
资料来源:可扩展性、可用性、稳定性、模式

@@ -1257,7 +1259,7 @@ def set_user(user_id, values): #### 刷新

- +
资料来源:从缓存到内存数据网格

@@ -1289,7 +1291,7 @@ def set_user(user_id, values): ## 异步

- +
资料来源:可缩放系统构架介绍

@@ -1319,7 +1321,7 @@ def set_user(user_id, values): ### 背压 -如果队列开始明显增长,那么队列大小可能会超过内存大小,导致高速缓存未命中,磁盘读取,甚至性能更慢。[背压](http://mechanical-sympathy.blogspot.com/2012/05/apply-back-pressure-when-overloaded.html)可以通过限制队列大小来帮助我们,从而为队列中的作业保持高吞吐率和良好的响应时间。一旦队列填满,客户端将得到服务器忙活着 HTTP 503 状态码,以便稍后重试。客户端可以在稍后时间重试该请求,也许是[指数退避](https://en.wikipedia.org/wiki/Exponential_backoff)。 +如果队列开始明显增长,那么队列大小可能会超过内存大小,导致高速缓存未命中,磁盘读取,甚至性能更慢。[背压](http://mechanical-sympathy.blogspot.com/2012/05/apply-back-pressure-when-overloaded.html)可以通过限制队列大小来帮助我们,从而为队列中的作业保持高吞吐率和良好的响应时间。一旦队列填满,客户端将得到服务器忙或者 HTTP 503 状态码,以便稍后重试。客户端可以在稍后时间重试该请求,也许是[指数退避](https://en.wikipedia.org/wiki/Exponential_backoff)。 ### 异步的缺点: @@ -1335,7 +1337,7 @@ def set_user(user_id, values): ## 通讯

- +
资料来源:OSI 7层模型

@@ -1370,7 +1372,7 @@ HTTP 是依赖于较低级协议(如 **TCP** 和 **UDP**)的应用层协议 ### 传输控制协议(TCP)

- +
资料来源:如何制作多人游戏

@@ -1394,7 +1396,7 @@ TCP 对于需要高可靠性但时间紧迫的应用程序很有用。比如包 ### 用户数据报协议(UDP)

- +
资料来源:如何制作多人游戏

@@ -1423,7 +1425,7 @@ UDP 可靠性更低但适合用在网络电话、视频聊天,流媒体和实 ### 远程过程调用协议(RPC)

- +
Source: Crack the system design interview

@@ -1521,7 +1523,7 @@ REST 关注于暴露数据。它减少了客户端/服务端的耦合程度, * [REST vs JSON-RPC](http://stackoverflow.com/questions/15056878/rest-vs-json-rpc) * [揭开 RPC 和 REST 的神秘面纱](http://etherealbits.com/2012/12/debunking-the-myths-of-rpc-rest/) * [使用 REST 的缺点是什么](https://www.quora.com/What-are-the-drawbacks-of-using-RESTful-APIs) -* [破解系统设计面试](http://www.puncsky.com/blog/2016/02/14/crack-the-system-design-interview/) +* [破解系统设计面试](http://www.puncsky.com/blog/2016-02-13-crack-the-system-design-interview) * [Thrift](https://code.facebook.com/posts/1468950976659943/) * [为什么在内部使用 REST 而不是 RPC](http://arstechnica.com/civis/viewtopic.php?t=1190508) @@ -1572,7 +1574,7 @@ Latency Comparison Numbers L1 cache reference 0.5 ns Branch mispredict 5 ns L2 cache reference 7 ns 14x L1 cache -Mutex lock/unlock 100 ns +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 @@ -1618,10 +1620,10 @@ Notes | 问题 | 引用 | | ----------------------- | ---------------------------------------- | | 设计类似于 Dropbox 的文件同步服务 | [youtube.com](https://www.youtube.com/watch?v=PE4gwstWhmc) | -| 设计类似于 Google 的搜索引擎 | [queue.acm.org](http://queue.acm.org/detail.cfm?id=988407)
[stackexchange.com](http://programmers.stackexchange.com/questions/38324/interview-question-how-would-you-implement-google-search)
[ardendertat.com](http://www.ardendertat.com/2012/01/11/implementing-search-engines/)
[stanford.edu](http://infolab.stanford.edu/~backrub/google.html) | +| 设计类似于 Google 的搜索引擎 | [queue.acm.org](http://queue.acm.org/detail.cfm?id=988407)
[stackexchange.com](http://programmers.stackexchange.com/questions/38324/interview-question-how-would-you-implement-google-search)
[ardendertat.com](http://www.ardendertat.com/2012/01/11/implementing-search-engines/)
[stanford.edu](http://infolab.stanford.edu/~backrub/google.html) | | 设计类似于 Google 的可扩展网络爬虫 | [quora.com](https://www.quora.com/How-can-I-build-a-web-crawler-from-scratch) | | 设计 Google 文档 | [code.google.com](https://code.google.com/p/google-mobwrite/)
[neil.fraser.name](https://neil.fraser.name/writing/sync/) | -| 设计类似 Redis 的建值存储 | [slideshare.net](http://www.slideshare.net/dvirsky/introduction-to-redis) | +| 设计类似 Redis 的键值存储 | [slideshare.net](http://www.slideshare.net/dvirsky/introduction-to-redis) | | 设计类似 Memcached 的缓存系统 | [slideshare.net](http://www.slideshare.net/oemebamo/introduction-to-memcached) | | 设计类似亚马逊的推荐系统 | [hulu.com](http://tech.hulu.com/blog/2011/09/19/recommendation-system.html)
[ijcai13.org](http://ijcai13.org/files/tutorial_slides/td3.pdf) | | 设计类似 Bitly 的短链接系统 | [n00tc0d3r.blogspot.com](http://n00tc0d3r.blogspot.com/) | @@ -1645,7 +1647,7 @@ Notes > 关于现实中真实的系统是怎么设计的文章。

- +
Source: Twitter timelines at scale

@@ -1782,7 +1784,7 @@ Notes * [mmcgrana/services-engineering](https://github.com/mmcgrana/services-engineering) * [System design cheat sheet](https://gist.github.com/vasanthk/485d1c25737e8e72759f) * [A distributed systems reading list](http://dancres.github.io/Pages/) -* [Cracking the system design interview](http://www.puncsky.com/blog/2016/02/14/crack-the-system-design-interview/) +* [Cracking the system design interview](http://www.puncsky.com/blog/2016-02-13-crack-the-system-design-interview) ## 联系方式 diff --git a/README-zh-TW.md b/README-zh-TW.md new file mode 100644 index 00000000000..c08362d3d37 --- /dev/null +++ b/README-zh-TW.md @@ -0,0 +1,1786 @@ +*[English](README.md) ∙ [日本語](README-ja.md) ∙ [简体中文](README-zh-Hans.md) ∙ [繁體中文](README-zh-TW.md) | [العَرَبِيَّة‎](https://github.com/donnemartin/system-design-primer/issues/170) ∙ [বাংলা](https://github.com/donnemartin/system-design-primer/issues/220) ∙ [Português do Brasil](https://github.com/donnemartin/system-design-primer/issues/40) ∙ [Deutsch](https://github.com/donnemartin/system-design-primer/issues/186) ∙ [ελληνικά](https://github.com/donnemartin/system-design-primer/issues/130) ∙ [עברית](https://github.com/donnemartin/system-design-primer/issues/272) ∙ [Italiano](https://github.com/donnemartin/system-design-primer/issues/104) ∙ [韓國語](https://github.com/donnemartin/system-design-primer/issues/102) ∙ [فارسی](https://github.com/donnemartin/system-design-primer/issues/110) ∙ [Polski](https://github.com/donnemartin/system-design-primer/issues/68) ∙ [русский язык](https://github.com/donnemartin/system-design-primer/issues/87) ∙ [Español](https://github.com/donnemartin/system-design-primer/issues/136) ∙ [ภาษาไทย](https://github.com/donnemartin/system-design-primer/issues/187) ∙ [Türkçe](https://github.com/donnemartin/system-design-primer/issues/39) ∙ [tiếng Việt](https://github.com/donnemartin/system-design-primer/issues/127) ∙ [Français](https://github.com/donnemartin/system-design-primer/issues/250) | [Add Translation](https://github.com/donnemartin/system-design-primer/issues/28)* + +# 系統設計入門 + +

+ +
+

+ +## 動機 + +> 學習如何設計大型系統。 +> +> 準備系統設計的面試。 + +### 學習如何設計大型系統 + +學習如何設計可擴展的系統會幫助你成為一個更好的工程師。 + +系統設計是一個廣泛的主題。在網路上,關於**系統設計的資源也是不計其數**。 + +本專案將**許多資源進行分門別類**,幫助你學習如何建構可擴展的系統。 + +### 從開放原始碼社群中學習 + +這是一個早期、持續不斷更新的開放原始碼專案。 + +[任何貢獻](#如何貢獻) 都相當歡迎! + +### 準備系統設計的面試 + +除了程式的面試外,系統設計在許多科技公司的**面試流程**中都是**必要**的一環。 + +**練習常見的系統設計問題**,並且將你的設計結果和**參考答案**進行**比對**:討論、程式碼和圖表。 + +關於面試的其他主題: + +* [學習指南](#學習指南) +* [如何解決一個系統設計的面試題目](#如何解決一個系統設計的面試題目) +* [系統設計面試問題與**解答**](#系統設計面試問題與解答) +* [物件導向設計問題與**解答**](#物件導向設計面試問題與解答) +* [其他的系統設計面試問題](#其他的系統設計面試問題) + +## 學習單字卡 + +

+ +
+

+ +底下提供的[學習單字卡](https://apps.ankiweb.net/)以每隔一段時間間隔出現的方式,幫助你學習系統設計的概念。 + +* [系統設計單字卡](resources/flash_cards/System%20Design.apkg) +* [系統設計練習單字卡](resources/flash_cards/System%20Design%20Exercises.apkg) +* [物件導向設計練習單字卡](resources/flash_cards/OO%20Design.apkg) + +這些是非常棒的學習資源,隨時都可以使用。 + +### 程式設計學習資源:互動式程式學習設計 + +你正在尋找資源來面對[**程式語言面試**](https://github.com/donnemartin/interactive-coding-challenges)嗎? + +

+ +
+

+ +請參考 [**互動程式語言學習挑戰**](https://github.com/donnemartin/interactive-coding-challenges),當中還包含了底下的學習單字卡: + +* [程式語言學習單卡](https://github.com/donnemartin/interactive-coding-challenges/tree/master/anki_cards/Coding.apkg) + +## 如何貢獻 + +> 從社群中學習 + +隨時歡迎提交 Pull Request: + +* 修正錯誤 +* 改善章節內容 +* 增加新的章節 +* [翻譯](https://github.com/donnemartin/system-design-primer/issues/28) + +某些還需要再完善的章節放在 [修正中](#仍在進行中)。 + +請參考 [貢獻指南](CONTRIBUTING.md)。 + +## 系統設計主題的索引 + +> 底下是數個系統設計的主題,包含了優點及缺點。**要記得,每一個系統設計的考量都包含著某種取捨**。 +> +> 每一章節都包含更深入資源的連結。 + +

+ +
+

+ +* [系統設計主題:從這裡開始](#系統設計主題從這裡開始) + * [第一步:複習關於可擴展性的影片講座](#第一步複習關於可擴展性的影片講座) + * [第二步:複習關於可擴展性的文章](#第二步複習關於可擴展性的文章) + * [下一步](#下一步) +* [效能與可擴展性](#效能與可擴展性) +* [延遲與吞吐量](#延遲與吞吐量) +* [可用性與一致性](#可用性與一致性) + * [CAP 理論](#cap-理論) + * [CP-一致性與部分容錯性](#cp-一致性與部分容錯性) + * [AP-可用性與部分容錯性](#ap-可用性與部分容錯性) +* [一致性模式](#一致性模式) + * [弱一致性](#弱一致性) + * [最終一致性](#最終一致性) + * [強一致性](#強一致性) +* [可用性模式](#可用性模式) + * [容錯轉移](#容錯轉移) + * [複寫機制](#複寫機制) +* [域名系統](#域名系統) +* [內容傳遞網路(CDN)](#內容傳遞網路cdn) + * [推送式 CDNs](#推送式-cdns) + * [拉取式 CDNs](#拉取式-cdns) +* [負載平衡器](#負載平衡器) + * [主動到備用切換模式(AP Mode)](#主動到備用切換模式ap-mode) + * [雙主動切換模式(AA Mode)](#雙主動切換模式aa-mode) + * [第四層負載平衡](#第四層負載平衡) + * [第七層負載平衡](#第七層負載平衡) + * [水平擴展](#水平擴展) +* [反向代理(網頁伺服器)](#反向代理網頁伺服器) + * [負載平衡器與反向代理伺服器](#負載平衡器與反向代理伺服器) +* [應用層](#應用層) + * [微服務](#微服務) + * [服務發現](#服務發現) +* [資料庫](#資料庫) + * [關連式資料庫管理系統(RDBMS)](#關連式資料庫管理系統rdbms) + * [主從複寫](#主從複寫) + * [主動模式複寫](#主動模式複寫) + * [聯邦式資料庫](#聯邦式資料庫) + * [分片](#分片) + * [反正規化](#反正規化) + * [SQL 優化](#sql-優化) + * [NoSQL](#nosql) + * [鍵-值對的資料庫](#鍵-值對的資料庫) + * [文件類型資料庫](#文件類型資料庫) + * [列儲存型資料庫](#列儲存型資料庫) + * [圖形資料庫](#圖形資料庫) + * [SQL 或 NoSQL](#sql-或-nosql) +* [快取](#快取) + * [客戶端快取](#客戶端快取) + * [CDN 快取](#cdn-快取) + * [網站伺服器快取](#網站伺服器快取) + * [資料庫快取](#資料庫快取) + * [應用程式快取](#應用程式快取) + * [資料庫查詢級別的快取](#資料庫查詢級別的快取) + * [物件級別的快取](#物件級別的快取) + * [什麼時候要更新快取](#什麼時候要更新快取) + * [快取模式](#快取模式) + * [寫入模式](#寫入模式) + * [事後寫入(回寫)](#事後寫入回寫) + * [更新式快取](#更新式快取) +* [非同步機制](#非同步機制) + * [訊息佇列](#訊息佇列) + * [工作佇列](#工作佇列) + * [背壓機制](#背壓機制) +* [通訊](#通訊) + * [傳輸控制通訊協定(TCP)](#傳輸控制通訊協定tcp) + * [使用者資料流通訊協定 (UDP)](#使用者資料流通訊協定-udp) + * [遠端程式呼叫 (RPC)](#遠端程式呼叫-rpc) + * [具象狀態轉移 (REST)](#具象狀態轉移-rest) +* [資訊安全](#資訊安全) +* [附錄](#附錄) + * [2 的次方表](#2-的次方表) + * [每個開發者都應該知道的延遲數量級](#每個開發者都應該知道的延遲數量級) + * [其他的系統設計面試問題](#其他的系統設計面試問題) + * [真實世界的架構](#真實世界的架構) + * [公司的系統架構](#公司的系統架構) + * [公司的工程部落格](#公司的工程部落格) +* [仍在進行中](#仍在進行中) +* [致謝](#致謝) +* [聯絡資訊](#聯絡資訊) +* [授權](#授權) + +## 學習指南 + +> 基於你面試的時間 (短、中、長) 來複習這些建議的主題。 + +![Imgur](http://i.imgur.com/OfVllex.png) + +**Q: 對於面試者來說,我需要知道這裡所有的知識嗎?** + +**A: 不,如果是為了面試,你不需要知道這裡所有的知識**。 + +在一場面試中,你會被問到什麼問題取決於以下幾點: + +* 你有多少經驗 +* 你的技術背景 +* 你面試什麼職位 +* 你面試什麼公司 +* 你的幸運程度 + +越有經驗的面試者通常被期望瞭解更多系統設計的知識。如果是架構師或團隊負責人則被預期瞭解更多除了個人貢獻以外的知識。頂尖的科技公司通常也會有一次或多次的系統設計面試。 + +面試時,會很廣泛地展開,並在幾個特定領域深入探討。這裡會幫助你了解一些系統設計不同的主題,基於你面試的時間、經驗、職位和公司來調整你所需要涉獵的知識內容。 + +* **短期** - 以系統設計的**廣度**為目標。通過解決**一些**面試題目來練習。 +* **中期** - 以系統設計的**廣度**和**初級深度**為目標。通過解決**很多**面試題目來練習。 +* **長期** - 以系統設計主題的**廣度**和**高級深度**為目標。通過解決**大部分**面試題目來練習。 + +| | 短期 | 中期 | 長期 | +|---------------------------------------------------------------------------------|------|------|--------| +| 閱讀 [系統設計主題的索引](#系統設計主題的索引) 來取得關於系統如何運作的廣泛知識 | :+1: | :+1: | :+1: | +| 閱讀一些你要面試的 [公司的工程部落格](#公司的工程部落格) 文章 | :+1: | :+1: | :+1: | +| 閱讀關於 [真實世界的架構](#真實世界的架構) | :+1: | :+1: | :+1: | +| 複習 [如何解決一個系統設計的面試題目](#如何解決一個系統設計的面試題目) | :+1: | :+1: | :+1: | +| 完成 [系統設計面試題目與解答](#系統設計面試問題與解答) | 一些 | 很多 | 大部分 | +| 完成 [物件導向設計與解答](#物件導向設計面試問題與解答) | 一些 | 很多 | 大部分 | +| 複習 [其他的系統設計面試問題](#其他的系統設計面試問題) | 一些 | 很多 | 大部分 | + +## 如何解決一個系統設計的面試題目 + +> 如何面對一個系統設計的面試題目 + +系統設計是一個**開放式的對話過程**,面試官會期望由你來主導這個對話。 + +你可以使用下面的步驟來引導整個討論過程。為了鞏固這個流程,請使用下面的步驟完成 [系統設計面試題目與解答](#系統設計面試問題與解答) 這個章節。 + +### 第一步:描述使用的場景、限制及假設 + +把問題的需求和範圍等資訊搜集起來。詢問以下問題,讓我們可以明確的定義使用場景和限制,對於提出的假設進行討論: + +* 誰會使用這個系統? +* 他們怎麼使用系統? +* 有多少使用者? +* 系統的作用是什麼? +* 系統的輸入和輸出是什麼? +* 我們預期希望處理多少資料? +* 我們希望每秒處理多少請求? +* 預期的讀、寫比例為何? + +### 第二步:建立一個高階的設計 + +使用重要的元件來建立一個高階的設計。 + +* 畫出主要的元件與其相互連接情況 +* 證明你的想法 + +### 第三步: 設計核心的元件 + +對每一個核心元件進行深入的分析。舉例來說, 如果你被問到 [設計一個短網址的服務](solutions/system_design/pastebin/README.md) ,可以開始討論以下內容: + +* 產生並儲存一個完整網址的 Hash + * [MD5](solutions/system_design/pastebin/README.md) 和 [Base62](solutions/system_design/pastebin/README.md) + * Hash 碰撞 + * SQL 或 NoSQL + * 資料庫的模型 +* 將一個 hash 過後的網址轉換為完整的網址 + * 資料庫查詢 +* API 和物件導向設計 + +### 第四步:評估你的設計 + +確認及指出你的設計的瓶頸與限制,舉例來說,你需要底下幾個元件來擴展你的設計嗎? + +* 負載平衡 +* 水平擴展 +* 快取 +* 資料庫切片 + +針對你的設計討論可能的解決方法與代價。每個設計都有取捨。使用 [可擴展的設計原則](#系統設計主題:從這裡開始) 來處理系統瓶頸。 + +### 快速有效的進行估算 + +你可能被要求針對你的設計進行一些估算,可以參考 [附錄](#附錄) 的一些資源: + +* [使用快速估算法](http://highscalability.com/blog/2011/1/26/google-pro-tip-use-back-of-the-envelope-calculations-to-choo.html) +* [2 的次方表](#2-的次方表) +* [每個開發者都應該知道的延遲數量級](#每個開發者都應該知道的延遲數量級) + +### 相關資源與延伸閱讀 + +查看以下的連結獲得更好的做法: + +* [如何在系統設計的面試中勝出](https://www.palantir.com/2011/10/how-to-rock-a-systems-design-interview/) +* [系統設計的面試](http://www.hiredintech.com/system-design) +* [系統架構與設計的面試介紹](https://www.youtube.com/watch?v=ZgdS0EUmn70) + +## 系統設計面試問題與解答 + +> 常見的系統設計面試問題與相關範例的討論、程式碼以及圖表。 +> +> 相關的解答位於 `解答/` 的資料夾中。 + +| 問題 | | +|-----------------------------------------------------------------------------------------------------|--------------------------------------------------------| +| 設計 Pastebin.com (或 Bit.ly) | [解答](solutions/system_design/pastebin/README.md) | +| 設計一個像是 Twitter 的 timeline (或 Facebook feed)設計一個 Twitter 搜尋功能 (or Facebook 搜尋功能) | [解答](solutions/system_design/twitter/README.md) | +| 設計一個爬蟲系統 | [解答](solutions/system_design/web_crawler/README.md) | +| 設計 Mint.com 網站 | [解答](solutions/system_design/mint/README.md) | +| 設計一個社交網站的資料結構 | [解答](solutions/system_design/social_graph/README.md) | +| 設計一個搜尋引擎使用的鍵值儲存資料結構 | [解答](solutions/system_design/query_cache/README.md) | +| 設計一個根據產品分類的亞馬遜銷售排名 | [解答](solutions/system_design/sales_rank/README.md) | +| 在 AWS 上設計一個百萬用戶等級的系統 | [解答](solutions/system_design/scaling_aws/README.md) | +| 增加一個系統設計的問題 | [貢獻](#如何貢獻) | + +### 設計 Pastebin.com (或 Bit.ly) + +[閱讀練習與解答](solutions/system_design/pastebin/README.md) + +![Imgur](http://i.imgur.com/4edXG0T.png) + +### 設計一個像是 Twitter 的 timeline (或 Facebook feed)設計一個 Twitter 搜尋功能 (or Facebook 搜尋功能) + +[閱讀練習與解答](solutions/system_design/twitter/README.md) + +![Imgur](http://i.imgur.com/jrUBAF7.png) + +### 設計一個爬蟲系統 + +[閱讀練習與解答](solutions/system_design/web_crawler/README.md) + +![Imgur](http://i.imgur.com/bWxPtQA.png) + +### 設計 Mint.com 網站 + +[閱讀練習與解答](solutions/system_design/mint/README.md) + +![Imgur](http://i.imgur.com/V5q57vU.png) + +### 設計一個社交網站的資料結構 + +[閱讀練習與解答](solutions/system_design/social_graph/README.md) + +![Imgur](http://i.imgur.com/cdCv5g7.png) + +### 設計一個搜尋引擎使用的鍵值儲存資料結構 + +[閱讀練習與解答](solutions/system_design/query_cache/README.md) + +![Imgur](http://i.imgur.com/4j99mhe.png) + +### 設計一個根據產品分類的亞馬遜銷售排名 + +[閱讀練習與解答](solutions/system_design/sales_rank/README.md) + +![Imgur](http://i.imgur.com/MzExP06.png) + +### 在 AWS 上設計一個百萬用戶等級的系統 + +[閱讀練習與解答](solutions/system_design/scaling_aws/README.md) + +![Imgur](http://i.imgur.com/jj3A5N8.png) + +## 物件導向設計面試問題與解答 + +> 常見的物件導向面試問題與案例探討、程式碼與圖表。 +> +> 相關的答案為在 `解答/` 目錄中。 + +>**注意: 本章節仍在完善內容中** + +| 問題 | | +|--------------------------|----------------------------------------------------------------------------| +| 設計一個 hash map | [解答](solutions/object_oriented_design/hash_table/hash_map.ipynb) | +| 設計一個 LRU 快取 | [解答](solutions/object_oriented_design/lru_cache/lru_cache.ipynb) | +| 設計一個客服系統 | [解答](solutions/object_oriented_design/call_center/call_center.ipynb) | +| 設計一副牌 | [解答](solutions/object_oriented_design/deck_of_cards/deck_of_cards.ipynb) | +| 設計一個停車場 | [解答](solutions/object_oriented_design/online_chat/online_chat.ipynb) | +| 設計一個環形陣列 | [如何貢獻](#如何貢獻) | +| 增加一個物件導向設計問題 | [如何貢獻](#如何貢獻) | + +## 系統設計主題:從這裡開始 + +你是系統設計的新手嗎? + +首先,你需要對於基本的原則有一定的認識,知道他們是什麼,如何使用,以及他們的優缺點。 + +### 第一步:複習關於可擴展性的影片講座 + +[哈佛大學可擴展性的影片](https://www.youtube.com/watch?v=-W9F__D3oY4) + +* 包含以下主題: + * 垂直擴展 + * 水平擴展 + * 快取 + * 負載平衡 + * 資料庫複寫 + * 資料庫分割 + +### 第二步:複習關於可擴展性的文章 + +[可擴展性](http://www.lecloud.net/tagged/scalability/chrono) + +* 包含以下主題: + * [複製](http://www.lecloud.net/post/7295452622/scalability-for-dummies-part-1-clones) + * [資料庫](http://www.lecloud.net/post/7994751381/scalability-for-dummies-part-2-database) + * [快取](http://www.lecloud.net/post/9246290032/scalability-for-dummies-part-3-cache) + * [非同步](http://www.lecloud.net/post/9699762917/scalability-for-dummies-part-4-asynchronism) + +### 下一步 + +接下來,我們需要看看某些取捨: + +* **效能** vs **可擴展性** +* **延遲** vs **吞吐量** +* **可用性** vs **一致性** + +記住,任何設計都是取捨。 + +接著,我們將會深入更具體的主題,包含 DNS、CDN 和負載平衡。 + +## 效能與可擴展性 + +如果服務**性能**的增加和資源的投入是成正比時,代表服務是可擴展的。一般來說,增加性能代表服務更多的工作單元,也可以處理更多的資料。1 + +從另一方面來看看性能與可擴展性: + +* 如果你的系統存在**性能**問題時,對單一使用者來說的感覺是慢的。 +* 如果你的系統存在**可擴展性**問題時,對於單一使用者來說感覺較快,但在高負載的時候就會變慢。 + +### 來源及延伸閱讀 + +* [簡談可擴展性](http://www.allthingsdistributed.com/2006/03/a_word_on_scalability.html) +* [可擴展性、可用性、穩定性與相關模式](http://www.slideshare.net/jboner/scalability-availability-stability-patterns/) + +## 延遲與吞吐量 + +**延遲** 指執行一個操作或運算結果所花費的時間。 + +**吞吐量** 指單位時間內執行此類型操作或運算的數量。 + +一般來說,你應該以**可接受的延遲**數量下的**最大化吞吐量**為設計目標。 + +### 來源及延伸閱讀 + +* [了解延遲與吞吐量](https://community.cadence.com/cadence_blogs_8/b/sd/archive/2010/09/13/understanding-latency-vs-throughput) + +## 可用性與一致性 + +### CAP 理論 + +

+ +
+ 來源:再看 CAP 理論 +

+ +在一個分散式系統中,只能滿足以下三個項目的任兩項: + +* **一致性** - 每次讀取都可以得到最新的資料,但偶爾會拿到錯誤 +* **可用性** - 每次讀取都可以得到非錯誤的回應,但不能保證可以得到最新的資料 +* **部分容錯性** - 在任意分區的網路故障情況下,系統仍然能夠持續運行 + +*網路是不可靠的,你的設計必須要確保部分容錯性,所以你只能夠在一致性與可用性中做出取捨。* + +#### CP-一致性與部分容錯性 + +等待分區的節點回覆可能會導致超時錯誤,如果你的系統的需求是需要保證原子讀寫時,CP 是一個不錯的選擇。 + +#### AP-可用性與部分容錯性 + +每個進行回覆的節點中的最新版本可能不是最新的,當分區節點解析完畢後,寫入的操作可能需要一些時間來傳播資料。 + +當你的系統需求需要保證 [最終一致性](#最終一致性) ,或當外部系統故障時,系統要能夠繼續運作時,AP 是一個不錯的選擇。 + +### 來源及延伸閱讀 + +* [複習 CAP 理論](http://robertgreiner.com/2014/08/cap-theorem-revisited/) +* [簡單的介紹 CAP 理論](http://ksat.me/a-plain-english-introduction-to-cap-theorem/) +* [CAP 問與答](https://github.com/henryr/cap-faq) + +## 一致性模式 + +當你的資料有多個副本時,要考慮怎麼同步他們,以便讓使用者有一致的資料顯示。想想 [CAP 理論](#cap-理論) 中的一致性定律 - 每次的訪問都可以得到最新的資料,但可能也會收到錯誤的回應。 + +### 弱一致性 + +在寫入之後,任何的存取不一定可以拿到資料,弱一致性將盡力確保能存取到最新的資料。 + +這種方式可以在 memcached 等系統中看到。弱一致性可以在 VoIP、視訊聊天或其他即時多人線上遊戲中看到相關的使用案例。比方說,如果你在通話中遺失幾秒鐘時間的資料,再重新連接後,你是無法聽到這幾秒鐘的內容。 + +### 最終一致性 + +在寫入後的讀取操作最終可以看到被寫入的資料(通常在數毫秒內)。資料透過非同步的方式被複製。 + +DNS 或是電子郵件系統使用的就是這種方式,最終一致性在高可用的系統中效果很好。 + +### 強一致性 + +在寫入後,讀取將立刻取得資料,資料是透過同步的方式寫入。 + +檔案系統或資料庫系統就是使用這種方式,強一致性在需要紀錄的系統中表現很好。 + +### 來源及延伸閱讀 + +* [資料中心的記錄行為](http://snarfed.org/transactions_across_datacenters_io.html) + +## 可用性模式 + +關於可用性有兩種模式:**容錯轉移** 和 **複寫**。 + +### 容錯轉移 + +#### 主動到備用切換模式(AP Mode) + +在這個模式下,heartbeat 訊號會在主動和備用的機器中發送,當 heartbeat 中斷時,備用的機器就會切換為主動機器的 IP 位置接替服務。 + +當機的時間取決於備用的機器是在「熱」待機狀態還是「冷」待機狀態。只有處於主動的機器會處理使用者來的流量。 + +這個模式的切換也被稱為主從的切換模式。 + +#### 雙主動切換模式(AA Mode) + +在此模式下,兩台伺服器都會負責處理流量,流量會在他們之間進行分散負載。 + +如果是外部網路的伺服器,DNS 需要知道兩台機器的 IP 位置,如果是內部網路的伺服器,應用程式邏輯需要知道這兩台機器。 + +雙主動切換模式也被稱為 master-master 切換。 + +### 缺點:容錯轉移 + +* 容錯轉移會需要增加額外的硬體與複雜度。 +* 如果在新寫入的資料被複製到備用的機器前系統就發生故障,那有可能會遺失資料。 + +### 複寫機制 + +#### 主動到備用複寫與雙主動複寫 + +這一個主題進一步討論了 [資料庫](#資料庫) 部分: + +* [主動到備用複寫](#主動到備用複寫) +* [雙主動複寫](#雙主動複寫) + +## 域名系統 + +

+ +
+ 資料來源:DNS 安全介紹 +

+ +DNS 是將域名轉換為 IP 地址的系統。 + +DNS 是階層式的架構,一部分的 DNS 伺服器位於頂層,當查詢域名時,你的路由器或 ISP 業者會提供連接到 DNS 伺服器的資訊。較底層的 DNS 伺服器會快取查詢的結果,而這些快取資訊會因為 DNS 的傳遞而逐漸更新。DNS 的結果可以暫存在瀏覽器或操作系統中一段時間,時間的長短取決於 [存活時間(TTL)](https://en.wikipedia.org/wiki/Time_to_live) 的設定。 + +* **NS 記錄 (域名伺服器)** - 指定解析域名或子域名的 DNS 伺服器。 +* **MX 記錄 (電子郵件交換伺服器)** - 指定接收電子郵件的伺服器。 +* **A 記錄 (地址)** - 指向要對應的 IP 位置。 +* **CNAME (別名)** - 從一個域名指向另外一個域名,或是 `CNAME` (example.com 指向 www.example.com) 或指向一個 `A` 記錄。 + +[CloudFlare](https://www.cloudflare.com/dns/) 和 [Route 53](https://aws.amazon.com/route53/) 提供了 DNS 的服務。而這些 DNS 服務商透過以下幾種方式來決定流量如何被分派: + +* [加權輪詢](http://g33kinfo.com/info/archives/2657) + * 防止流量進入正在維修中的伺服器 + * 在不同大小的集群中進行負載平衡 + * A/B 測試 +* 基於延遲來路由請求 +* 基於地理位置來路由請求 + +### DNS 的缺點 + +* 儘管可以透過快取來減輕 DNS 的延遲,但連接 DNS 伺服器還是帶來了些許的延遲。 +* DNS 伺服器的管理是複雜的,儘管他通常由 [政府、ISP 業者或大公司](http://superuser.com/questions/472695/who-controls-the-dns-servers/472729) 來處理。 +* DNS 伺服器會有 [DDoS 攻擊](http://dyn.com/blog/dyn-analysis-summary-of-friday-october-21-attack/) ,讓不知道 Twitter IP 的使用者無法訪問 Twitter 網站。 + +### 來源及延伸閱讀 + +* [DNS 架構](https://technet.microsoft.com/en-us/library/dd197427(v=ws.10).aspx) +* [維基百科](https://en.wikipedia.org/wiki/Domain_Name_System) +* [DNS 文章](https://support.dnsimple.com/categories/dns/) + +## 內容傳遞網路(CDN) + +

+ +
+ 來源:為什麼要使用 CDN +

+ +內容傳遞網路(CDN)是一種全球性的分散式代理伺服器,它透過靠近使用者的伺服器來提供檔案。通常 HTML/CSS/JS、圖片或影片等檔案會靜態檔案會透過 CDN 來提供,儘管 Amazon 的 CloudFront 也支援了動態內容的 CDN 服務。而 CDN 的 DNS 服務會告知使用者要連接哪一台伺服器。 + +透過 CDN 來取得檔案可以大幅度地增加請求的效率,因為: + +* 從靠近使用者的伺服器來拿檔案 +* 透過 CDN 來回應使用者,你的原始伺服器不需要處理請求 + +### 推送式 CDNs + +當你的伺服器有檔案變動時,推送 CDN 會接收到新的變動內容,並重寫 URL 位置指向新的內容。你可以設定檔案內容什麼時候過期以及何時更新,檔案內容只有在變更或新增的時候才會推送,最小化流量,但最大化儲存。 + +流量較小的網站,或是內容不是經常更新的網站使用推送式的 CDN 相當適合,因為內容會被經常放置在 CDN 內,而不是常常需要重新抓取新檔案。 + +### 拉取式 CDNs + +拉取式的 CDN 指的是當地一個使用者來請求該資源時,才從伺服器上抓取對應檔案。將檔案留在伺服器上並且重寫指向 CDN 的 URL,直到檔案被快取在 CDN 上為止,請求都會比較慢。 + +[存活時間 (TTL)](https://en.wikipedia.org/wiki/Time_to_live) 決定檔案要被緩存多久的時間。拉取式 CDN 可以節省儲存空間,但在過期的文件被更新之前,則會導致多餘的流量。 + +拉取式的 CDN 適合高流量的網站,因為檔案會被平均的分散在各個結點伺服器中。 + +### CDN 的缺點 + +* CDN 的成本取決於流量,在權衡評估後,你可能會因為成本而放棄使用。 +* 如果在 TTL 過期之前就更新內容,CDN 的緩存內容可能會過期。 +* 需要改變靜態內容的網址來指向 CDN。 + +### 來源及延伸閱讀 + +* [全球性的 CDN](http://repository.cmu.edu/cgi/viewcontent.cgi?article=2112&context=compsci) +* [拉取式和推拉式 CDN 的差別](http://www.travelblogadvice.com/technical/the-differences-between-push-and-pull-cdns/) +* [維基百科](https://en.wikipedia.org/wiki/Content_delivery_network) + +## 負載平衡器 + +

+ +
+ 來源:可擴展的系統設計模式 +

+ +負載平衡將使用者的請求分發到後端伺服器和資料庫,不管是哪種情況,負載平衡器會將回應返回給對應的使用者。而負載平衡器之所以有效在於以下幾點: + +* 避免請求被轉到非正常運作的伺服器 +* 避免資源過載 +* 避免單點失敗 + +負載平衡器可以透過硬體(較昂貴)或 HAProxy 等軟體來實現。 + +其餘額外的好處有: + +* **SSL 終結** - 將傳入的請求解密,並且加密伺服器的回應,如此一來後端伺服器就不需要進行這些高度消耗資源的運算 + * 不需要在每一台機器上安裝 [X.509 憑證](https://en.wikipedia.org/wiki/X.509)。 +* **Session 保存** - 發行 cookie,並將特定使用者的請求路由到同樣的後端伺服器上。 + +為了避免故障,通常會採用 [主動到備用切換模式](#主動到備用切換模式(AP Mode)) 或 [雙主動切換模式](#雙主動切換模式(AA Mode)) 這樣多個負載平衡器的模式。 + +負載平衡器會基於多種方法來路由請求: + +* 隨機 +* 最少負載 +* Session/cookies +* [輪詢調度或加權輪詢調度](http://g33kinfo.com/info/archives/2657) +* [第四層負載平衡](#第四層負載平衡) +* [第七層負載平衡](#第七層負載平衡) + +### 第四層負載平衡 + +第四層的負載平衡器會監看 [傳輸層](#傳輸層) 的資訊來決定如何分發請求。一般來說,這包含了來源、目標 IP 位置,以及在 header 中的 port,但不包含資料本身的內容。第四層的負載平衡器會透過 [網路地址轉換(NAT)](https://www.nginx.com/resources/glossary/layer-4-load-balancing/) 來向上游的伺服器轉發資料。 + +### 第七層負載平衡 + +第七層的負載平衡器會監看 [應用層](#應用層) 來決定如何分發請求。這包含了請求的 header、訊息和 cookies。這種負載平衡器會終結網路的流量、讀取訊息並做出如何轉發訊息的決定,並把流量轉往對應的伺服器。舉例來說,一個第七層的負載平衡器可以將影音的流量轉往負責影音流量的伺服器,而將更敏感的使用者帳單的請求轉往安全性更強的伺服器。 + +第四層的負載平衡比起第七層的所要花費的時間和計算資源更低,雖然這對於現代商用硬體的性能影響已經微乎其微了。 + +### 水平擴展 + +負載平衡器一樣可以幫助水平擴展,提高性能與可用性。使用這種方式的擴展比起在單一機器的**垂直擴展**來說性價比更高,同時,聘請商用硬體的人才比起特定企業級系統人才來的更加容易。 + +#### 水平擴展的缺點 + +* 水平擴展會增加複雜性,同時也涉及了多台伺服器的議題 + * 伺服器應該是無狀態的:不應該包括像是 session 或資料圖片等和使用者相關的內容 + * Session 可以集中儲存在資料庫或 [快取](#快取)(Redis、Memcached) 等資料儲存中。 +* 快取伺服器或資料庫需要隨著伺服器的增加而進行擴展,以便處理更多的請求。 + +### 負載平衡器的缺點 + +* 當負載平衡器資源不夠或沒有正確設定時,他可能會成為效能的瓶頸 +* 使用負載平衡器來避免單點失敗會增加架構的複雜性 +* 只有一台負載平衡器時,一樣有單點失敗的問題。而多台的負載平衡器一樣增加了架構的複雜性。 + +### 來源及延伸閱讀 + +* [NGINX 架構](https://www.nginx.com/blog/inside-nginx-how-we-designed-for-performance-scale/) +* [HAProxy 架構指南](http://www.haproxy.org/download/1.2/doc/architecture.txt) +* [可擴展性](http://www.lecloud.net/post/7295452622/scalability-for-dummies-part-1-clones) +* [維基百科](https://en.wikipedia.org/wiki/Load_balancing_(computing)) +* [第四層負載平衡](https://www.nginx.com/resources/glossary/layer-4-load-balancing/) +* [第七層負載平衡](https://www.nginx.com/resources/glossary/layer-7-load-balancing/) +* [ELB 監聽器設定](http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-listener-config.html) + +## 反向代理(網頁伺服器) + +

+ +
+ 來源:維基百科 +
+

+ +反向代理伺服器是一個集中內部服務,並提供統一個介面給公開使用者的伺服器。來自客戶端的請求會先被反向代理伺服器轉發到可以接收服務的伺服器,然後再由代理伺服器將結果返回給客戶端。 + +這樣做的好處有: + +* **增加安全性** - 隱藏後端伺服器的資訊、可以設定 IP 的黑名單、限制每個客戶端的連線數量等。 +* **增加可擴展性與靈活性** - 客戶端只會看到反向代理伺服器的 IP 或域名,這樣你就可以增加背後伺服器的數量或設定而不影響客戶端。 +* **SSL 終止** - 解密傳入的請求、加密伺服器的回應,這樣後端伺服器就不需要進行這些高成本的操作 + * 不需要在每一台伺服器安裝 [X.509 憑證](https://en.wikipedia.org/wiki/X.509)。 +* **壓縮** - 壓縮伺服器的回應 +* **快取** - 直接在代理伺服器回應命中快取的結果 +* **靜態檔案** - 直接提供靜態內容 + * HTML/CSS/JS + * 圖片 + * 影片 + * 等等 + +### 負載平衡器與反向代理伺服器 + +* 當有多台伺服器時,使用負載平衡非常有用,一般來說,負載平衡器會將流量路由給一組功能相同的伺服器上。 +* 即使只有一台伺服器或應用伺服器,反向代理也是有用的。可以參考上述的好處。 +* Nginx 或 HAProxy 等解決方案可以同時支援第七層的反向代理與負載平衡 + +### 反向代理伺服器的缺點 + +* 引入反向代理伺服器會增加系統複雜度。 +* 只有一台反向代理伺服器會有單點失效的問題,而設定多台的反向代理伺服器(如 [故障轉移](https://en.wikipedia.org/wiki/Failover) )同樣會增加系統複雜度。 + +### 來源與延伸閱讀 + +* [反向代理伺服器與負載平衡](https://www.nginx.com/resources/glossary/reverse-proxy-vs-load-balancer/) +* [NGINX 架構](https://www.nginx.com/blog/inside-nginx-how-we-designed-for-performance-scale/) +* [HAProxy 架構指南](http://www.haproxy.org/download/1.2/doc/architecture.txt) +* [維基百科](https://en.wikipedia.org/wiki/Reverse_proxy) + +## 應用層 + +

+ +
+ 資料來源:可縮放式系統架構介紹 +

+ +將 Web 服務層與應用層(也被稱為平台層)分離,如此一來這兩層就可以獨立縮放與設定,增加新的 API 服務只需要增加應用伺服器,而不需要增加額外的 Web 伺服器。 + +**單一職責原則**鼓勵小型、自治的服務與共同合作,小型團隊透過提供小型的服務可以更有效率地讓計畫成長。 + +在應用層中的工作程式可以實作 [非同步機制](#非同步機制) + +### 微服務 + +相關的主題還有 [微服務](https://en.wikipedia.org/wiki/Microservices) ,指的是可以獨立運作、小型的模組化服務。每個服務會透過明確定義好的輕量級溝通機制,運作在一個獨立的流程中來共同實現一個目標。1 + +舉例來說,Pinterest 可能有以下這些微服務:使用者資料、跟隨者、Feed、搜尋、照片上傳等等。 + +### 服務發現 + +[Consul](https://www.consul.io/docs/index.html)、[Etcd](https://coreos.com/etcd/docs/latest), 或是 [Zookeeper](http://www.slideshare.net/sauravhaloi/introduction-to-apache-zookeeper) 等系統可以透過註冊的名稱、位置、Port 等資訊來幫助各個服務發現彼此。[Health checks](https://www.consul.io/intro/getting-started/checks.html) 可以幫助確認服務的完整性以及是否經常使用一個 [HTTP](#hypertext-transfer-protocol-http) 的路徑。[鍵-值對的資料庫](#鍵-值對的資料庫) 則用來儲存設定的資訊與其他共享的資料。 + +### 應用層的缺點 + +* 設計多個鬆耦合微服務所組成的應用層,必須從架構、維運、流程等多個面向來考量,相對於單系統而言會非常不同。 +* 微服務會增加部署與維運的複雜度。 + +### 來源與延伸閱讀 + +* [可擴展式系統架構介紹](http://lethain.com/introduction-to-architecting-systems-for-scale) +* [破解系統設計面試](http://www.puncsky.com/blog/2016-02-13-crack-the-system-design-interview) +* [面向服務架構](https://en.wikipedia.org/wiki/Service-oriented_architecture) +* [Zookeeper 介紹](http://www.slideshare.net/sauravhaloi/introduction-to-apache-zookeeper) +* [建構微服務系統你所需要知道的一切](https://cloudncode.wordpress.com/2016/07/22/msa-getting-started/) + +## 資料庫 + +

+ +
+ 來源:擴展你的使用者數量到第一個一千萬量級 +

+ +### 關連式資料庫管理系統(RDBMS) + +像 SQL 這種關連式資料庫是以一組表格的形式存在的資料集合。 + +**ACID** 是用來描述資料庫 [事務](https://en.wikipedia.org/wiki/Database_transaction) 的特性。 + +* **原子性** - 每一個資料庫事務操作要不就是全部完成,要不就是全部不完成。 +* **一致性** - 任何一個資料庫事務操作都會讓資料庫從一個有效的狀態轉換到另外一個有效狀態。 +* **隔離性** - 併發執行資料庫事務操作的結果會和循序執行的結果一致。 +* **持久性** - 一旦一個事務被資料庫執行後,他的結果與影響是擁永久保存的。 + +要針對關聯式資料庫系統進行擴展有許多方法: **主從複寫**, **主動模式複寫**, **聯邦式資料庫**, **分片**, **反正規化**, 和 **SQL 優化**. + +#### 主從複寫 + +主資料庫負責讀和寫,並且將寫入的資料複寫至一或多個從屬資料庫中,從屬資料庫只負責讀取。而從屬資料庫可以再將寫入複製到更多以樹狀結構的其他資料庫中。如果主資料庫離線了,系統可以以只讀模式運行,直到某個從屬資料庫被提升為主資料庫,或有新的主資料庫出現。 + +

+ +
+ 來源: 可擴展性、可用性、穩定性及其模式 +

+ +##### 主從複寫的缺點 + +* 需要額外的處理邏輯來將從屬資料庫提升為主要資料庫。 +* 參考 [複寫的缺點](#複寫的缺點) 章節,你可以看到主動模式複寫與主從模式**共同**的缺點。 + +#### 主動模式複寫 + +兩個主要的資料庫都負責讀取和寫入,並且兩者互相協調。如果其中一個主要資料庫離線,系統可以繼續運作。 + +

+ +
+ 來源: 可擴展性、可用性、穩定性及其模式 +

+ +##### 主動模式的缺點 + +* 你需要一個負載平衡器來或是在你的應用程式邏輯中做修改來決定要寫入哪個資料庫。 +* 大多數的主動模式資料庫無法保證一致性(違反 ACID),或是會因為同步而產生了寫入延遲。 +* 隨著更多寫入節點的增加和延遲的提高,如何解決衝突就顯得更加重要。 +* 參考 [複寫的缺點](#複寫的缺點) 章節,你可以看到主動模式複寫與主從模式**共同**的缺點。 + +##### 複寫的缺點 + +* 如果在主要資料庫複製到其他結點前系統就失效,則會有資料丟失的可能。 +* 當有過多寫入時,讀取的資料庫可能會因為過多寫入操作而被阻塞,導致讀取功能異常。 +* 當讀取的資料庫越多時,需要複寫的資料越多,將會導致較為嚴重的延遲。 +* 在某些資料庫系統中,寫入主資料庫的操作可以用多執行緒來並行寫入,但讀取的資料庫只支援單一執行緒來循序寫入。 +* 複寫意味著更多的硬體以及更高的複雜度。 + +##### 來源及延伸閱讀 + +* [可擴展性、可用性、穩定性及其模式](http://www.slideshare.net/jboner/scalability-availability-stability-patterns/) +* [多主要資料庫複寫](https://en.wikipedia.org/wiki/Multi-master_replication) + +#### 聯邦式資料庫 + +

+ +
+ 來源:擴展你的使用者數量到第一個一千萬量級 +

+ +聯邦式資料庫(或是指功能式切分)是將資料庫按照對應的功能進行分割。例如:你可以三個資料庫,分別是:**論壇**、**使用者**和**產品**,而不僅僅是單一資料庫。這樣會減少每個資料庫寫入與讀取的流量,進而降低複製的延遲。較少的資料意味者更多適合放入記憶體中的資料,進而增加快取命中率。因為沒有循序寫入的中央式主資料庫,你可以並行寫入以增加吞吐量。 + +##### 聯邦式資料庫的缺點 + +* 如果你的資料表需要大量的功能和資料表,聯邦式資料庫的效率並不好。 +* 需要更新應用程式的邏輯來決定如何讀取和寫入到哪個資料庫。 +* 透過 [server link](http://stackoverflow.com/questions/5145637/querying-data-by-joining-two-tables-in-two-database-on-different-servers) 從兩個資料庫中關資料更加複雜。 +* 聯邦式資料庫需要更多的硬體和額外的複雜度。 + +##### 來源及延伸閱讀 + +* [來源:擴展你的使用者數量到第一個一千萬量級](https://www.youtube.com/watch?v=vg5onp8TU6Q) + +#### 分片 + +

+ +
+ 來源: 可擴展性、可用性、穩定性及其模式 +

+ +分片是指將資料分配在不同的資料庫上,使每個資料庫只管理整個資料的部分子集。以使用者資料庫為例,隨著使用者數量的增加,越來越多的分片會被加入到群集當中。 + +類似於 [聯邦式資料庫](#聯邦式資料庫) 的優點,分片可以減少讀取和寫入的流量、減少複製並提高快取命中率。索引的容量也會減少,如此一來可以改善查詢的效能。當一個分片出現問題時,其餘的仍然可以正常運作,而為了避免資料遺失,你可能需要思考其他複寫的機制。如同聯邦式資料庫,分片的機制並沒有中央式的資料庫,你可以並行寫入以增加吞吐量。 + +以使用者資料庫為例,常見的做法是用使用者姓氏的部首或使用者地理問位置來區隔使用者資料表。 + +##### 分片的缺點 + +* 你需要修改應用程式的邏輯來實作分片,這可能會導致 SQL 變得複雜。 +* 不合理的分片可能會導致資料負載不均,例如,頻繁被訪問的使用者資料如果被放置在同一個分片中,會導致該分片負載相對較高。 + * 再平衡會需要額外的複雜度。基於 [一致性 hash](http://www.paperplanes.de/2011/12/9/the-magic-of-consistent-hashing.html) 的分片演算法可以減少這種情形。 +* 從多個分片中操作資料會很複雜。 +* 分片需要額外的硬體和複雜度。 + +##### 來源及延伸閱讀 + +* [分片時代來臨](http://highscalability.com/blog/2009/8/6/an-unorthodox-approach-to-database-design-the-coming-of-the.html) +* [分片資料庫架構](https://en.wikipedia.org/wiki/Shard_(database_architecture)) +* [一致性 hashing](http://www.paperplanes.de/2011/12/9/the-magic-of-consistent-hashing.html) + +#### 反正規化 + +反正規化嘗試以寫入的性能作為代價來改善讀取性能。透過在不同資料表中的重複資料來避免高成本的 Join 操作。 + +某些關連式資料庫,例如 [PostgreSQL](https://en.wikipedia.org/wiki/PostgreSQL) 和 Oracle 支援 [materialized views](https://en.wikipedia.org/wiki/Materialized_view) ,可以用來處理重複資料的儲存,以及保證這些資料的一致性。 + +一旦資料使用如 [聯合](#聯合) 或 [切片](#切片) 等技術被分割,處理跨資料中心 Join 操作的複雜度。反正規化可以避免這種複雜的操作。 + +在多數系統中,讀取的操作頻率會遠高於寫入的頻率,比例可能會到 100:1 甚至 1000:1。進行複雜讀取操作的成本很高,會在硬碟上消耗大量的時間。 + +##### 反正規化的缺點 + +* 資料會重複存取 +* Constraints 的機制可以讓重複的資料保持同步,但這樣會增加資料庫設計的複雜度。 +* 反正規化的資料庫在大量寫入負載的情況下,性能表現可能會比正規化的資料庫差。 + +###### 來源及延伸閱讀 + +* [反正規化](https://en.wikipedia.org/wiki/Denormalization) + +#### SQL 優化 + +SQL 優化是一個涵蓋範圍很廣的主題,有許多相關的 [參考書籍](https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=sql+tuning) 可以做為參考。 + +透過 **效能測試** 和 **效能分析** 來模擬並發現系統的瓶頸是很重要的。 + +* **效能測試** - 透過 [ab](http://httpd.apache.org/docs/2.2/programs/ab.html) 等工具來測試高負載的情況。 +* **效能分析** - 使用 [slow query log](http://dev.mysql.com/doc/refman/5.7/en/slow-query-log.html) 等工具來追蹤性能問題。 + +效能測試和效能分析可能會引導你到以下的優化方案。 + +##### 使用較為精準的 schema + +* 為了加快存取速度,MySQL 會在硬碟上使用連續的 block 來儲存資料。 +* 使用 `CHAR` 來儲存固定長度的資料,不要使用 `VARCHAR`。 + * `CHAR` 在快速、隨機存取時效率很高。如果使用 `VARCHAR`,想要讀取下一個字元時,需要先讀取到目前字元的尾端。 +* 使用 `TEXT` 來儲存大量的文字,例如部落格文章。`TEXT` 還可以使用布林搜尋。使用 `TEXT` 時,會在硬碟上保存一個指向硬碟區塊的指標。 +* 使用 `INT` 來儲存數量級達到 2^32 或 40 億等較大的數字。 +* 使用 `DECIMAL` 來儲存貨幣資料可以避免浮點數表達錯誤。 +* 避免儲存龐大的 `BLOBS`,取而代之的,應該儲存存放該對象的位置。 +* `VARCHAR(255)` 是使用 8 位數來儲存時的最大表示法,在某些關連式資料庫中,要最大限度地使用它。 +* 在適用的情況下設定 `NOT NULL` 來 [提高搜尋性能](http://stackoverflow.com/questions/1017239/how-do-null-values-affect-performance-in-a-database-search)。 + +##### 使用正確的索引 + +* 當你使用 (`SELECT`, `GROUP BY`, `ORDER BY`, `JOIN`) 這些操作的對應欄位如果有使用索引就會查詢更快。 +* 索引通常是使用平衡 [B 樹](https://en.wikipedia.org/wiki/B-tree) 表示,這樣可以保證資料是有序的,並允許在對數時間內進行搜尋、循序訪問以及插入、刪除等操作。 +* 設定索引時,會將資料放置於記憶體中,會佔用更多記憶體空間。 +* 寫入操作會變慢,因為索引會需要更新。 +* 當讀取大量資料時,禁用索引再讀取,之後再重新建立索引,這樣也許會更快。 + +##### 避免高成本的 Join 操作 + +* 有性能需求時,可以進行 [反正規化](#反正規化)。 + +##### 分割資料表 + +* 將熱門的資料拆分到單獨的資料表中可以增加快取。 + +##### 調整查詢的快取 + +* 在某些情況下,[查詢快取](http://dev.mysql.com/doc/refman/5.7/en/query-cache) 可能會導致 [性能問題](https://www.percona.com/blog/2014/01/28/10-mysql-performance-tuning-settings-after-installation/)。 + +##### 來源及延伸閱讀 + +* [MySQL 查詢優化小提示](http://20bits.com/article/10-tips-for-optimizing-mysql-queries-that-dont-suck) +* [為什麼使用 VARCHAR(255) 很常見](http://stackoverflow.com/questions/1217466/is-there-a-good-reason-i-see-varchar255-used-so-often-as-opposed-to-another-l) +* [Null 值是如何影響資料庫性能](http://stackoverflow.com/questions/1017239/how-do-null-values-affect-performance-in-a-database-search) +* [慢 SQL log 查詢](http://dev.mysql.com/doc/refman/5.7/en/slow-query-log.html) + +### NoSQL + +NoSQL 指的是 **鍵-值對的資料庫**、**文件類型資料庫**、**列儲存型資料庫** 和 **圖形資料庫** 等的統稱。資料是非正規化的,Join 大部分在應用端完成。大多數的 NoSQL 資料庫無法真正實現 ACID 的 transaction,他們通常會支援 [最終一致性](#最終一致性)。 + +**BASE** 通常被用來描述 NoSQL 資料庫的特性。 跟 [CAP 理論](#cap 理論) 相比,BASE 強調可用性而非一致性。 + +* **基本可用** - 系統保證可用性。 +* **軟狀態** - 系統的狀態可能隨著時間改變,即使在沒有輸入的情況下也是如此。 +* **最終一致性** - 經過一段時間之後,在沒有收到任何輸入的情況下,系統最終會達到一致。 + +除了在 [SQL 或 NoSQL](#sql-或-nosql) 之間做選擇,了解哪種類型的 NoSQL 資料庫最適合你的需求也是很有幫助的。我們會在下一節中快速瞭解一下 **鍵-值對的資料庫**、**文件類型資料庫**、**列儲存型資料庫** 和 **圖形資料庫** 等資料庫。 + +#### 鍵-值對的資料庫 + +> 抽象模型:hash table + +一個鍵值對的資料庫通常可以實現 O(1) 時間內的讀寫,同時,它的背後通常使用記憶體或 SSD 當作儲存媒介。資料在儲存時,可以按照 [字典順序](https://en.wikipedia.org/wiki/Lexicographical_order) 來維護鍵的數值,進而實踐鍵數值的高效率檢索。鍵值對的資料庫也可以用來儲存值的 metadata。 + +鍵值對資料庫的效能很好,通常用來儲存簡單的資料模型或是頻繁修改的資料,如放在記憶體中的快取層。鍵值對資料庫所提供的操作有限,如果要進行更多操作,會將其放在應用端進行。 + +鍵值對的資料庫在某些情況下,是更複雜系統的基礎,例如圖形資料庫或是文件類型的資料庫。 + +##### 來源及延伸閱讀 + +* [鍵值對資料庫](https://en.wikipedia.org/wiki/Key-value_database) +* [鍵值對資料庫的缺點](http://stackoverflow.com/questions/4056093/what-are-the-disadvantages-of-using-a-key-value-table-over-nullable-columns-or) +* [Redis 架構](http://qnimate.com/overview-of-redis-architecture/) +* [Memcached 架構](https://www.adayinthelifeof.nl/2011/02/06/memcache-internals/) + +#### 文件類型資料庫 + +> 抽象模型:將文件當做值的鍵值對資料庫 + +文件類型的資料庫是以文件 (XML、JSON、二進制檔案等) 為核心,文件本身儲存了對應物件的所有資訊。這種類型的資料庫提供了 API 或相關的查詢方法來根據儲存物件本身的特性來實現查詢功能。請注意,許多鍵值對資料庫有儲存 metadata 的特性,這也模糊了這兩種資料庫之間的界線。 + +根據底層實作的不同,文件資料庫可以根據集合、標籤、metadata 或目錄等來組織而成。儘管不同的文件可以被組織在一起或是分成一組,但彼此之間可能具有完全不同的內容。 + +某些文件型資料庫,例如 [MongoDB](https://www.mongodb.com/mongodb-architecture) 和 [CouchDB](https://blog.couchdb.org/2016/08/01/couchdb-2-0-architecture/) 同樣提供了類似於 SQL 查詢語句的功能來實現複雜的查詢。[DynamoDB](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/decandia07dynamo.pdf)則同時支援了鍵值對儲存和文件類型儲存的功能。 + +文件類型的資料庫具備高度靈活性,通常用於處理偶爾變化的資料。 + +##### 延伸閱讀 + +* [文件類型的資料庫](https://en.wikipedia.org/wiki/Document-oriented_database) +* [MongoDB 架構](https://www.mongodb.com/mongodb-architecture) +* [CouchDB 架構](https://blog.couchdb.org/2016/08/01/couchdb-2-0-architecture/) +* [Elasticsearch 架構](https://www.elastic.co/blog/found-elasticsearch-from-the-bottom-up) + +#### 列儲存型資料庫 + +

+ +
+ 來源:SQL 和 NoSQL,簡短的歷史介紹 +

+ +> 抽象模型: 巢狀的 Map `ColumnFamily>` + +列儲存型資料庫的基本單元是一列 (名稱/值為一組)。每一列可以被分到一個列的族群中(類似於 SQL 中的資料表)。而每個列族群之上還可以有一個超級列群。你可以透過列的鍵值來存取每一列,每個值都有一個時間戳記來解決版本問題。 + +Google 發表了第一個列儲存型資料庫 [Bigtable](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/chang06bigtable.pdf),這影響了用於 Hadoop 系統中開源的 [HBase](https://www.mapr.com/blog/in-depth-look-hbase-architecture) often-used in the Hadoop ecosystem, 和 Facebook 的 [Cassandra](http://docs.datastax.com/en/archived/cassandra/2.0/cassandra/architecture/architectureIntro_c.html)。這些資料庫的儲存系統把鍵值利用字母順序來儲存,可以有效率的來讀取。 + +列儲存型態的資料的提供了高可用和高擴展性,通常被用在大量資料的儲存上。 + +##### 來源及延伸閱讀 + +* [SQL 和 NoSQL 歷史簡介](http://blog.grio.com/2015/11/sql-nosql-a-brief-history.html) +* [Bigtable 架構](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/chang06bigtable.pdf) +* [HBase 架構](https://www.mapr.com/blog/in-depth-look-hbase-architecture) +* [Cassandra 架構](http://docs.datastax.com/en/archived/cassandra/2.0/cassandra/architecture/architectureIntro_c.html) + +#### 圖形資料庫 + +

+ +
+ 來源: 圖形化資料庫 +

+ +> 抽象模型:圖 + +在圖形資料庫中,每一個節點會對應一條紀錄,而每個邊描述兩個節點之間的關係。圖形資料庫針對表示外來鍵(Foreign Key)眾多的複雜關聯或多對多關聯進行優化。 + +圖形資料庫為了儲存複雜的資料結構,例如社群網路,提供了很高的性能。他們相對較新,尚未被廣泛使用,查詢工具或資源比較難取得,許多這種類型的資料庫只能透過 [REST API](#representational-state-transfer-rest) 來存取。 + +##### 來源及延伸閱讀 + +* [圖形資料庫](https://en.wikipedia.org/wiki/Graph_database) +* [Neo4j](https://neo4j.com/) +* [FlockDB](https://blog.twitter.com/2010/introducing-flockdb) + +#### 來源及延伸閱讀:NoSQL + +* [資料庫術語解釋](http://stackoverflow.com/questions/3342497/explanation-of-base-terminology) +* [NoSQL 資料庫:調查與決策指南](https://medium.com/baqend-blog/nosql-databases-a-survey-and-decision-guidance-ea7823a822d#.wskogqenq) +* [可擴展性](http://www.lecloud.net/post/7994751381/scalability-for-dummies-part-2-database) +* [NoSQL 介紹](https://www.youtube.com/watch?v=qI_g07C_Q5I) +* [NoSQL 模式](http://horicky.blogspot.com/2009/11/nosql-patterns.html) + +### SQL 或 NoSQL + +

+ +
+ 來源:從 RDBMS 轉換到 NoSQL +

+ +選擇 **SQL** 的原因: + +* 結構化資料 +* 嚴格的 schema +* 關連式資料 +* 需要複雜的 join +* 事務 +* 清晰的擴展模式 +* 既有資源更豐富:開發者、社群、原始碼、工具等 +* 透過索引查詢很快 + +選擇 **NoSQL** 的原因: + +* 半結構化資料 +* 動態或具有彈性的 schema +* 非關連式資料 +* 不需要複雜的 joins +* 儲存 TB (或 PB) 等級的資料 +* 高資料密集量的工作負載 +* IOPS 的高吞吐量 + +適合使用 NoSQL 的範例: + +* 快速地得到點擊的日誌資料 +* 排行榜或得分資料 +* 暫時性的資料,像是購物車 +* 經常頻繁存取的資料表 +* Metadata 或 查找資料表 + +##### 來源及延伸閱讀: SQL 或 NoSQL + +* [擴展你的使用者到第一個一千萬等級](https://www.youtube.com/watch?v=vg5onp8TU6Q) +* [SQL 和 NoSQL 的不同](https://www.sitepoint.com/sql-vs-nosql-differences/) + +## 快取 + +

+ +
+ 來源:可擴展的系統設計模式 +

+ +快取可以提高頁面讀取速度,並且減少伺服器和資料庫的負載。在這種模型中,分派器會先檢查該次請求之前是否曾經被回應過,如果有的話,則直接拿之前的結果返回,避免真正執行處理的程序。 + +資料庫在資料均勻分布的情況下,讀取和寫入的效能是最好的。但是熱門的資料會讓讀取分佈不均,如此一來就會造成效能瓶頸。在資料庫前增加一個快取,就可以減少負載不均和突發流量所造成的影響。 + +### 客戶端快取 + +快取可以在客戶端(作業系統或瀏覽器)、[伺服器端](#反向代理伺服器) 或不同的緩存層等。 + +### CDN 快取 + +[內容傳遞網路(CDN)](#內容傳遞網路(CDN)) 也被視為一種快取。 + +### 網站伺服器快取 + +[反向代理](#反向代理網站伺服器) 以及像是 [Varnish](https://www.varnish-cache.org/) 等的快取服務可以提供靜態和動態內容。網站伺服器也可以快取使用者請求,返回結果,而不需要真正的處理這些請求。 + +### 資料庫快取 + +資料庫的預設設定中通常包含了快取的級別,針對一般的使用進行了優化。你可以針對不同的情況調整這些設定來進一步提高效能。 + +### 應用程式快取 + +基於記憶體的快取,像是 Memcached 和 Redis 是一種在應用層和資料庫之間的鍵值對快取。由於資料保存在記憶體中,比起存放在硬碟中的資料庫在存取上要快得多。記憶體的限制也比硬碟更多,所以像是 [least recently used (LRU)](https://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used) 的 [cache invalidation](https://en.wikipedia.org/wiki/Cache_algorithms) 方法可以讓 '熱門資料' 放在記憶體中,而比較 '冷門' 的資料在記憶體中失效。 + +Redis 還有以下額外的功能: + +* 持久性的設定 +* 內建一些資料結構,像是 Set 或 List + +你可以快取的級別有好幾種,大致上分為兩類:**資料庫查詢** 和 **物件**: + +* 記錄級別 +* 查詢級別 +* 完整的可序列化物件 +* 完整的 HTML + +一般來說,你應該避免文件檔案的快取,因為這會讓複製和自動擴展變得困難。 + +### 資料庫查詢級別的快取 + +當你將查詢資料庫的查詢語句的 hash 值和查詢結果儲存到快取中時,這種方法會遇到以下問題: + +* 當你的查詢很複雜時,很難刪除快取內容 +* 如果某個資料表中的某個欄位值改變時,需要刪除所有可能包含該欄位值的快取結果。 + +### 物件級別的快取 + +將資料視為物件,就像對待你的程式碼一樣。讓應用程式將資料從資料庫中組合到類別實例或資料結構中: + +* 如果物件內的基本資料已經改變,那應該要從快取中刪除這個物件 +* 允許異步處理:workers 透過使用最新的快取來組裝物件 + +建議快取的資料: + +* 使用者 sessions +* 完整渲染的頁面 +* 活動資訊 +* 使用者資料圖表 + +### 什麼時候要更新快取 + +由於你只能在快取中儲存有限的資料,所以你需要選擇一個適用的快取策略。 + +#### 快取模式 + +

+ +
+ 資料來源:從快取到記憶體資料網格 +

+ +應用程式負責從儲存裝置中進行讀取及寫入。快取不直接和儲存裝置進行互動,應用程式會執行以下操作: + +* 從快取中尋找紀錄,如果所需要的紀錄在快取中找不到時 +* 從資料庫中讀取紀錄 +* 將該筆記錄儲存到快取 +* 將資料返回 + +```python +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](https://memcached.org/) 通常被用在快取上。 + +加入快取中的資料讀取速度很快,快取的模式也被稱為延遲讀取。只有被請求過的資料會被加入到快取中,避免沒有被請求的資料佔滿了快取空間。 + +##### 快取的缺點 + +* 當請求的資料不在快取中時,就需要經過三個步驟來獲得資料,這會導致明顯的延遲。 +* 如果資料庫中的資料被更新了,會導致快取中的資料過時,這需要透過設定 TTL 強制更新快取,或透過直接更新模式來解決這種問題。 +* 當快取的某個節點發生故障時,會需要被一個新的節點取代,這會導致延遲。 + +#### 寫入模式 + +

+ +
+ 資料來源:可獲展性、可用性、穩定性與模式 +

+ +應用程式使用快取當作主要的資料儲存服務,將資料寫入/讀取到快取中,由快取服務負責向資料庫讀寫資料。 + +* 應用程式向快取寫入/讀取資料 +* 快取同步的將資料寫到資料庫進行儲存 +* 返回所需要的內容 + +應用程式程式碼: + +``` +set_user(12345, {"foo":"bar"}) +``` + +快取程式碼: + +```python +def set_user(user_id, values): + user = db.query("UPDATE Users WHERE id = {0}", user_id, values) + cache.set(user_id, user) +``` + +直寫模式因為寫入操作的緣故,是一種較慢的操作,但讀取剛剛寫入的資料會很快,使用者通常比較能接受更新較慢,但讀取快速的情況。在快取中的資料不會過時。 + +##### 寫入模式的缺點 + +* 當發生故障或因為水平擴展而產生新的節點時,新的節點中將不會有快取資料,直到資料庫更新為止。將快取模式和寫入模式一起使用可以減緩這種現象。 +* 被寫入多數的資料可能永遠都不會被讀取,你可以設定 TTL 來解決這種問題。 + +#### 事後寫入(回寫) + +

+ +
+ 資料來源:可獲展性、可用性、穩定性與模式 +

+ +在事後寫入的模式中,應用程式會執行以下步驟: + +* 在快取中新增/更新資料 +* 非同步的寫入資料到資料儲存單元,提高寫入的性能 + +##### 事後寫入的缺點 + +* 快取可能在資料成功寫入到儲存單元前就丟失 +* 事後寫入比起快取模式或是直寫模式在實作上更為複雜 + +#### 更新式快取 + +

+ +
+ 來源:從快取到記憶體資料網格技術 +

+ +你可以將快取設定為在到期之前就自動更新為最新存取的內容。 + +如果快取可以準確的預測將來可能會存取哪些資料,那自動更新可以降低讀取的延遲。 + +##### 更新式快取的缺點 + +* 無法準確預測未來會使用的資料時,會導致性能降低,還不如使用其他模式。 + +### 快取的缺點 + +* 需要保持快取和資料庫之間資料的一致性,比如說要如何設定 [快取無效](https://en.wikipedia.org/wiki/Cache_algorithms)。 +* 需要更改應用程式程式碼來支援像是 Redis 或 Memcached 等快取服務。 +* 快取的無效性是個難題,而什麼時候要更新快取就是個對應的複雜問題。 + +### 來源及延伸閱讀 + +* [從快取到記憶體資料網格技術](http://www.slideshare.net/tmatyashovsky/from-cache-to-in-memory-data-grid-introduction-to-hazelcast) +* [可擴展的系統設計模式](http://horicky.blogspot.com/2010/10/scalable-system-design-patterns.html) +* [可擴展的系統架構介紹](http://lethain.com/introduction-to-architecting-systems-for-scale/) +* [可擴展性、可用性、穩定性與模式](http://www.slideshare.net/jboner/scalability-availability-stability-patterns/) +* [可擴展性](http://www.lecloud.net/post/9246290032/scalability-for-dummies-part-3-cache) +* [AWS ElastiCache 策略](http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/Strategies.html) +* [維基百科](https://en.wikipedia.org/wiki/Cache_(computing)) + +## 非同步機制 + +

+ +
+ 資料來源:可縮放性系統架構介紹 +

+ +非同步的工作流程有助於減少原本按照同步順序進行請求的時間,透過提前進行一些耗時操作來將降低整體請求時間,比如說:定期的彙整資料。 + +### 訊息佇列 + +訊息佇列用來接收、保留以及傳遞訊息。如果一個操作按照順序執行太慢的時候,你可以透過訊息佇列和以下的流程搭配來完成此工作: + +* 應用程式將訊息發送到佇列中,並通知使用者對應的狀態 +* 一個 worker 從佇列中拿出該訊息並進行處理,然後完成後顯示對應資訊 + +這樣的工作流程,使用者不會被阻塞,同時工作會在背景完成。在這段期間,客戶端可以進行一些處理讓此任務看起來已經完成了。例如,當你要發送一則推文訊息時,此訊息可以馬上出現在你的時間軸上,但可能需要一段時間才會發送到你的追蹤者上面。 + +**Redis** 是一個簡單且令人滿意的訊息佇列服務,但訊息有可能會丟失。 + +**RabbitMQ** 很受歡迎,但你必須要使用 AMQP 通訊協定,並且要自己管理節點。 + +**Amazon SQS** 是一個被 AWS 託管的服務,但可能會有高延遲,並且訊息可能會被傳送兩次。 + +### 工作佇列 + +工作佇列會接收工作和對應的資料,執行它們,並且傳送其結果。他們可以支援排程,並且可以在背景運作計算密集型的工作。 + +**Celery** 支援排程,主要是使用 Python 開發。 + +### 背壓機制 + +當佇列開始明顯成長時,佇列的大小可能會超過記憶體,這會導致無法命中快取,降低整體效能。[背壓](http://mechanical-sympathy.blogspot.com/2012/05/apply-back-pressure-when-overloaded.html) 可以用來限制佇列的大小,讓佇列保持高吞吐率和良好的回應時間。一旦佇列滿了,客戶端將會得到 HTTP 503 的回應碼,以便讓他們在稍後重新嘗試。客戶端可以透過 [指數後退演算法](https://en.wikipedia.org/wiki/Exponential_backoff) 這種方式來進行重試。 + +### 非同步的缺點 + +* 簡單的運算和需要即時的工作可能更適合使用同步運算,導入佇列可能會增加延遲或系統複雜度。 + +### 來源及延伸閱讀 + +* [這是一個數字遊戲](https://www.youtube.com/watch?v=1KRYH75wgy4) +* [當過載時,使用背壓](http://mechanical-sympathy.blogspot.com/2012/05/apply-back-pressure-when-overloaded.html) +* [利特爾法則](https://en.wikipedia.org/wiki/Little%27s_law) +* [訊息佇列和工作佇列有什麼不同?](https://www.quora.com/What-is-the-difference-between-a-message-queue-and-a-task-queue-Why-would-a-task-queue-require-a-message-broker-like-RabbitMQ-Redis-Celery-or-IronMQ-to-function) + +## 通訊 + +

+ +
+ 來源:OSI 七層模型 +

+ +### 超文件通訊協定 (HTTP) + +HTTP 是一種在客戶端和伺服器端傳輸資料和定義編碼的方法。它是基於請求/回應的協議:客戶端發出請求,而伺服器端則針對請求內容完成對應的行為並進行回應。HTTP 是獨立的,它允許請求和回應經過許多負載平衡、快取、加密和壓縮的中間路由器和伺服器。 + +一個基本的 HTTP 請求是由一個動詞(方法)和一個資源(端點)所組成。以下是常見的 HTTP 動詞: + +| 動詞 | 描述 | 冪等* | 安全性 | 可快取性 | +|--------|----------------------------------|-------|--------|-----------------------------------------| +| GET | 讀取資源 | Yes | Yes | Yes | +| POST | 建立資源,或是驅動處理資料的流程 | No | No | Yes,如果回應包含更新的資訊 | +| PUT | 建立或更新資源 | Yes | No | No | +| PATCH | 更新部分資料 | No | No | Yes if response contains freshness info | +| DELETE | 刪除資料 | Yes | No | No | + +*指的是當進行多次相同請求時,結果是相同的。 + +HTTP 是依賴於較底層的協議(例如:**TCP** 和 **UDP**) 的應用層協議。 + +#### 來源及延伸閱讀 + +* [什麼是 HTTP?](https://www.nginx.com/resources/glossary/http/) +* [HTTP 和 TCP 的差別](https://www.quora.com/What-is-the-difference-between-HTTP-protocol-and-TCP-protocol) +* [PUT 和 PATCH 的差別](https://laracasts.com/discuss/channels/general-discussion/whats-the-differences-between-put-and-patch?page=1) + +### 傳輸控制通訊協定(TCP) + +

+ +
+ 來源:如何開發多人遊戲 +

+ +TCP 是透過 [IP 網路](https://en.wikipedia.org/wiki/Internet_Protocol) 面向連線的通訊協定。連線是透過 [握手](https://en.wikipedia.org/wiki/Handshaking) 的方式來建立和斷開連接,所有發送的資料在接收時會保證順序,另外透過以下的機制來保證資料不會損毀: + +* 每個資料的序列號碼和 [校驗碼](https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Checksum_computation) +* [確認訊息](https://en.wikipedia.org/wiki/Acknowledgement_(data_networks)) 和自動重傳 + +如果發送端沒有收到正確的回應,會重新發送資料,如果有多次的逾期時,連線就會斷開。TCP 實作了 [流量控制](https://en.wikipedia.org/wiki/Flow_control_(data)) 和 [阻塞控制](https://en.wikipedia.org/wiki/Network_congestion#Congestion_control),這些機制會導致延遲,而且通常傳輸的效率會比 UDP 來得低。 + +為了確保高吞吐量,Web 伺服器會保持大量的 TCP 連線,進而導致記憶體用量變大。在 Web 伺服器之間使用大量的開放連線可能是昂貴的,更別說是在 memcached 快取中做這些事情。[連線池](https://en.wikipedia.org/wiki/Connection_pool) 可以幫助在適合的情況下切換到 UDP。 + +TCP 對於需要高可靠、低時間急迫性的應用來說很有用,比如說:Web 伺服器、資料庫、SMTP、FTP 和 SSH。 + +以下的情況請使用 TCP 而不是 UDP: + +* 你需要資料完整無缺 +* 你想要自動地對網路的流量進行最佳評估 + +### 使用者資料流通訊協定 (UDP) + +

+ +
+ 資料來源:如何製作多人遊戲 +

+ +UDP 是非連線型的通訊協定。資料流(類似於封包)只在資料流級別進行確保。資料可能會不按照順序地到達目的地,也可能會遺失。UDP 並不支援阻塞處理,儘管 UDP 不像 TCP 一樣可靠,但通常效率更好。 + +UDP 可以透過廣播來傳送資料流到所有子網路中的所有裝置,這對於 [DHCP](https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol) 來說很有用,因為所有子網路中的設備還沒有分配到 IP 位置,而對 TCP 來說,IP 是必須的。 + +UDP 的可靠性較低,但適合用在像是網路電話、視訊聊天、串流和多人線上即時遊戲中。 + +針對以下的案例,請使用 UDP 來代替 TCP: + +* 你需要低延遲 +* 資料延遲的成本比資料遺失還高 +* 你想要自己實作錯誤校正方法 + +#### 來源及延伸閱讀 + +* [遊戲程式撰寫的網路架構](http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/) +* [TCP 和 UDP 的關鍵區別](http://www.cyberciti.biz/faq/key-differences-between-tcp-and-udp-protocols/) +* [TCP 和 UDP 的差別](http://stackoverflow.com/questions/5970383/difference-between-tcp-and-udp) +* [傳輸控制協議(TCP)](https://en.wikipedia.org/wiki/Transmission_Control_Protocol) +* [使用者資料流協議(UDP)](https://en.wikipedia.org/wiki/User_Datagram_Protocol) +* [Memcache 在 Facebook 中的可擴展性設計](http://www.cs.bu.edu/~jappavoo/jappavoo.github.com/451/papers/memcache-fb.pdf) + +### 遠端程式呼叫 (RPC) + +

+ +
+ 資料來源:破解系統設計面試 +

+ +在一個 RPC 中,客戶端會去呼叫另外一個位置空間(通常是在遠端的伺服器)的方法。呼叫的方式就像是呼叫本地端的一個方法一樣,客戶端和伺服器溝通的具體過程被抽象化,而遠端呼叫相較於本地端呼叫來說一般較慢,而且可靠性較差,因此了解如何區別這兩種方法是必要的。熱門的 RPC 框架包含了 [Protobuf](https://developers.google.com/protocol-buffers/)、[Thrift](https://thrift.apache.org/) 和 [Avro](https://avro.apache.org/docs/current/)。 + +RPC 是一個請求-回應的通訊協定: + +* **客戶端程序** - 呼叫客戶端的 stub 程序,就像呼叫本地端方法一樣,參數會被放入堆疊當中 +* **客戶端 stub 程序** - 將請求過程的 id 和參數打包放入請求資訊中 +* **客戶端通訊模組** - 作業系統將資訊從客戶端發送到伺服器端 +* **伺服器端通訊模組** - 作業系統將收到的資訊傳送到伺服器端的 stub 程序 +* **伺服器端 stub 程序** - 將結果解開後,依照過程中的 ID 來呼叫伺服器 +* 伺服器回覆的順序會按照以上相反的順序來回覆 + +RPC 使用範例: + +``` +GET /someoperation?data=anId + +POST /anotheroperation +{ + "data":"anId"; + "anotherdata": "another value" +} +``` + +RPC 專注於揭露行為,它通常用來處理內部通訊的效能問題,通常你可以手動處理本地端的呼叫來更加符合你的使用案例。 + +當遇到以下情況時,使用本地端函式庫(也就是 SDK): + +* 你知道你的目標平台 +* 你想要控制如何訪問你的 "邏輯" +* 當你的函式庫發生錯誤時,你想要進行控制 +* 效能和使用者體驗是你最關注的事情 + +遵守 **REST** 規範的 HTTP API 往往更適合用在公用的 API。 + +#### RPC 的缺點 + +* RPC 的客戶端會變得和伺服器的實作綁得更死 +* 一個新的 API 必須在每個操作或使用案例中進行定義 +* RPC 很難抓錯誤 +* 你很難方便的修改現有的技術,舉例來說,如果你希望在 [Squid](http://www.squid-cache.org/) 這樣的快取伺服器上確保 [RPC 呼叫被正確的快取](http://etherealbits.com/2012/12/debunking-the-myths-of-rpc-rest/),你可以需要多費額外的努力了。 + +### 具象狀態轉移 (REST) + +REST 是一個規範客戶端/伺服器端架構設計的模型。客戶端基於伺服器管理的系列操作,伺服器提供修改或取得資源的介面,所有的通訊必須是無狀態、可快取的。 + +Restful 的設計有四個原則: + +* **標示資源 (HTTP 中的 URI)** - 無論任何操作都使用相同的 URI +* **表示層的改變 (HTTP 中的動作)** - 使用 HTTP 動詞、Headers 和 body +* **可自我描述的錯誤訊息 (HTTP 中的狀態碼)** - 使用狀態碼,不要重複造輪子 +* **[HATEOAS](http://restcookbook.com/Basics/hateoas/) (HTTP 中的 HTML 介面)** - 你的 Web 伺服器應該要能夠透過瀏覽器訪問 + +REST 請求範例: + +``` +GET /someresources/anId + +PUT /someresources/anId +{"anotherdata": "another value"} +``` + +REST 關注於揭露資料,減少客戶端/伺服器之間耦合的程度,並且經常用在公共的 HTTP API 設計上。REST 使用更通用和受規範的方法來透過 URI 來揭露資源,[透過 Headers 來描述](https://github.com/for-GET/know-your-http-well/blob/master/headers.md),並透過 GET、POST、PUT、DELETE 和 PATCH 等動作來進行操作,因為無狀態的特性,REST 易於橫向擴展和分片。 + +#### REST 的缺點 + +* 因為 REST 的重點是放在如何揭露資料,所以當資料不是以自然的形式組成時,或是結構相當複雜時,REST 可能無法很好的處理他們。舉個範例,回傳過去一小時中與特定事件吻合的更新操作就很難透過路徑來表示,使用 REST,可能會使用 URI、查詢參數和請求本身來實現。 +* REST 一般依賴於幾個動詞操作(GET、POST、PUT、DELETE 和 PATCH),但有時候這些操作無法滿足你的需求,舉個範例,將過期的文件移動到歸檔文件資料庫中這樣的操作,可能就沒辦法簡單的使用以上幾個動詞操作來完成。 +* 對於那些多層複雜的資源來說,需要在客戶端和伺服器端進行多次請求,例如:獲得部落格頁面及相關評論,而對於網路環境較不穩定的行動端應用來說,這些多次往返的請求是非常麻煩的。 +* 隨著時間的增加,API 的回應中可能會增加更多的欄位,比較舊的客戶端還是會收到所有新的回應內容,即時他們不需要這些回應,這會造成他們的負擔,並且造成更大的延遲。 + +### RPC 和 REST 呼叫的比較 + +| 操作 | RPC | REST | +|----------------------------|-----------------------------------------------------------------------|-----------------------------------------------| +| 註冊 | **POST** /signup | **POST** /persons | +| 取消 | **POST** /resign{"personid": "1234"} | **DELETE** /persons/1234 | +| 讀取使用者資訊 | **GET** /readPerson?personid=1234 | **GET** /persons/1234 | +| 讀取使用者物品清單 | **GET** /readUsersItemsList?personid=1234 | **GET** /persons/1234/items | +| 增加一個物品到使用者的清單 | **POST** /addItemToUsersItemsList{"personid": "1234";"itemid": "456"} | **POST** /persons/1234/items{"itemid": "456"} | +| 更新一個物品 | **POST** /modifyItem{"itemid": "456";"key": "value"} | **PUT** /items/456{"key": "value"} | +| 刪除一個物品 | **POST** /removeItem{"itemid": "456"} | **DELETE** /items/456 | + +

+ 資料來源:你真的知道為什麼你更喜歡 REST 而不是 RPC 嗎? +

+ +#### 來源及延伸閱讀 + +* [你真的知道為什麼你更喜歡 REST 而不是 RPC 嗎?](https://apihandyman.io/do-you-really-know-why-you-prefer-rest-over-rpc/) +* [什麼時候 RPC 比 REST 更適合](http://programmers.stackexchange.com/a/181186) +* [REST 和 JSON-RPC](http://stackoverflow.com/questions/15056878/rest-vs-json-rpc) +* [揭開 RPC 和 REST 的神秘面紗](http://etherealbits.com/2012/12/debunking-the-myths-of-rpc-rest/) +* [使用 REST 的缺點](https://www.quora.com/What-are-the-drawbacks-of-using-RESTful-APIs) +* [破解系統設計面試](http://www.puncsky.com/blog/2016-02-13-crack-the-system-design-interview) +* [Thrift](https://code.facebook.com/posts/1468950976659943/) +* [為什麼在內部要使用 REST 而不是 RPC](http://arstechnica.com/civis/viewtopic.php?t=1190508) + +## 資訊安全 + +這一章節需要更多的貢獻,一起[加入](#如何貢獻)吧! + +資訊安全是一個廣泛的議題,除非你有相當的經驗、資訊安全的背景或正在申請相關的職位要求對應的知識,否則了解以下的基礎內容即可: + +*在傳輸和等待的過程中進行加密 +* 對所有使用者輸入和從使用者得到的參數進行處理,以避免 [XSS](https://en.wikipedia.org/wiki/Cross-site_scripting) 和 [SQL injection](https://en.wikipedia.org/wiki/SQL_injection) +* 使用參數化輸入來避免 SQL injection +* 使用 [最小權限原則](https://en.wikipedia.org/wiki/Principle_of_least_privilege) + +### 來源及延伸閱讀 + +* [為開發者準備的資訊安全指南](https://github.com/FallibleInc/security-guide-for-developers) +* [OWASP top ten](https://www.owasp.org/index.php/OWASP_Top_Ten_Cheat_Sheet) + +## 附錄 + +某些時候你可能會被要求做一些保守估計,比如說,你可能需要預估從硬碟中生成 100 張圖片約略需要多少時間,或一個資料結構需要多少記憶體等。**2 的次方表** 和 **每個開發者都需要知道的一些時間資料** 都是一些很方便的參考料。 + +### 2 的次方表 + +``` +次方 實際值 近似值 位元組 +--------------------------------------------------------------- +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 +``` + +#### 來源及延伸閱讀 + +* [2 的次方](https://en.wikipedia.org/wiki/Power_of_two) + +### 每個開發者都應該知道的延遲數量級 + +``` +延遲比較數量級 +-------------------------- +L1 快取參考數量級 0.5 ns +Branch mispredict 5 ns +L2 快取參考數量級 7 ns 14x L1 cache +Mutex lock/unlock 25 ns +主記憶體參考數量級 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 +Disk 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 disk 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 +``` + +一些基於上述數字的指標: + +* 循序的從硬碟讀取資料大約 30 MB/s +* 循序的從 1 Gbps 坪寬的乙太網路讀取約 100 MB/s +* 循序的從 SSD 讀取大約 1 GB/s +* 循序的從主記憶體中讀取大約 4 GB/s +* 每秒大約可以繞地球 6-7 圈 +* 資料中心內每秒約有 2000 次的往返 + +#### 視覺化延遲數 + +![](https://camo.githubusercontent.com/77f72259e1eb58596b564d1ad823af1853bc60a3/687474703a2f2f692e696d6775722e636f6d2f6b307431652e706e67) + +#### 來源及延伸閱讀 + +* [每個程式設計師都應該知道的延遲數量級 - 1](https://gist.github.com/jboner/2841832) +* [每個程式設計師都應該知道的延遲數量級 - 2](https://gist.github.com/hellerbarde/2843375) +* [關於建置大型分散式系統所需要知道的設計方案、課程和建議](http://www.cs.cornell.edu/projects/ladis2009/talks/dean-keynote-ladis2009.pdf) +* [從軟體工程師的角度來看建置大型分散式系統](https://static.googleusercontent.com/media/research.google.com/en//people/jeff/stanford-295-talk.pdf) + +### 其他的系統設計面試問題 + +> 常見的系統設計問題,同時提供如何解決該問題的連結 + +| 問題 | 來源 | +|----------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 設計一個類似於 Dropbox 的文件同步系統 | [youtube.com](https://www.youtube.com/watch?v=PE4gwstWhmc) | +| 設計一個類似於 Google 的搜尋引擎 | [queue.acm.org](http://queue.acm.org/detail.cfm?id=988407)
[stackexchange.com](http://programmers.stackexchange.com/questions/38324/interview-question-how-would-you-implement-google-search)
[ardendertat.com](http://www.ardendertat.com/2012/01/11/implementing-search-engines/)
[stanford.edu](http://infolab.stanford.edu/~backrub/google.html) | +| 設計一個像 Google 一樣可擴展的網路爬蟲 | [quora.com](https://www.quora.com/How-can-I-build-a-web-crawler-from-scratch) | +| 設計一個 Google Docs | [code.google.com](https://code.google.com/p/google-mobwrite/)
[neil.fraser.name](https://neil.fraser.name/writing/sync/) | +| 設計一個像 Redis 一樣的鍵值對系統 | [slideshare.net](http://www.slideshare.net/dvirsky/introduction-to-redis) | +| 設計一個像 Memcached 的快取系統 | [slideshare.net](http://www.slideshare.net/oemebamo/introduction-to-memcached) | +| 設計一個像 Amazon 一樣的推薦系統 | [hulu.com](http://tech.hulu.com/blog/2011/09/19/recommendation-system.html)[ijcai13.org](http://ijcai13.org/files/tutorial_slides/td3.pdf) | +| 設計一個像 Bitly 一樣的短網址服務 | [n00tc0d3r.blogspot.com](http://n00tc0d3r.blogspot.com/) | +| 設計一個像 WhatsApp 一樣的即時訊息系統 | [highscalability.com](http://highscalability.com/blog/2014/2/26/the-whatsapp-architecture-facebook-bought-for-19-billion.html) | +| 設計一個像 Instagram 一樣的相片服務 | [highscalability.com](http://highscalability.com/flickr-architecture)
[highscalability.com](http://highscalability.com/blog/2011/12/6/instagram-architecture-14-million-users-terabytes-of-photos.html) | +| 設計一個像 Facebook 的新聞推薦方法 | [quora.com](http://www.quora.com/What-are-best-practices-for-building-something-like-a-News-Feed)
[quora.com](http://www.quora.com/Activity-Streams/What-are-the-scaling-issues-to-keep-in-mind-while-developing-a-social-network-feed)
[slideshare.net](http://www.slideshare.net/danmckinley/etsy-activity-feeds-architecture) | +| 設計一個 Facebook 時間軸功能 | [facebook.com](https://www.facebook.com/note.php?note_id=10150468255628920)
[highscalability.com](http://highscalability.com/blog/2012/1/23/facebook-timeline-brought-to-you-by-the-power-of-denormaliza.html) | +| 設計 Facebook 的聊天功能 | [erlang-factory.com](http://www.erlang-factory.com/upload/presentations/31/EugeneLetuchy-ErlangatFacebook.pdf)
[facebook.com](https://www.facebook.com/note.php?note_id=14218138919&id=9445547199&index=0) | +| 設計一個像 Facebook 的圖形化搜尋系統 | [facebook.com](https://www.facebook.com/notes/facebook-engineering/under-the-hood-building-out-the-infrastructure-for-graph-search/10151347573598920)
[facebook.com](https://www.facebook.com/notes/facebook-engineering/under-the-hood-indexing-and-ranking-in-graph-search/10151361720763920)
[facebook.com](https://www.facebook.com/notes/facebook-engineering/under-the-hood-the-natural-language-interface-of-graph-search/10151432733048920) | +| 設計一個像 CloudFlare 的內容傳輸網路 | [cmu.edu](http://repository.cmu.edu/cgi/viewcontent.cgi?article=2112&context=compsci) | +| 設計一個像 Twitter 的微網誌服務 | [michael-noll.com](http://www.michael-noll.com/blog/2013/01/18/implementing-real-time-trending-topics-in-storm/)
[snikolov .wordpress.com](http://snikolov.wordpress.com/2012/11/14/early-detection-of-twitter-trends/) | +| 設計一個隨機 ID 生成系統 | [blog.twitter.com](https://blog.twitter.com/2010/announcing-snowflake)
[github.com](https://github.com/twitter/snowflake/) | +| 給定一段時間,回傳次數排名前 K 的請求 | [ucsb.edu](https://icmi.cs.ucsb.edu/research/tech_reports/reports/2005-23.pdf)
[wpi.edu](http://davis.wpi.edu/xmdv/docs/EDBT11-diyang.pdf) | +| 設計一個資料來源在多個資料中心的系統 | [highscalability.com](http://highscalability.com/blog/2009/8/24/how-google-serves-data-from-multiple-datacenters.html) | +| 設計一個線上多人卡牌遊戲 | [indieflashblog.com](http://www.indieflashblog.com/how-to-create-an-asynchronous-multiplayer-game.html)
[buildnewgames.com](http://buildnewgames.com/real-time-multiplayer/) | +| 設計一個垃圾回收系統 | [stuffwithstuff.com](http://journal.stuffwithstuff.com/2013/12/08/babys-first-garbage-collector/)
[washington.edu](http://courses.cs.washington.edu/courses/csep521/07wi/prj/rick.pdf) | +| 貢獻更多系統設計問題 | [Contribute](#如何貢獻) | + +### 真實世界的架構 + +> 底下是關於真實世界的系統架構是如何設計的文章 + +

+ +
+ 資料來源:可擴展式的 Twitter 時間軸設計 +

+ +**不要關注以下文章的細節,而是注意以下幾點:** + +* 找到這些文章中共通的原則、技術和模式 +* 學習每個元件負責解決哪些問題、在什麼情況下使用、什麼情況下不適用 +* 複習學習過的文章 + +| 種類 | 系統 | 參考來源 | +|----------|----------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------| +| 資料處理 | **MapReduce** - Google 的分散式資料處理 | [research.google.com](http://static.googleusercontent.com/media/research.google.com/zh-CN/us/archive/mapreduce-osdi04.pdf) | +| 資料處理 | **Spark** - Databricks 的分散式資料處理 | [slideshare.net](http://www.slideshare.net/AGrishchenko/apache-spark-architecture) | +| 資料處理 | **Storm** - Twitter 的分散式資料處理 | [slideshare.net](http://www.slideshare.net/previa/storm-16094009) | +| | | | +| 資料儲存 | **Bigtable** - Google 的列式資料庫 | [harvard.edu](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/chang06bigtable.pdf) | +| 資料儲存 | **HBase** - Bigtable 的開放原始碼解決方案 | [slideshare.net](http://www.slideshare.net/alexbaranau/intro-to-hbase) | +| 資料儲存 | **Cassandra** - Facebook 的列式資料庫 | [slideshare.net](http://www.slideshare.net/planetcassandra/cassandra-introduction-features-30103666) | +| 資料儲存 | **DynamoDB** - Amazon 的文件式資料庫 | [harvard.edu](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/decandia07dynamo.pdf) | +| 資料儲存 | **MongoDB** - 文件式資料庫 | [slideshare.net](http://www.slideshare.net/mdirolf/introduction-to-mongodb) | +| 資料儲存 | **Spanner** - Google 的全球分散式資料庫 | [research.google.com](http://research.google.com/archive/spanner-osdi2012.pdf) | +| 資料儲存 | **Memcached** - 分散式的記憶體快取系統 | [slideshare.net](http://www.slideshare.net/oemebamo/introduction-to-memcached) | +| 資料儲存 | **Redis** - 具有持久化及值型別的分散式快取系統 | [slideshare.net](http://www.slideshare.net/dvirsky/introduction-to-redis) | +| | | | +| 檔案系統 | **Google File System (GFS)** - 分散式的檔案系統 | [research.google.com](http://static.googleusercontent.com/media/research.google.com/zh-CN/us/archive/gfs-sosp2003.pdf) | +| 檔案系統 | **Hadoop File System (HDFS)** - GFS 的開放原始碼解決方案 | [apache.org](https://hadoop.apache.org/docs/r1.2.1/hdfs_design.html) | +| | | | +| 其他 | **Chubby** - Google 的分散式系統低耦合鎖服務 | [research.google.com](http://static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/en/us/archive/chubby-osdi06.pdf) | +| 其他 | **Dapper** - 分散式系統監控基礎設施 | [research.google.com](http://static.googleusercontent.com/media/research.google.com/en//pubs/archive/36356.pdf) | +| 其他 | **Kafka** - LinkedIn 的 pub/sub 訊息佇列服務 | [slideshare.net](http://www.slideshare.net/mumrah/kafka-talk-tri-hug) | +| 其他 | **Zookeeper** - 集中式的基礎架構和協調服務 | [slideshare.net](http://www.slideshare.net/sauravhaloi/introduction-to-apache-zookeeper) | +| | 貢獻更多架構 | [Contribute](#如何貢獻) | + +### 公司的系統架構 + +| 公司 | 參考 | +|----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Amazon | [Amazon 的架構](http://highscalability.com/amazon-architecture) | +| Cinchcast | [每天產生 1,500 小時的音樂](http://highscalability.com/blog/2012/7/16/cinchcast-architecture-producing-1500-hours-of-audio-every-d.html) | +| DataSift | [每秒探勘 120,000 則 tweet](http://highscalability.com/blog/2011/11/29/datasift-architecture-realtime-datamining-at-120000-tweets-p.html) | +| DropBox | [我們如何擴展 Dropbox](https://www.youtube.com/watch?v=PE4gwstWhmc) | +| ESPN | [每秒操作 100,000 次 duh nuh nuhs](http://highscalability.com/blog/2013/11/4/espns-architecture-at-scale-operating-at-100000-duh-nuh-nuhs.html) | +| Google | [Google 的架構](http://highscalability.com/google-architecture) | +| Instagram | [一千四百萬個使用者,TB 等級的照片儲存](http://highscalability.com/blog/2011/12/6/instagram-architecture-14-million-users-terabytes-of-photos.html)
[什麼驅動著 Instagram](http://instagram-engineering.tumblr.com/post/13649370142/what-powers-instagram-hundreds-of-instances) | +| Justin.tv | [Justin.Tv 的即時影片廣播架構](http://highscalability.com/blog/2010/3/16/justintvs-live-video-broadcasting-architecture.html) | +| Facebook | [Facebook 可擴展的 memcached 架構](https://cs.uwaterloo.ca/~brecht/courses/854-Emerging-2014/readings/key-value/fb-memcached-nsdi-2013.pdf)
[TAO: Facebook 為了社交網路架構的分散式資料儲存](https://cs.uwaterloo.ca/~brecht/courses/854-Emerging-2014/readings/data-store/tao-facebook-distributed-datastore-atc-2013.pdf)
[Facebook 的圖片儲存架構](https://www.usenix.org/legacy/event/osdi10/tech/full_papers/Beaver.pdf) | +| Flickr | [Flickr 的架構](http://highscalability.com/flickr-architecture) | +| Mailbox | [在六週內從 0 到 100 萬個使用者](http://highscalability.com/blog/2013/6/18/scaling-mailbox-from-0-to-one-million-users-in-6-weeks-and-1.html) | +| Pinterest | [從零到每個月數十億次的瀏覽量](http://highscalability.com/blog/2013/4/15/scaling-pinterest-from-0-to-10s-of-billions-of-page-views-a.html)
[1800 萬個訪問人次、10 倍成長、12 名員工](http://highscalability.com/blog/2012/5/21/pinterest-architecture-update-18-million-visitors-10x-growth.html) | +| Playfish | [月使用者量 5000 萬人次在成長](http://highscalability.com/blog/2010/9/21/playfishs-social-gaming-architecture-50-million-monthly-user.html) | +| PlentyOfFish | [PlentyOfFish 的架構](http://highscalability.com/plentyoffish-architecture) | +| Salesforce | [如何處理每天 13 億筆交易](http://highscalability.com/blog/2013/9/23/salesforce-architecture-how-they-handle-13-billion-transacti.html) | +| Stack Overflow | [Stack Overflow 的架構](http://highscalability.com/blog/2009/8/5/stack-overflow-architecture.html) | +| TripAdvisor | [4000 萬的訪問人次、2 億次頁面瀏覽量、30 TB 的資料](http://highscalability.com/blog/2011/6/27/tripadvisor-architecture-40m-visitors-200m-dynamic-page-view.html) | +| Tumblr | [每月 150 億的瀏覽量](http://highscalability.com/blog/2012/2/13/tumblr-architecture-15-billion-page-views-a-month-and-harder.html) | +| Twitter | [如何讓 Twitter 的速度成長 10000 倍](http://highscalability.com/scaling-twitter-making-twitter-10000-percent-faster)
[使用 MySQL 儲存每天 2.5 億條 tweet](http://highscalability.com/blog/2011/12/19/how-twitter-stores-250-million-tweets-a-day-using-mysql.html)
[1.5 億的活躍使用者、300K QPS、22 MB/S 的串流資料](http://highscalability.com/blog/2013/7/8/the-architecture-twitter-uses-to-deal-with-150m-active-users.html)
[可擴展的 Timelines](https://www.infoq.com/presentations/Twitter-Timeline-Scalability)
[Twitter 的大大小小的資料](https://www.youtube.com/watch?v=5cKTP36HVgI)
[Twitter 的運營:擴展超過一億個使用者](https://www.youtube.com/watch?v=z8LU0Cj6BOU) | +| Uber | [Uber 是如何擴展他們的及時行銷平台](http://highscalability.com/blog/2015/9/14/how-uber-scales-their-real-time-market-platform.html) | +| WhatsApp | [讓 Facebook 用 $190 億購買下來的 WhatsApp 的架構](http://highscalability.com/blog/2014/2/26/the-whatsapp-architecture-facebook-bought-for-19-billion.html) | +| YouTube | [YouTube 的可擴展性](https://www.youtube.com/watch?v=w5WVu624fY8)[YouTube 的架構](http://highscalability.com/youtube-architecture) | + +### 公司的工程部落格 + +> 你即將面試的公司的架構 +> +> 你被問到的問題可能就來自於相同領域的問題 + +* [Airbnb Engineering](http://nerds.airbnb.com/) +* [Atlassian Developers](https://developer.atlassian.com/blog/) +* [Autodesk Engineering](http://cloudengineering.autodesk.com/blog/) +* [AWS Blog](https://aws.amazon.com/blogs/aws/) +* [Bitly Engineering Blog](http://word.bitly.com/) +* [Box Blogs](https://www.box.com/blog/engineering/) +* [Cloudera Developer Blog](http://blog.cloudera.com/blog/) +* [Dropbox Tech Blog](https://tech.dropbox.com/) +* [Engineering at Quora](http://engineering.quora.com/) +* [Ebay Tech Blog](http://www.ebaytechblog.com/) +* [Evernote Tech Blog](https://blog.evernote.com/tech/) +* [Etsy Code as Craft](http://codeascraft.com/) +* [Facebook Engineering](https://www.facebook.com/Engineering) +* [Flickr Code](http://code.flickr.net/) +* [Foursquare Engineering Blog](http://engineering.foursquare.com/) +* [GitHub Engineering Blog](http://githubengineering.com/) +* [Google Research Blog](http://googleresearch.blogspot.com/) +* [Groupon Engineering Blog](https://engineering.groupon.com/) +* [Heroku Engineering Blog](https://engineering.heroku.com/) +* [Hubspot Engineering Blog](http://product.hubspot.com/blog/topic/engineering) +* [High Scalability](http://highscalability.com/) +* [Instagram Engineering](http://instagram-engineering.tumblr.com/) +* [Intel Software Blog](https://software.intel.com/en-us/blogs/) +* [Jane Street Tech Blog](https://blogs.janestreet.com/category/ocaml/) +* [LinkedIn Engineering](http://engineering.linkedin.com/blog) +* [Microsoft Engineering](https://engineering.microsoft.com/) +* [Microsoft Python Engineering](https://blogs.msdn.microsoft.com/pythonengineering/) +* [Netflix Tech Blog](http://techblog.netflix.com/) +* [Paypal Developer Blog](https://devblog.paypal.com/category/engineering/) +* [Pinterest Engineering Blog](http://engineering.pinterest.com/) +* [Quora Engineering](https://engineering.quora.com/) +* [Reddit Blog](http://www.redditblog.com/) +* [Salesforce Engineering Blog](https://developer.salesforce.com/blogs/engineering/) +* [Slack Engineering Blog](https://slack.engineering/) +* [Spotify Labs](https://labs.spotify.com/) +* [Twilio Engineering Blog](http://www.twilio.com/engineering) +* [Twitter Engineering](https://engineering.twitter.com/) +* [Uber Engineering Blog](http://eng.uber.com/) +* [Yahoo Engineering Blog](http://yahooeng.tumblr.com/) +* [Yelp Engineering Blog](http://engineeringblog.yelp.com/) +* [Zynga Engineering Blog](https://www.zynga.com/blogs/engineering) + +#### 來源及延伸閱讀 + +* [kilimchoi/engineering-blogs](https://github.com/kilimchoi/engineering-blogs) + +## 仍在進行中 + +有興趣增加一些內容,或幫忙完善某些部分嗎? [來貢獻吧](#如何貢獻)! + +* 使用 MapReduce 進行分散式運算 +* 一致性的 hashing +* 直接記憶體存取 +* [貢獻](#如何貢獻) + +## 致謝 + +在這個 Repository 中提供的任何來源和開放原始碼庫 + +特別感謝: + +* [Hired in tech](http://www.hiredintech.com/system-design/the-system-design-process/) +* [Cracking the coding interview](https://www.amazon.com/dp/0984782850/) +* [High scalability](http://highscalability.com/) +* [checkcheckzz/system-design-interview](https://github.com/checkcheckzz/system-design-interview) +* [shashank88/system_design](https://github.com/shashank88/system_design) +* [mmcgrana/services-engineering](https://github.com/mmcgrana/services-engineering) +* [System design cheat sheet](https://gist.github.com/vasanthk/485d1c25737e8e72759f) +* [A distributed systems reading list](http://dancres.github.io/Pages/) +* [Cracking the system design interview](http://www.puncsky.com/blog/2016-02-13-crack-the-system-design-interview) + +## 聯絡資訊 + +隨時歡迎與我討論相關的問題或意見。 + +我的聯絡資訊可以在我的 [GitHub 主頁](https://github.com/donnemartin) 中找到。 + +## 授權 + +*我已開放原始碼授權的方式提供你在此儲存庫中的程式碼和資源。因為這是我個人的儲存庫,所以你所以所收到的使用許可是來自於我,並非我的雇主(Facebook)* + + Copyright 2017 Donne Martin + + Creative Commons Attribution 4.0 International License (CC BY 4.0) + + http://creativecommons.org/licenses/by/4.0/ diff --git a/README.md b/README.md index 257935187a4..4ff765ffeaf 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -*[English](README.md) ∙ [简体中文](README-zh-Hans.md) | [Brazilian Portuguese](https://github.com/donnemartin/system-design-primer/issues/40) ∙ [Turkish](https://github.com/donnemartin/system-design-primer/issues/39) | [Add Translation](https://github.com/donnemartin/system-design-primer/issues/28)* +*[English](README.md) ∙ [日本語](README-ja.md) ∙ [简体中文](README-zh-Hans.md) ∙ [繁體中文](README-zh-TW.md) | [العَرَبِيَّة‎](https://github.com/donnemartin/system-design-primer/issues/170) ∙ [বাংলা](https://github.com/donnemartin/system-design-primer/issues/220) ∙ [Português do Brasil](https://github.com/donnemartin/system-design-primer/issues/40) ∙ [Deutsch](https://github.com/donnemartin/system-design-primer/issues/186) ∙ [ελληνικά](https://github.com/donnemartin/system-design-primer/issues/130) ∙ [עברית](https://github.com/donnemartin/system-design-primer/issues/272) ∙ [Italiano](https://github.com/donnemartin/system-design-primer/issues/104) ∙ [韓國語](https://github.com/donnemartin/system-design-primer/issues/102) ∙ [فارسی](https://github.com/donnemartin/system-design-primer/issues/110) ∙ [Polski](https://github.com/donnemartin/system-design-primer/issues/68) ∙ [русский язык](https://github.com/donnemartin/system-design-primer/issues/87) ∙ [Español](https://github.com/donnemartin/system-design-primer/issues/136) ∙ [ภาษาไทย](https://github.com/donnemartin/system-design-primer/issues/187) ∙ [Türkçe](https://github.com/donnemartin/system-design-primer/issues/39) ∙ [tiếng Việt](https://github.com/donnemartin/system-design-primer/issues/127) ∙ [Français](https://github.com/donnemartin/system-design-primer/issues/250) | [Add Translation](https://github.com/donnemartin/system-design-primer/issues/28)* # The System Design Primer

- +

@@ -23,7 +23,7 @@ This repo is an **organized collection** of resources to help you learn how to b ### Learn from the open source community -This is an early draft of a continually updated, open source project. +This is a continually updated, open source project. [Contributions](#contributing) are welcome! @@ -44,15 +44,15 @@ Additional topics for interview prep: ## Anki flashcards

- +

The provided [Anki flashcard decks](https://apps.ankiweb.net/) use spaced repetition to help you retain key system design concepts. -* [System design deck](resources/flash_cards/System%20Design.apkg) -* [System design exercises deck](resources/flash_cards/System%20Design%20Exercises.apkg) -* [Object oriented design exercises deck](resources/flash_cards/OO%20Design.apkg) +* [System design deck](https://github.com/donnemartin/system-design-primer/tree/master/resources/flash_cards/System%20Design.apkg) +* [System design exercises deck](https://github.com/donnemartin/system-design-primer/tree/master/resources/flash_cards/System%20Design%20Exercises.apkg) +* [Object oriented design exercises deck](https://github.com/donnemartin/system-design-primer/tree/master/resources/flash_cards/OO%20Design.apkg) Great for use while on-the-go. @@ -61,7 +61,7 @@ Great for use while on-the-go. Looking for resources to help you prep for the [**Coding Interview**](https://github.com/donnemartin/interactive-coding-challenges)?

- +

@@ -91,7 +91,7 @@ Review the [Contributing Guidelines](CONTRIBUTING.md). > Each section contains links to more in-depth resources.

- +

@@ -112,6 +112,7 @@ Review the [Contributing Guidelines](CONTRIBUTING.md). * [Availability patterns](#availability-patterns) * [Fail-over](#fail-over) * [Replication](#replication) + * [Availability in numbers](#availability-in-numbers) * [Domain name system](#domain-name-system) * [Content delivery network](#content-delivery-network) * [Push CDNs](#push-cdns) @@ -289,7 +290,7 @@ Check out the following links to get a better idea of what to expect: | Question | | |---|---| | Design Pastebin.com (or Bit.ly) | [Solution](solutions/system_design/pastebin/README.md) | -| Design the Twitter timeline (or Facebook feed)
Design Twitter search (or Facebook search) | [Solution](solutions/system_design/twitter/README.md) | +| Design the Twitter timeline and search (or Facebook feed and search) | [Solution](solutions/system_design/twitter/README.md) | | Design a web crawler | [Solution](solutions/system_design/web_crawler/README.md) | | Design Mint.com | [Solution](solutions/system_design/mint/README.md) | | Design the data structures for a social network | [Solution](solutions/system_design/social_graph/README.md) | @@ -385,7 +386,7 @@ First, you'll need a basic understanding of common principles, learning about wh ### Step 2: Review the scalability article -[Scalability](http://www.lecloud.net/tagged/scalability) +[Scalability](http://www.lecloud.net/tagged/scalability/chrono) * Topics covered: * [Clones](http://www.lecloud.net/post/7295452622/scalability-for-dummies-part-1-clones) @@ -436,7 +437,7 @@ Generally, you should aim for **maximal throughput** with **acceptable latency** ### CAP theorem

- +
Source: CAP theorem revisited

@@ -455,7 +456,7 @@ Waiting for a response from the partitioned node might result in a timeout error #### AP - availability and partition tolerance -Responses return the most recent version of the data available on the a node, which might not be the latest. Writes might take some time to propagate when the partition is resolved. +Responses return the most recent version of the data available on a node, which might not be the latest. Writes might take some time to propagate when the partition is resolved. AP is a good choice if the business needs allow for [eventual consistency](#eventual-consistency) or when the system needs to continue working despite external errors. @@ -527,10 +528,56 @@ This topic is further discussed in the [Database](#database) section: * [Master-slave replication](#master-slave-replication) * [Master-master replication](#master-master-replication) +### Availability in numbers + +Availability is often quantified by uptime (or downtime) as a percentage of time the service is available. Availability is generally measured in number of 9s--a service with 99.99% availability is described as having four 9s. + +#### 99.9% availability - three 9s + +| Duration | Acceptable downtime| +|---------------------|--------------------| +| Downtime per year | 8h 45min 57s | +| Downtime per month | 43m 49.7s | +| Downtime per week | 10m 4.8s | +| Downtime per day | 1m 26.4s | + +#### 99.99% availability - four 9s + +| Duration | Acceptable downtime| +|---------------------|--------------------| +| Downtime per year | 52min 35.7s | +| Downtime per month | 4m 23s | +| Downtime per week | 1m 5s | +| Downtime per day | 8.6s | + +#### Availability in parallel vs in sequence + +If a service consists of multiple components prone to failure, the service's overall availability depends on whether the components are in sequence or in parallel. + +###### In sequence + +Overall availability decreases when two components with availability < 100% are in sequence: + +``` +Availability (Total) = Availability (Foo) * Availability (Bar) +``` + +If both `Foo` and `Bar` each had 99.9% availability, their total availability in sequence would be 99.8%. + +###### In parallel + +Overall availability increases when two components with availability < 100% are in parallel: + +``` +Availability (Total) = 1 - (1 - Availability (Foo)) * (1 - Availability (Bar)) +``` + +If both `Foo` and `Bar` each had 99.9% availability, their total availability in parallel would be 99.9999%. + ## Domain name system

- +
Source: DNS security presentation

@@ -556,7 +603,7 @@ Services such as [CloudFlare](https://www.cloudflare.com/dns/) and [Route 53](ht ### Disadvantage(s): DNS * Accessing a DNS server introduces a slight delay, although mitigated by caching described above. -* DNS server management could be complex, although they are generally managed by [governments, ISPs, and large companies](http://superuser.com/questions/472695/who-controls-the-dns-servers/472729). +* DNS server management could be complex and is generally managed by [governments, ISPs, and large companies](http://superuser.com/questions/472695/who-controls-the-dns-servers/472729). * DNS services have recently come under [DDoS attack](http://dyn.com/blog/dyn-analysis-summary-of-friday-october-21-attack/), preventing users from accessing websites such as Twitter without knowing Twitter's IP address(es). ### Source(s) and further reading @@ -568,7 +615,7 @@ Services such as [CloudFlare](https://www.cloudflare.com/dns/) and [Route 53](ht ## Content delivery network

- +
Source: Why use a CDN

@@ -602,14 +649,14 @@ Sites with heavy traffic work well with pull CDNs, as traffic is spread out more ### Source(s) and further reading -* [Globally distributed content delivery](http://repository.cmu.edu/cgi/viewcontent.cgi?article=2112&context=compsci) +* [Globally distributed content delivery](https://figshare.com/articles/Globally_distributed_content_delivery/6605972) * [The differences between push and pull CDNs](http://www.travelblogadvice.com/technical/the-differences-between-push-and-pull-cdns/) * [Wikipedia](https://en.wikipedia.org/wiki/Content_delivery_network) ## Load balancer

- +
Source: Scalable system design patterns

@@ -643,7 +690,7 @@ Load balancers can route traffic based on various metrics, including: Layer 4 load balancers look at info at the [transport layer](#communication) to decide how to distribute requests. Generally, this involves the source, destination IP addresses, and ports in the header, but not the contents of the packet. Layer 4 load balancers forward network packets to and from the upstream server, performing [Network Address Translation (NAT)](https://www.nginx.com/resources/glossary/layer-4-load-balancing/). -### layer 7 load balancing +### Layer 7 load balancing Layer 7 load balancers look at the [application layer](#communication) to decide how to distribute requests. This can involve contents of the header, message, and cookies. Layer 7 load balancers terminates network traffic, reads the message, makes a load-balancing decision, then opens a connection to the selected server. For example, a layer 7 load balancer can direct video traffic to servers that host videos while directing more sensitive user billing traffic to security-hardened servers. @@ -679,7 +726,7 @@ Load balancers can also help with horizontal scaling, improving performance and ## Reverse proxy (web server)

- +
Source: Wikipedia
@@ -722,14 +769,12 @@ Additional benefits include: ## Application layer

- +
Source: Intro to architecting systems for scale

-Separating out the web layer from the application layer (also known as platform layer) allows you to scale and configure both layers independently. Adding a new API results in adding application servers without necessarily adding additional web servers. - -The **single responsibility principle** advocates for small and autonomous services that work together. Small teams with small services can plan more aggressively for rapid growth. +Separating out the web layer from the application layer (also known as platform layer) allows you to scale and configure both layers independently. Adding a new API results in adding application servers without necessarily adding additional web servers. The **single responsibility principle** advocates for small and autonomous services that work together. Small teams with small services can plan more aggressively for rapid growth. Workers in the application layer also help enable [asynchronism](#asynchronism). @@ -751,7 +796,7 @@ Systems such as [Consul](https://www.consul.io/docs/index.html), [Etcd](https:// ### Source(s) and further reading * [Intro to architecting systems for scale](http://lethain.com/introduction-to-architecting-systems-for-scale) -* [Crack the system design interview](http://www.puncsky.com/blog/2016/02/14/crack-the-system-design-interview/) +* [Crack the system design interview](http://www.puncsky.com/blog/2016-02-13-crack-the-system-design-interview) * [Service oriented architecture](https://en.wikipedia.org/wiki/Service-oriented_architecture) * [Introduction to Zookeeper](http://www.slideshare.net/sauravhaloi/introduction-to-apache-zookeeper) * [Here's what you need to know about building microservices](https://cloudncode.wordpress.com/2016/07/22/msa-getting-started/) @@ -759,9 +804,9 @@ Systems such as [Consul](https://www.consul.io/docs/index.html), [Etcd](https:// ## Database

- +
- Source: Scaling up to your first 10 million users + Source: Scaling up to your first 10 million users

### Relational database management system (RDBMS) @@ -782,7 +827,7 @@ There are many techniques to scale a relational database: **master-slave replica The master serves reads and writes, replicating writes to one or more slaves, which serve only reads. Slaves can also replicate to additional slaves in a tree-like fashion. If the master goes offline, the system can continue to operate in read-only mode until a slave is promoted to a master or a new master is provisioned.

- +
Source: Scalability, availability, stability, patterns

@@ -797,7 +842,7 @@ The master serves reads and writes, replicating writes to one or more slaves, wh Both masters serve reads and writes and coordinate with each other on writes. If either master goes down, the system can continue to operate with both reads and writes.

- +
Source: Scalability, availability, stability, patterns

@@ -825,9 +870,9 @@ Both masters serve reads and writes and coordinate with each other on writes. I #### Federation

- +
- Source: Scaling up to your first 10 million users + Source: Scaling up to your first 10 million users

Federation (or functional partitioning) splits up databases by function. For example, instead of a single, monolithic database, you could have three databases: **forums**, **users**, and **products**, resulting in less read and write traffic to each database and therefore less replication lag. Smaller databases result in more data that can fit in memory, which in turn results in more cache hits due to improved cache locality. With no single central master serializing writes you can write in parallel, increasing throughput. @@ -841,12 +886,12 @@ Federation (or functional partitioning) splits up databases by function. For ex ##### Source(s) and further reading: federation -* [Scaling up to your first 10 million users](https://www.youtube.com/watch?v=vg5onp8TU6Q) +* [Scaling up to your first 10 million users](https://www.youtube.com/watch?v=w95murBkYmU) #### Sharding

- +
Source: Scalability, availability, stability, patterns

@@ -877,7 +922,7 @@ Denormalization attempts to improve read performance at the expense of some writ Once data becomes distributed with techniques such as [federation](#federation) and [sharding](#sharding), managing joins across data centers further increases complexity. Denormalization might circumvent the need for such complex joins. -In most systems, reads can heavily number writes 100:1 or even 1000:1. A read resulting in a complex database join can be very expensive, spending a significant amount of time on disk operations. +In most systems, reads can heavily outnumber writes 100:1 or even 1000:1. A read resulting in a complex database join can be very expensive, spending a significant amount of time on disk operations. ##### Disadvantage(s): denormalization @@ -930,18 +975,18 @@ Benchmarking and profiling might point you to the following optimizations. ##### Tune the query cache -* In some cases, the [query cache](http://dev.mysql.com/doc/refman/5.7/en/query-cache) could lead to [performance issues](https://www.percona.com/blog/2014/01/28/10-mysql-performance-tuning-settings-after-installation/). +* In some cases, the [query cache](https://dev.mysql.com/doc/refman/5.7/en/query-cache.html) could lead to [performance issues](https://www.percona.com/blog/2016/10/12/mysql-5-7-performance-tuning-immediately-after-installation/). ##### Source(s) and further reading: SQL tuning -* [Tips for optimizing MySQL queries](http://20bits.com/article/10-tips-for-optimizing-mysql-queries-that-dont-suck) +* [Tips for optimizing MySQL queries](http://aiddroid.com/10-tips-optimizing-mysql-queries-dont-suck/) * [Is there a good reason i see VARCHAR(255) used so often?](http://stackoverflow.com/questions/1217466/is-there-a-good-reason-i-see-varchar255-used-so-often-as-opposed-to-another-l) * [How do null values affect performance?](http://stackoverflow.com/questions/1017239/how-do-null-values-affect-performance-in-a-database-search) * [Slow query log](http://dev.mysql.com/doc/refman/5.7/en/slow-query-log.html) ### NoSQL -NoSQL is a collection of data items represented in a **key-value store**, **document-store**, **wide column store**, or a **graph database**. Data is denormalized, and joins are generally done in the application code. Most NoSQL stores lack true ACID transactions and favor [eventual consistency](#eventual-consistency). +NoSQL is a collection of data items represented in a **key-value store**, **document store**, **wide column store**, or a **graph database**. Data is denormalized, and joins are generally done in the application code. Most NoSQL stores lack true ACID transactions and favor [eventual consistency](#eventual-consistency). **BASE** is often used to describe the properties of NoSQL databases. In comparison with the [CAP Theorem](#cap-theorem), BASE chooses availability over consistency. @@ -949,7 +994,7 @@ NoSQL is a collection of data items represented in a **key-value store**, **docu * **Soft state** - the state of the system may change over time, even without input. * **Eventual consistency** - the system will become consistent over a period of time, given that the system doesn't receive input during that period. -In addition to choosing between [SQL or NoSQL](#sql-or-nosql), it is helpful to understand which type of NoSQL database best fits your use case(s). We'll review **key-value stores**, **document-stores**, **wide column stores**, and **graph databases** in the next section. +In addition to choosing between [SQL or NoSQL](#sql-or-nosql), it is helpful to understand which type of NoSQL database best fits your use case(s). We'll review **key-value stores**, **document stores**, **wide column stores**, and **graph databases** in the next section. #### Key-value store @@ -974,7 +1019,7 @@ A key-value store is the basis for more complex systems such as a document store A document store is centered around documents (XML, JSON, binary, etc), where a document stores all information for a given object. Document stores provide APIs or a query language to query based on the internal structure of the document itself. *Note, many key-value stores include features for working with a value's metadata, blurring the lines between these two storage types.* -Based on the underlying implementation, documents are organized in either collections, tags, metadata, or directories. Although documents can be organized or grouped together, documents may have fields that are completely different from each other. +Based on the underlying implementation, documents are organized by collections, tags, metadata, or directories. Although documents can be organized or grouped together, documents may have fields that are completely different from each other. Some document stores like [MongoDB](https://www.mongodb.com/mongodb-architecture) and [CouchDB](https://blog.couchdb.org/2016/08/01/couchdb-2-0-architecture/) also provide a SQL-like language to perform complex queries. [DynamoDB](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/decandia07dynamo.pdf) supports both key-values and documents. @@ -990,7 +1035,7 @@ Document stores provide high flexibility and are often used for working with occ #### Wide column store

- +
Source: SQL & NoSQL, a brief history

@@ -999,7 +1044,7 @@ Document stores provide high flexibility and are often used for working with occ 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](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/chang06bigtable.pdf) as the first wide column store, which influenced the open-source [HBase](https://www.mapr.com/blog/in-depth-look-hbase-architecture) often-used in the Hadoop ecosystem, and [Cassandra](http://docs.datastax.com/en/archived/cassandra/2.0/cassandra/architecture/architectureIntro_c.html) from Facebook. Stores such as BigTable, HBase, and Cassandra maintain keys in lexicographic order, allowing efficient retrieval of selective key ranges. +Google introduced [Bigtable](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/chang06bigtable.pdf) as the first wide column store, which influenced the open-source [HBase](https://www.mapr.com/blog/in-depth-look-hbase-architecture) often-used in the Hadoop ecosystem, and [Cassandra](http://docs.datastax.com/en/cassandra/3.0/cassandra/architecture/archIntro.html) 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. @@ -1008,12 +1053,12 @@ Wide column stores offer high availability and high scalability. They are often * [SQL & NoSQL, a brief history](http://blog.grio.com/2015/11/sql-nosql-a-brief-history.html) * [Bigtable architecture](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/chang06bigtable.pdf) * [HBase architecture](https://www.mapr.com/blog/in-depth-look-hbase-architecture) -* [Cassandra architecture](http://docs.datastax.com/en/archived/cassandra/2.0/cassandra/architecture/architectureIntro_c.html) +* [Cassandra architecture](http://docs.datastax.com/en/cassandra/3.0/cassandra/architecture/archIntro.html) #### Graph database

- +
Source: Graph database

@@ -1041,7 +1086,7 @@ Graphs databases offer high performance for data models with complex relationshi ### SQL or NoSQL

- +
Source: Transitioning from RDBMS to NoSQL

@@ -1061,7 +1106,7 @@ Reasons for **NoSQL**: * Semi-structured data * Dynamic or flexible schema -* Non relational data +* Non-relational data * No need for complex joins * Store many TB (or PB) of data * Very data intensive workload @@ -1077,13 +1122,13 @@ Sample data well-suited for NoSQL: ##### Source(s) and further reading: SQL or NoSQL -* [Scaling up to your first 10 million users](https://www.youtube.com/watch?v=vg5onp8TU6Q) +* [Scaling up to your first 10 million users](https://www.youtube.com/watch?v=w95murBkYmU) * [SQL vs NoSQL differences](https://www.sitepoint.com/sql-vs-nosql-differences/) ## Cache

- +
Source: Scalable system design patterns

@@ -1094,7 +1139,7 @@ Databases often benefit from a uniform distribution of reads and writes across i ### Client caching -Caches can be located on the client side (OS or browser), [server side](#reverse-proxy), or in a distinct cache layer. +Caches can be located on the client side (OS or browser), [server side](#reverse-proxy-web-server), or in a distinct cache layer. ### CDN caching @@ -1154,7 +1199,7 @@ Since you can only store a limited amount of data in cache, you'll need to deter #### Cache-aside

- +
Source: From cache to in-memory data grid

@@ -1166,7 +1211,7 @@ The application is responsible for reading and writing from storage. The cache * Add entry to cache * Return entry -``` +```python def get_user(self, user_id): user = cache.get("user.{0}", user_id) if user is None: @@ -1190,7 +1235,7 @@ Subsequent reads of data added to cache are fast. Cache-aside is also referred #### Write-through

- +
Source: Scalability, availability, stability, patterns

@@ -1203,13 +1248,13 @@ The application uses the cache as the main data store, reading and writing data Application code: -``` +```python set_user(12345, {"foo":"bar"}) ``` Cache code: -``` +```python def set_user(user_id, values): user = db.query("UPDATE Users WHERE id = {0}", user_id, values) cache.set(user_id, user) @@ -1220,12 +1265,12 @@ Write-through is a slow overall operation due to the write operation, but subseq ##### Disadvantage(s): write through * When a new node is created due to failure or scaling, the new node will not cache entries until the entry is updated in the database. Cache-aside in conjunction with write through can mitigate this issue. -* Most data written might never read, which can be minimized with a TTL. +* Most data written might never be read, which can be minimized with a TTL. #### Write-behind (write-back)

- +
Source: Scalability, availability, stability, patterns

@@ -1243,7 +1288,7 @@ In write-behind, the application does the following: #### Refresh-ahead

- +
Source: From cache to in-memory data grid

@@ -1259,8 +1304,8 @@ Refresh-ahead can result in reduced latency vs read-through if the cache can acc ### Disadvantage(s): cache * Need to maintain consistency between caches and the source of truth such as the database through [cache invalidation](https://en.wikipedia.org/wiki/Cache_algorithms). -* Need to make application changes such as adding Redis or memcached. * Cache invalidation is a difficult problem, there is additional complexity associated with when to update the cache. +* Need to make application changes such as adding Redis or memcached. ### Source(s) and further reading @@ -1275,7 +1320,7 @@ Refresh-ahead can result in reduced latency vs read-through if the cache can acc ## Asynchronism

- +
Source: Intro to architecting systems for scale

@@ -1291,11 +1336,11 @@ Message queues receive, hold, and deliver messages. If an operation is too slow 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. +**[Redis](https://redis.io/)** 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. +**[RabbitMQ](https://www.rabbitmq.com/)** 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. +**[Amazon SQS](https://aws.amazon.com/sqs/)** is hosted but can have high latency and has the possibility of messages being delivered twice. ### Task queues @@ -1321,7 +1366,7 @@ If queues start to grow significantly, the queue size can become larger than mem ## Communication

- +
Source: OSI 7 layer model

@@ -1353,7 +1398,7 @@ HTTP is an application layer protocol relying on lower-level protocols such as * ### Transmission control protocol (TCP)

- +
Source: How to make a multiplayer game

@@ -1365,7 +1410,7 @@ TCP is a connection-oriented protocol over an [IP network](https://en.wikipedia. 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](https://en.wikipedia.org/wiki/Flow_control_(data)) and [congestion control](https://en.wikipedia.org/wiki/Network_congestion#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](#memcached) server. [Connection pooling](https://en.wikipedia.org/wiki/Connection_pool) can help in addition to switching to UDP where applicable. +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](https://memcached.org/) server. [Connection pooling](https://en.wikipedia.org/wiki/Connection_pool) 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. @@ -1377,7 +1422,7 @@ Use TCP over UDP when: ### User datagram protocol (UDP)

- +
Source: How to make a multiplayer game

@@ -1406,9 +1451,9 @@ Use UDP over TCP when: ### Remote procedure call (RPC)

- +
- Source: Crack the system design interview + 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](https://developers.google.com/protocol-buffers/), [Thrift](https://thrift.apache.org/), and [Avro](https://avro.apache.org/docs/current/). @@ -1485,12 +1530,12 @@ REST is focused on exposing data. It minimizes the coupling between client/serv | Operation | RPC | REST | |---|---|---| -| Signup | **POST** /signup | **POST** /persons | -| Resign | **POST** /resign
{
"personid": "1234"
} | **DELETE** /persons/1234 | +| 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"
} | +| Update an item | **POST** /modifyItem
{
"itemid": "456";
"key": "value"
} | **PUT** /items/456
{
"key": "value"
} | | Delete an item | **POST** /removeItem
{
"itemid": "456"
} | **DELETE** /items/456 |

@@ -1504,7 +1549,7 @@ REST is focused on exposing data. It minimizes the coupling between client/serv * [REST vs JSON-RPC](http://stackoverflow.com/questions/15056878/rest-vs-json-rpc) * [Debunking the myths of RPC and REST](http://etherealbits.com/2012/12/debunking-the-myths-of-rpc-rest/) * [What are the drawbacks of using REST](https://www.quora.com/What-are-the-drawbacks-of-using-RESTful-APIs) -* [Crack the system design interview](http://www.puncsky.com/blog/2016/02/14/crack-the-system-design-interview/) +* [Crack the system design interview](http://www.puncsky.com/blog/2016-02-13-crack-the-system-design-interview) * [Thrift](https://code.facebook.com/posts/1468950976659943/) * [Why REST for internal use and not RPC](http://arstechnica.com/civis/viewtopic.php?t=1190508) @@ -1555,7 +1600,7 @@ Latency Comparison Numbers L1 cache reference 0.5 ns Branch mispredict 5 ns L2 cache reference 7 ns 14x L1 cache -Mutex lock/unlock 100 ns +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 @@ -1602,12 +1647,12 @@ Handy metrics based on numbers above: | Question | Reference(s) | |---|---| | Design a file sync service like Dropbox | [youtube.com](https://www.youtube.com/watch?v=PE4gwstWhmc) | -| Design a search engine like Google | [queue.acm.org](http://queue.acm.org/detail.cfm?id=988407)
[stackexchange.com](http://programmers.stackexchange.com/questions/38324/interview-question-how-would-you-implement-google-search)
[ardendertat.com](http://www.ardendertat.com/2012/01/11/implementing-search-engines/)
[stanford.edu](http://infolab.stanford.edu/~backrub/google.html) | +| Design a search engine like Google | [queue.acm.org](http://queue.acm.org/detail.cfm?id=988407)
[stackexchange.com](http://programmers.stackexchange.com/questions/38324/interview-question-how-would-you-implement-google-search)
[ardendertat.com](http://www.ardendertat.com/2012/01/11/implementing-search-engines/)
[stanford.edu](http://infolab.stanford.edu/~backrub/google.html) | | Design a scalable web crawler like Google | [quora.com](https://www.quora.com/How-can-I-build-a-web-crawler-from-scratch) | | Design Google docs | [code.google.com](https://code.google.com/p/google-mobwrite/)
[neil.fraser.name](https://neil.fraser.name/writing/sync/) | | Design a key-value store like Redis | [slideshare.net](http://www.slideshare.net/dvirsky/introduction-to-redis) | | Design a cache system like Memcached | [slideshare.net](http://www.slideshare.net/oemebamo/introduction-to-memcached) | -| Design a recommendation system like Amazon's | [hulu.com](http://tech.hulu.com/blog/2011/09/19/recommendation-system.html)
[ijcai13.org](http://ijcai13.org/files/tutorial_slides/td3.pdf) | +| Design a recommendation system like Amazon's | [hulu.com](https://web.archive.org/web/20170406065247/http://tech.hulu.com/blog/2011/09/19/recommendation-system.html)
[ijcai13.org](http://ijcai13.org/files/tutorial_slides/td3.pdf) | | Design a tinyurl system like Bitly | [n00tc0d3r.blogspot.com](http://n00tc0d3r.blogspot.com/) | | Design a chat app like WhatsApp | [highscalability.com](http://highscalability.com/blog/2014/2/26/the-whatsapp-architecture-facebook-bought-for-19-billion.html) | Design a picture sharing system like Instagram | [highscalability.com](http://highscalability.com/flickr-architecture)
[highscalability.com](http://highscalability.com/blog/2011/12/6/instagram-architecture-14-million-users-terabytes-of-photos.html) | @@ -1615,13 +1660,14 @@ Handy metrics based on numbers above: | Design the Facebook timeline function | [facebook.com](https://www.facebook.com/note.php?note_id=10150468255628920)
[highscalability.com](http://highscalability.com/blog/2012/1/23/facebook-timeline-brought-to-you-by-the-power-of-denormaliza.html) | | Design the Facebook chat function | [erlang-factory.com](http://www.erlang-factory.com/upload/presentations/31/EugeneLetuchy-ErlangatFacebook.pdf)
[facebook.com](https://www.facebook.com/note.php?note_id=14218138919&id=9445547199&index=0) | | Design a graph search function like Facebook's | [facebook.com](https://www.facebook.com/notes/facebook-engineering/under-the-hood-building-out-the-infrastructure-for-graph-search/10151347573598920)
[facebook.com](https://www.facebook.com/notes/facebook-engineering/under-the-hood-indexing-and-ranking-in-graph-search/10151361720763920)
[facebook.com](https://www.facebook.com/notes/facebook-engineering/under-the-hood-the-natural-language-interface-of-graph-search/10151432733048920) | -| Design a content delivery network like CloudFlare | [cmu.edu](http://repository.cmu.edu/cgi/viewcontent.cgi?article=2112&context=compsci) | +| Design a content delivery network like CloudFlare | [figshare.com](https://figshare.com/articles/Globally_distributed_content_delivery/6605972) | | Design a trending topic system like Twitter's | [michael-noll.com](http://www.michael-noll.com/blog/2013/01/18/implementing-real-time-trending-topics-in-storm/)
[snikolov .wordpress.com](http://snikolov.wordpress.com/2012/11/14/early-detection-of-twitter-trends/) | | Design a random ID generation system | [blog.twitter.com](https://blog.twitter.com/2010/announcing-snowflake)
[github.com](https://github.com/twitter/snowflake/) | -| Return the top k requests during a time interval | [ucsb.edu](https://icmi.cs.ucsb.edu/research/tech_reports/reports/2005-23.pdf)
[wpi.edu](http://davis.wpi.edu/xmdv/docs/EDBT11-diyang.pdf) | +| Return the top k requests during a time interval | [cs.ucsb.edu](https://www.cs.ucsb.edu/sites/cs.ucsb.edu/files/docs/reports/2005-23.pdf)
[wpi.edu](http://davis.wpi.edu/xmdv/docs/EDBT11-diyang.pdf) | | Design a system that serves data from multiple data centers | [highscalability.com](http://highscalability.com/blog/2009/8/24/how-google-serves-data-from-multiple-datacenters.html) | | Design an online multiplayer card game | [indieflashblog.com](http://www.indieflashblog.com/how-to-create-an-asynchronous-multiplayer-game.html)
[buildnewgames.com](http://buildnewgames.com/real-time-multiplayer/) | | Design a garbage collection system | [stuffwithstuff.com](http://journal.stuffwithstuff.com/2013/12/08/babys-first-garbage-collector/)
[washington.edu](http://courses.cs.washington.edu/courses/csep521/07wi/prj/rick.pdf) | +| Design an API rate limiter | [https://stripe.com/blog/](https://stripe.com/blog/rate-limiters) | | Add a system design question | [Contribute](#contributing) | ### Real world architectures @@ -1629,7 +1675,7 @@ Handy metrics based on numbers above: > Articles on how real world systems are designed.

- +
Source: Twitter timelines at scale

@@ -1656,7 +1702,7 @@ Handy metrics based on numbers above: | Data store | **Redis** - Distributed memory caching system with persistence and value types | [slideshare.net](http://www.slideshare.net/dvirsky/introduction-to-redis) | | | | | | File system | **Google File System (GFS)** - Distributed file system | [research.google.com](http://static.googleusercontent.com/media/research.google.com/zh-CN/us/archive/gfs-sosp2003.pdf) | -| File system | **Hadoop File System (HDFS)** - Open source implementation of GFS | [apache.org](https://hadoop.apache.org/docs/r1.2.1/hdfs_design.html) | +| File system | **Hadoop File System (HDFS)** - Open source implementation of GFS | [apache.org](http://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html) | | | | | | Misc | **Chubby** - Lock service for loosely-coupled distributed systems from Google | [research.google.com](http://static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/en/us/archive/chubby-osdi06.pdf) | | Misc | **Dapper** - Distributed systems tracing infrastructure | [research.google.com](http://static.googleusercontent.com/media/research.google.com/en//pubs/archive/36356.pdf) @@ -1676,9 +1722,10 @@ Handy metrics based on numbers above: | Google | [Google architecture](http://highscalability.com/google-architecture) | | Instagram | [14 million users, terabytes of photos](http://highscalability.com/blog/2011/12/6/instagram-architecture-14-million-users-terabytes-of-photos.html)
[What powers Instagram](http://instagram-engineering.tumblr.com/post/13649370142/what-powers-instagram-hundreds-of-instances) | | Justin.tv | [Justin.Tv's live video broadcasting architecture](http://highscalability.com/blog/2010/3/16/justintvs-live-video-broadcasting-architecture.html) | -| Facebook | [Scaling memcached at Facebook](https://cs.uwaterloo.ca/~brecht/courses/854-Emerging-2014/readings/key-value/fb-memcached-nsdi-2013.pdf)
[TAO: Facebook’s distributed data store for the social graph](https://cs.uwaterloo.ca/~brecht/courses/854-Emerging-2014/readings/data-store/tao-facebook-distributed-datastore-atc-2013.pdf)
[Facebook’s photo storage](https://www.usenix.org/legacy/event/osdi10/tech/full_papers/Beaver.pdf) | +| Facebook | [Scaling memcached at Facebook](https://cs.uwaterloo.ca/~brecht/courses/854-Emerging-2014/readings/key-value/fb-memcached-nsdi-2013.pdf)
[TAO: Facebook’s distributed data store for the social graph](https://cs.uwaterloo.ca/~brecht/courses/854-Emerging-2014/readings/data-store/tao-facebook-distributed-datastore-atc-2013.pdf)
[Facebook’s photo storage](https://www.usenix.org/legacy/event/osdi10/tech/full_papers/Beaver.pdf)
[How Facebook Live Streams To 800,000 Simultaneous Viewers](http://highscalability.com/blog/2016/6/27/how-facebook-live-streams-to-800000-simultaneous-viewers.html) | | Flickr | [Flickr architecture](http://highscalability.com/flickr-architecture) | | Mailbox | [From 0 to one million users in 6 weeks](http://highscalability.com/blog/2013/6/18/scaling-mailbox-from-0-to-one-million-users-in-6-weeks-and-1.html) | +| Netflix | [A 360 Degree View Of The Entire Netflix Stack](http://highscalability.com/blog/2015/11/9/a-360-degree-view-of-the-entire-netflix-stack.html)
[Netflix: What Happens When You Press Play?](http://highscalability.com/blog/2017/12/11/netflix-what-happens-when-you-press-play.html) | | Pinterest | [From 0 To 10s of billions of page views a month](http://highscalability.com/blog/2013/4/15/scaling-pinterest-from-0-to-10s-of-billions-of-page-views-a.html)
[18 million visitors, 10x growth, 12 employees](http://highscalability.com/blog/2012/5/21/pinterest-architecture-update-18-million-visitors-10x-growth.html) | | Playfish | [50 million monthly users and growing](http://highscalability.com/blog/2010/9/21/playfishs-social-gaming-architecture-50-million-monthly-user.html) | | PlentyOfFish | [PlentyOfFish architecture](http://highscalability.com/plentyoffish-architecture) | @@ -1686,8 +1733,8 @@ Handy metrics based on numbers above: | Stack Overflow | [Stack Overflow architecture](http://highscalability.com/blog/2009/8/5/stack-overflow-architecture.html) | | TripAdvisor | [40M visitors, 200M dynamic page views, 30TB data](http://highscalability.com/blog/2011/6/27/tripadvisor-architecture-40m-visitors-200m-dynamic-page-view.html) | | Tumblr | [15 billion page views a month](http://highscalability.com/blog/2012/2/13/tumblr-architecture-15-billion-page-views-a-month-and-harder.html) | -| Twitter | [Making Twitter 10000 percent faster](http://highscalability.com/scaling-twitter-making-twitter-10000-percent-faster)
[Storing 250 million tweets a day using MySQL](http://highscalability.com/blog/2011/12/19/how-twitter-stores-250-million-tweets-a-day-using-mysql.html)
[150M active users, 300K QPS, a 22 MB/S firehose](http://highscalability.com/blog/2013/7/8/the-architecture-twitter-uses-to-deal-with-150m-active-users.html)
[Timelines at scale](https://www.infoq.com/presentations/Twitter-Timeline-Scalability)
[Big and small data at Twitter](https://www.youtube.com/watch?v=5cKTP36HVgI)
[Operations at Twitter: scaling beyond 100 million users](https://www.youtube.com/watch?v=z8LU0Cj6BOU) | -| Uber | [How Uber scales their real-time market platform](http://highscalability.com/blog/2015/9/14/how-uber-scales-their-real-time-market-platform.html) | +| Twitter | [Making Twitter 10000 percent faster](http://highscalability.com/scaling-twitter-making-twitter-10000-percent-faster)
[Storing 250 million tweets a day using MySQL](http://highscalability.com/blog/2011/12/19/how-twitter-stores-250-million-tweets-a-day-using-mysql.html)
[150M active users, 300K QPS, a 22 MB/S firehose](http://highscalability.com/blog/2013/7/8/the-architecture-twitter-uses-to-deal-with-150m-active-users.html)
[Timelines at scale](https://www.infoq.com/presentations/Twitter-Timeline-Scalability)
[Big and small data at Twitter](https://www.youtube.com/watch?v=5cKTP36HVgI)
[Operations at Twitter: scaling beyond 100 million users](https://www.youtube.com/watch?v=z8LU0Cj6BOU)
[How Twitter Handles 3,000 Images Per Second](http://highscalability.com/blog/2016/4/20/how-twitter-handles-3000-images-per-second.html) | +| Uber | [How Uber scales their real-time market platform](http://highscalability.com/blog/2015/9/14/how-uber-scales-their-real-time-market-platform.html)
[Lessons Learned From Scaling Uber To 2000 Engineers, 1000 Services, And 8000 Git Repositories](http://highscalability.com/blog/2016/10/12/lessons-learned-from-scaling-uber-to-2000-engineers-1000-ser.html) | | WhatsApp | [The WhatsApp architecture Facebook bought for $19 billion](http://highscalability.com/blog/2014/2/26/the-whatsapp-architecture-facebook-bought-for-19-billion.html) | | YouTube | [YouTube scalability](https://www.youtube.com/watch?v=w5WVu624fY8)
[YouTube architecture](http://highscalability.com/youtube-architecture) | @@ -1699,11 +1746,10 @@ Handy metrics based on numbers above: * [Airbnb Engineering](http://nerds.airbnb.com/) * [Atlassian Developers](https://developer.atlassian.com/blog/) -* [Autodesk Engineering](http://cloudengineering.autodesk.com/blog/) * [AWS Blog](https://aws.amazon.com/blogs/aws/) * [Bitly Engineering Blog](http://word.bitly.com/) -* [Box Blogs](https://www.box.com/blog/engineering/) -* [Cloudera Developer Blog](http://blog.cloudera.com/blog/) +* [Box Blogs](https://blog.box.com/blog/category/engineering) +* [Cloudera Developer Blog](http://blog.cloudera.com/) * [Dropbox Tech Blog](https://tech.dropbox.com/) * [Engineering at Quora](http://engineering.quora.com/) * [Ebay Tech Blog](http://www.ebaytechblog.com/) @@ -1726,14 +1772,14 @@ Handy metrics based on numbers above: * [Microsoft Python Engineering](https://blogs.msdn.microsoft.com/pythonengineering/) * [Netflix Tech Blog](http://techblog.netflix.com/) * [Paypal Developer Blog](https://devblog.paypal.com/category/engineering/) -* [Pinterest Engineering Blog](http://engineering.pinterest.com/) +* [Pinterest Engineering Blog](https://medium.com/@Pinterest_Engineering) * [Quora Engineering](https://engineering.quora.com/) * [Reddit Blog](http://www.redditblog.com/) * [Salesforce Engineering Blog](https://developer.salesforce.com/blogs/engineering/) * [Slack Engineering Blog](https://slack.engineering/) * [Spotify Labs](https://labs.spotify.com/) * [Twilio Engineering Blog](http://www.twilio.com/engineering) -* [Twitter Engineering](https://engineering.twitter.com/) +* [Twitter Engineering](https://blog.twitter.com/engineering/) * [Uber Engineering Blog](http://eng.uber.com/) * [Yahoo Engineering Blog](http://yahooeng.tumblr.com/) * [Yelp Engineering Blog](http://engineeringblog.yelp.com/) @@ -1741,6 +1787,8 @@ Handy metrics based on numbers above: #### Source(s) and further reading +Looking to add a blog? To avoid duplicating work, consider adding your company blog to the following repo: + * [kilimchoi/engineering-blogs](https://github.com/kilimchoi/engineering-blogs) ## Under development @@ -1766,7 +1814,7 @@ Special thanks to: * [mmcgrana/services-engineering](https://github.com/mmcgrana/services-engineering) * [System design cheat sheet](https://gist.github.com/vasanthk/485d1c25737e8e72759f) * [A distributed systems reading list](http://dancres.github.io/Pages/) -* [Cracking the system design interview](http://www.puncsky.com/blog/2016/02/14/crack-the-system-design-interview/) +* [Cracking the system design interview](http://www.puncsky.com/blog/2016-02-13-crack-the-system-design-interview) ## Contact info @@ -1776,6 +1824,10 @@ My contact info can be found on my [GitHub page](https://github.com/donnemartin) ## License +*I am providing code and resources in this repository to you under an open source license. Because this is my personal repository, the license you receive to my code and resources is from me and not my employer (Facebook).* + + Copyright 2017 Donne Martin + Creative Commons Attribution 4.0 International License (CC BY 4.0) http://creativecommons.org/licenses/by/4.0/ diff --git a/epub-metadata.yaml b/epub-metadata.yaml new file mode 100644 index 00000000000..f4b296baf92 --- /dev/null +++ b/epub-metadata.yaml @@ -0,0 +1,3 @@ +title: System Design Primer +creator: Donne Martin +date: 2018 \ No newline at end of file diff --git a/generate-epub.sh b/generate-epub.sh new file mode 100755 index 00000000000..d7c21241b80 --- /dev/null +++ b/generate-epub.sh @@ -0,0 +1,40 @@ +#! /usr/bin/env sh + +generate_from_stdin() { + outfile=$1 + language=$2 + + echo "Generating '$language' ..." + + pandoc --metadata-file=epub-metadata.yaml --metadata=lang:$2 --from=markdown -o $1 <&0 + + echo "Done! You can find the '$language' book at ./$outfile" +} + +generate_with_solutions () { + tmpfile=$(mktemp /tmp/sytem-design-primer-epub-generator.XXX) + + cat ./README.md >> $tmpfile + + for dir in ./solutions/system_design/*; do + case $dir in *template*) continue;; esac + case $dir in *__init__.py*) continue;; esac + : [[ -d "$dir" ]] && ( cd "$dir" && cat ./README.md >> $tmpfile && echo "" >> $tmpfile ) + done + + cat $tmpfile | generate_from_stdin 'README.epub' 'en' + + rm "$tmpfile" +} + +generate () { + name=$1 + language=$2 + + cat $name.md | generate_from_stdin $name.epub $language +} + +generate_with_solutions +generate README-ja ja +generate README-zh-Hans zh-Hans +generate README-zh-TW zh-TW diff --git a/solutions/object_oriented_design/call_center/call_center.ipynb b/solutions/object_oriented_design/call_center/call_center.ipynb index deac342c6b4..c540c6a6422 100644 --- a/solutions/object_oriented_design/call_center/call_center.ipynb +++ b/solutions/object_oriented_design/call_center/call_center.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer-primer)." + "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer)." ] }, { @@ -24,9 +24,9 @@ " * Operator, supervisor, director\n", "* Can we assume operators always get the initial calls?\n", " * Yes\n", - "* If there is no free operators or the operator can't handle the call, does the call go to the supervisors?\n", + "* If there is no available operators or the operator can't handle the call, does the call go to the supervisors?\n", " * Yes\n", - "* If there is no free supervisors or the supervisor can't handle the call, does the call go to the directors?\n", + "* If there is no available supervisors or the supervisor can't handle the call, does the call go to the directors?\n", " * Yes\n", "* Can we assume the directors can handle all calls?\n", " * Yes\n", diff --git a/solutions/object_oriented_design/call_center/call_center.py b/solutions/object_oriented_design/call_center/call_center.py index 7bdd992b386..a2785594478 100644 --- a/solutions/object_oriented_design/call_center/call_center.py +++ b/solutions/object_oriented_design/call_center/call_center.py @@ -112,6 +112,11 @@ def _dispatch_call(self, call, employees): return employee return None - def notify_call_escalated(self, call): # ... - def notify_call_completed(self, call): # ... - def dispatch_queued_call_to_newly_freed_employee(self, call, employee): # ... \ No newline at end of file + def notify_call_escalated(self, call): + pass + + def notify_call_completed(self, call): + pass + + def dispatch_queued_call_to_newly_freed_employee(self, call, employee): + pass diff --git a/solutions/object_oriented_design/deck_of_cards/deck_of_cards.ipynb b/solutions/object_oriented_design/deck_of_cards/deck_of_cards.ipynb index 3c19e1fbe98..45b217a0ff0 100644 --- a/solutions/object_oriented_design/deck_of_cards/deck_of_cards.ipynb +++ b/solutions/object_oriented_design/deck_of_cards/deck_of_cards.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer-primer)." + "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer)." ] }, { @@ -89,11 +89,11 @@ " super(BlackJackCard, self).__init__(value, suit)\n", "\n", " def is_ace(self):\n", - " return True if self._value == 1 else False\n", + " return self._value == 1\n", "\n", " def is_face_card(self):\n", " \"\"\"Jack = 11, Queen = 12, King = 13\"\"\"\n", - " return True if 10 < self._value <= 13 else False\n", + " return 10 < self._value <= 13\n", "\n", " @property\n", " def value(self):\n", diff --git a/solutions/object_oriented_design/deck_of_cards/deck_of_cards.py b/solutions/object_oriented_design/deck_of_cards/deck_of_cards.py index 2ec4f1bc90b..a47087585e0 100644 --- a/solutions/object_oriented_design/deck_of_cards/deck_of_cards.py +++ b/solutions/object_oriented_design/deck_of_cards/deck_of_cards.py @@ -68,7 +68,7 @@ def add_card(self, card): def score(self): total_value = 0 - for card in card: + for card in self.cards: total_value += card.value return total_value @@ -92,7 +92,7 @@ def score(self): def possible_scores(self): """Return a list of possible scores, taking Aces into account.""" - # ... + pass class Deck(object): @@ -102,9 +102,9 @@ def __init__(self, cards): self.deal_index = 0 def remaining_cards(self): - return len(self.cards) - deal_index + return len(self.cards) - self.deal_index - def deal_card(): + def deal_card(self): try: card = self.cards[self.deal_index] card.is_available = False @@ -113,4 +113,5 @@ def deal_card(): return None return card - def shuffle(self): # ... \ No newline at end of file + def shuffle(self): + pass diff --git a/solutions/object_oriented_design/hash_table/hash_map.ipynb b/solutions/object_oriented_design/hash_table/hash_map.ipynb index b5728897478..92713d94bb7 100644 --- a/solutions/object_oriented_design/hash_table/hash_map.ipynb +++ b/solutions/object_oriented_design/hash_table/hash_map.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer-primer)." + "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer)." ] }, { diff --git a/solutions/object_oriented_design/hash_table/hash_map.py b/solutions/object_oriented_design/hash_table/hash_map.py index beceb7738a2..33d9a35de15 100644 --- a/solutions/object_oriented_design/hash_table/hash_map.py +++ b/solutions/object_oriented_design/hash_table/hash_map.py @@ -35,4 +35,4 @@ def remove(self, key): if item.key == key: del self.table[hash_index][index] return - raise KeyError('Key not found') \ No newline at end of file + raise KeyError('Key not found') diff --git a/solutions/object_oriented_design/lru_cache/lru_cache.ipynb b/solutions/object_oriented_design/lru_cache/lru_cache.ipynb index e78966d1d6f..cd91da11ba5 100644 --- a/solutions/object_oriented_design/lru_cache/lru_cache.ipynb +++ b/solutions/object_oriented_design/lru_cache/lru_cache.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer-primer)." + "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer)." ] }, { @@ -21,7 +21,7 @@ "## Constraints and assumptions\n", "\n", "* What are we caching?\n", - " * We are cahing the results of web queries\n", + " * We are caching the results of web queries\n", "* Can we assume inputs are valid or do we have to validate them?\n", " * Assume they're valid\n", "* Can we assume this fits memory?\n", @@ -56,7 +56,8 @@ "\n", " def __init__(self, results):\n", " self.results = results\n", - " self.next = next\n", + " self.prev = None\n", + " self.next = None\n", "\n", "\n", "class LinkedList(object):\n", @@ -83,7 +84,7 @@ " \n", " Accessing a node updates its position to the front of the LRU list.\n", " \"\"\"\n", - " node = self.lookup[query]\n", + " node = self.lookup.get(query)\n", " if node is None:\n", " return None\n", " self.linked_list.move_to_front(node)\n", @@ -96,7 +97,7 @@ " If the entry is new and the cache is at capacity, removes the oldest entry\n", " before the new entry is added.\n", " \"\"\"\n", - " node = self.lookup[query]\n", + " node = self.lookup.get(query)\n", " if node is not None:\n", " # Key exists in cache, update the value\n", " node.results = results\n", diff --git a/solutions/object_oriented_design/lru_cache/lru_cache.py b/solutions/object_oriented_design/lru_cache/lru_cache.py index 3652aeb6127..acee46516eb 100644 --- a/solutions/object_oriented_design/lru_cache/lru_cache.py +++ b/solutions/object_oriented_design/lru_cache/lru_cache.py @@ -11,9 +11,14 @@ def __init__(self): self.head = None self.tail = None - def move_to_front(self, node): # ... - def append_to_front(self, node): # ... - def remove_from_tail(self): # ... + def move_to_front(self, node): + pass + + def append_to_front(self, node): + pass + + def remove_from_tail(self): + pass class Cache(object): @@ -24,12 +29,12 @@ def __init__(self, MAX_SIZE): self.lookup = {} # key: query, value: node self.linked_list = LinkedList() - def get(self, query) + def get(self, query): """Get the stored query result from the cache. - + Accessing a node updates its position to the front of the LRU list. """ - node = self.lookup[query] + node = self.lookup.get(query) if node is None: return None self.linked_list.move_to_front(node) @@ -37,12 +42,12 @@ def get(self, query) def set(self, results, query): """Set the result for the given query key in the cache. - + When updating an entry, updates its position to the front of the LRU list. If the entry is new and the cache is at capacity, removes the oldest entry before the new entry is added. """ - node = self.lookup[query] + node = self.lookup.get(query) if node is not None: # Key exists in cache, update the value node.results = results @@ -58,4 +63,4 @@ def set(self, results, query): # Add the new key and value new_node = Node(results) self.linked_list.append_to_front(new_node) - self.lookup[query] = new_node \ No newline at end of file + self.lookup[query] = new_node diff --git a/solutions/object_oriented_design/online_chat/online_chat.ipynb b/solutions/object_oriented_design/online_chat/online_chat.ipynb index 3e42f88efd0..b9f84ef424e 100644 --- a/solutions/object_oriented_design/online_chat/online_chat.ipynb +++ b/solutions/object_oriented_design/online_chat/online_chat.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer-primer)." + "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer)." ] }, { diff --git a/solutions/object_oriented_design/online_chat/online_chat.py b/solutions/object_oriented_design/online_chat/online_chat.py index d74262953da..7063ca04426 100644 --- a/solutions/object_oriented_design/online_chat/online_chat.py +++ b/solutions/object_oriented_design/online_chat/online_chat.py @@ -1,4 +1,5 @@ from abc import ABCMeta +from enum import Enum class UserService(object): @@ -6,11 +7,20 @@ class UserService(object): def __init__(self): self.users_by_id = {} # key: user id, value: User - def add_user(self, user_id, name, pass_hash): # ... - def remove_user(self, user_id): # ... - def add_friend_request(self, from_user_id, to_user_id): # ... - def approve_friend_request(self, from_user_id, to_user_id): # ... - def reject_friend_request(self, from_user_id, to_user_id): # ... + def add_user(self, user_id, name, pass_hash): + pass + + def remove_user(self, user_id): + pass + + def add_friend_request(self, from_user_id, to_user_id): + pass + + def approve_friend_request(self, from_user_id, to_user_id): + pass + + def reject_friend_request(self, from_user_id, to_user_id): + pass class User(object): @@ -25,12 +35,23 @@ def __init__(self, user_id, name, pass_hash): self.received_friend_requests_by_friend_id = {} # key: friend id, value: AddRequest self.sent_friend_requests_by_friend_id = {} # key: friend id, value: AddRequest - def message_user(self, friend_id, message): # ... - def message_group(self, group_id, message): # ... - def send_friend_request(self, friend_id): # ... - def receive_friend_request(self, friend_id): # ... - def approve_friend_request(self, friend_id): # ... - def reject_friend_request(self, friend_id): # ... + def message_user(self, friend_id, message): + pass + + def message_group(self, group_id, message): + pass + + def send_friend_request(self, friend_id): + pass + + def receive_friend_request(self, friend_id): + pass + + def approve_friend_request(self, friend_id): + pass + + def reject_friend_request(self, friend_id): + pass class Chat(metaclass=ABCMeta): @@ -51,8 +72,11 @@ def __init__(self, first_user, second_user): class GroupChat(Chat): - def add_user(self, user): # ... - def remove_user(self, user): # ... + def add_user(self, user): + pass + + def remove_user(self, user): + pass class Message(object): @@ -77,4 +101,4 @@ class RequestStatus(Enum): UNREAD = 0 READ = 1 ACCEPTED = 2 - REJECTED = 3 \ No newline at end of file + REJECTED = 3 diff --git a/solutions/object_oriented_design/parking_lot/parking_lot.ipynb b/solutions/object_oriented_design/parking_lot/parking_lot.ipynb index 4b37bf9d567..4613b79bded 100644 --- a/solutions/object_oriented_design/parking_lot/parking_lot.ipynb +++ b/solutions/object_oriented_design/parking_lot/parking_lot.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer-primer)." + "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer)." ] }, { @@ -71,7 +71,7 @@ " def __init__(self, vehicle_size, license_plate, spot_size):\n", " self.vehicle_size = vehicle_size\n", " self.license_plate = license_plate\n", - " self.spot_size\n", + " self.spot_size = spot_size\n", " self.spots_taken = []\n", "\n", " def clear_spots(self):\n", diff --git a/solutions/object_oriented_design/parking_lot/parking_lot.py b/solutions/object_oriented_design/parking_lot/parking_lot.py index c34c010b6e8..08852d9dc22 100644 --- a/solutions/object_oriented_design/parking_lot/parking_lot.py +++ b/solutions/object_oriented_design/parking_lot/parking_lot.py @@ -1,4 +1,5 @@ from abc import ABCMeta, abstractmethod +from enum import Enum class VehicleSize(Enum): @@ -44,7 +45,7 @@ def __init__(self, license_plate): super(Car, self).__init__(VehicleSize.COMPACT, license_plate, spot_size=1) def can_fit_in_spot(self, spot): - return True if (spot.size == LARGE or spot.size == COMPACT) else False + return spot.size in (VehicleSize.LARGE, VehicleSize.COMPACT) class Bus(Vehicle): @@ -53,7 +54,7 @@ def __init__(self, license_plate): super(Bus, self).__init__(VehicleSize.LARGE, license_plate, spot_size=5) def can_fit_in_spot(self, spot): - return True if spot.size == LARGE else False + return spot.size == VehicleSize.LARGE class ParkingLot(object): @@ -63,7 +64,7 @@ def __init__(self, num_levels): self.levels = [] # List of Levels def park_vehicle(self, vehicle): - for level in levels: + for level in self.levels: if level.park_vehicle(vehicle): return True return False @@ -92,11 +93,11 @@ def park_vehicle(self, vehicle): def _find_available_spot(self, vehicle): """Find an available spot where vehicle can fit, or return None""" - # ... + pass def _park_starting_at_spot(self, spot, vehicle): """Occupy starting at spot.spot_number to vehicle.spot_size.""" - # ... + pass class ParkingSpot(object): @@ -117,5 +118,8 @@ def can_fit_vehicle(self, vehicle): return False return vehicle.can_fit_in_spot(self) - def park_vehicle(self, vehicle): # ... - def remove_vehicle(self): # ... \ No newline at end of file + def park_vehicle(self, vehicle): + pass + + def remove_vehicle(self): + pass diff --git a/solutions/system_design/__init__.py b/solutions/system_design/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/solutions/system_design/mint/README.md b/solutions/system_design/mint/README.md index 654e82628a0..6fca19385a7 100644 --- a/solutions/system_design/mint/README.md +++ b/solutions/system_design/mint/README.md @@ -136,7 +136,7 @@ Data flow: * The **Client** sends a request to the **Web Server** * The **Web Server** forwards the request to the **Accounts API** server -* The **Accounts API** server places a job on a **Queue** such as Amazon SQS or [RabbitMQ](https://www.rabbitmq.com/) +* The **Accounts API** server places a job on a **Queue** such as [Amazon SQS](https://aws.amazon.com/sqs/) or [RabbitMQ](https://www.rabbitmq.com/) * Extracting transactions could take awhile, we'd probably want to do this [asynchronously with a queue](https://github.com/donnemartin/system-design-primer#asynchronism), although this introduces additional complexity * The **Transaction Extraction Service** does the following: * Pulls from the **Queue** and extracts transactions for the given account from the financial institution, storing the results as raw log files in the **Object Store** @@ -182,7 +182,7 @@ For the **Category Service**, we can seed a seller-to-category dictionary with t **Clarify with your interviewer how much code you are expected to write**. -``` +```python class DefaultCategories(Enum): HOUSING = 0 @@ -199,7 +199,7 @@ seller_category_map['Target'] = DefaultCategories.SHOPPING For sellers not initially seeded in the map, we could use a crowdsourcing effort by evaluating the manual category overrides our users provide. We could use a heap to quickly lookup the top manual override per seller in O(1) time. -``` +```python class Categorizer(object): def __init__(self, seller_category_map, self.seller_category_crowd_overrides_map): @@ -219,7 +219,7 @@ class Categorizer(object): Transaction implementation: -``` +```python class Transaction(object): def __init__(self, created_at, seller, amount): @@ -232,7 +232,7 @@ class Transaction(object): To start, we could use a generic budget template that allocates category amounts based on income tiers. Using this approach, we would not have to store the 100 million budget items identified in the constraints, only those that the user overrides. If a user overrides a budget category, which we could store the override in the `TABLE budget_overrides`. -``` +```python class Budget(object): def __init__(self, income): @@ -273,7 +273,7 @@ user_id timestamp seller amount **MapReduce** implementation: -``` +```python class SpendingByCategory(MRJob): def __init__(self, categorizer): @@ -349,7 +349,7 @@ We'll introduce some components to complete the design and to address scalabilit * [Relational database management system (RDBMS)](https://github.com/donnemartin/system-design-primer#relational-database-management-system-rdbms) * [SQL write master-slave failover](https://github.com/donnemartin/system-design-primer#fail-over) * [Master-slave replication](https://github.com/donnemartin/system-design-primer#master-slave-replication) -* [Asynchronism](https://github.com/donnemartin/system-design-primer#aysnchronism) +* [Asynchronism](https://github.com/donnemartin/system-design-primer#asynchronism) * [Consistency patterns](https://github.com/donnemartin/system-design-primer#consistency-patterns) * [Availability patterns](https://github.com/donnemartin/system-design-primer#availability-patterns) diff --git a/solutions/system_design/mint/mint_mapreduce.py b/solutions/system_design/mint/mint_mapreduce.py index 2e8339f84cf..e3554243018 100644 --- a/solutions/system_design/mint/mint_mapreduce.py +++ b/solutions/system_design/mint/mint_mapreduce.py @@ -30,12 +30,12 @@ def mapper(self, _, line): (2016-01, shopping), 100 (2016-01, gas), 50 """ - timestamp, seller, amount = line.split('\t') + timestamp, category, amount = line.split('\t') period = self. extract_year_month(timestamp) if period == self.current_year_month(): yield (period, category), amount - def reducer(self, key, value): + def reducer(self, key, values): """Sum values for each key. (2016-01, shopping), 125 diff --git a/solutions/system_design/mint/mint_snippets.py b/solutions/system_design/mint/mint_snippets.py index 3000d5fd40a..cc5d228b2a4 100644 --- a/solutions/system_design/mint/mint_snippets.py +++ b/solutions/system_design/mint/mint_snippets.py @@ -1,12 +1,16 @@ # -*- coding: utf-8 -*- +from enum import Enum + + class DefaultCategories(Enum): HOUSING = 0 FOOD = 1 GAS = 2 SHOPPING = 3 - ... + # ... + seller_category_map = {} seller_category_map['Exxon'] = DefaultCategories.GAS @@ -44,4 +48,3 @@ def __init__(self, template_categories_to_budget_map): def override_category_budget(self, category, amount): self.categories_to_budget_map[category] = amount - diff --git a/solutions/system_design/pastebin/README-zh-Hans.md b/solutions/system_design/pastebin/README-zh-Hans.md new file mode 100644 index 00000000000..b5fcbd3a0e6 --- /dev/null +++ b/solutions/system_design/pastebin/README-zh-Hans.md @@ -0,0 +1,330 @@ +# 设计 Pastebin.com (或者 Bit.ly) + +**Note: 为了避免重复,当前文档直接链接到[系统设计主题](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#系统设计主题的索引)的相关区域,请参考链接内容以获得综合的讨论点、权衡和替代方案。** + +**设计 Bit.ly** - 是一个类似的问题,区别是 pastebin 需要存储的是 paste 的内容,而不是原始的未短化的 url。 + +## 第一步:概述用例和约束 + +> 收集这个问题的需求和范畴。 +> 问相关问题来明确用例和约束。 +> 讨论一些假设。 + +因为没有面试官来明确这些问题,所以我们自己将定义一些用例和约束。 + +### 用例 + +#### 我们将问题的范畴限定在如下用例 + +* **用户** 输入一段文本,然后得到一个随机生成的链接 + * 过期设置 + * 默认的设置是不会过期的 + * 可以选择设置一个过期的时间 +* **用户** 输入一个 paste 的 url 后,可以看到它存储的内容 +* **用户** 是匿名的 +* **Service** 跟踪页面分析 + * 一个月的访问统计 +* **Service** 删除过期的 pastes +* **Service** 需要高可用 + +#### 超出范畴的用例 + +* **用户** 可以注册一个账户 + * **用户** 通过验证邮箱 +* **用户** 可以用注册的账户登录 + * **用户** 可以编辑文档 +* **用户** 可以设置可见性 +* **用户** 可以设置短链接 + +### 约束和假设 + +#### 状态假设 + +* 访问流量不是均匀分布的 +* 打开一个短链接应该是很快的 +* pastes 只能是文本 +* 页面访问分析数据可以不用实时 +* 一千万的用户量 +* 每个月一千万的 paste 写入量 +* 每个月一亿的 paste 读取量 +* 读写比例在 10:1 + +#### 计算使用 + +**向面试官说明你是否应该粗略计算一下使用情况。** + +* 每个 paste 的大小 + * 每一个 paste 1 KB + * `shortlink` - 7 bytes + * `expiration_length_in_minutes` - 4 bytes + * `created_at` - 5 bytes + * `paste_path` - 255 bytes + * 总共 = ~1.27 KB +* 每个月新的 paste 内容在 12.7GB + * (1.27 * 10000000)KB / 月的 paste + * 三年内将近 450GB 的新 paste 内容 + * 三年内 3.6 亿短链接 + * 假设大部分都是新的 paste,而不是需要更新已存在的 paste +* 平均 4paste/s 的写入速度 +* 平均 40paste/s 的读取速度 + +简单的转换指南: + +* 2.5 百万 req/s +* 1 req/s = 2.5 百万 req/m +* 40 req/s = 1 亿 req/m +* 400 req/s = 10 亿 req/m + +## 第二步:创建一个高层次设计 + +> 概述一个包括所有重要的组件的高层次设计 + +![Imgur](http://i.imgur.com/BKsBnmG.png) + +## 第三步:设计核心组件 + +> 深入每一个核心组件的细节 + +### 用例:用户输入一段文本,然后得到一个随机生成的链接 + +我们可以用一个 [关系型数据库](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#关系型数据库管理系统rdbms)作为一个大的哈希表,用来把生成的 url 映射到一个包含 paste 文件的文件服务器和路径上。 + +为了避免托管一个文件服务器,我们可以用一个托管的**对象存储**,比如 Amazon 的 S3 或者[NoSQL 文档类型存储](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#文档类型存储)。 + +作为一个大的哈希表的关系型数据库的替代方案,我们可以用[NoSQL 键值存储](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#键-值存储)。我们需要讨论[选择 SQL 或 NoSQL 之间的权衡](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#sql-还是-nosql)。下面的讨论是使用关系型数据库方法。 + +* **客户端** 发送一个创建 paste 的请求到作为一个[反向代理](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#反向代理web-服务器)启动的 **Web 服务器**。 +* **Web 服务器** 转发请求给 **写接口** 服务器 +* **写接口** 服务器执行如下操作: + * 生成一个唯一的 url + * 检查这个 url 在 **SQL 数据库** 里面是否是唯一的 + * 如果这个 url 不是唯一的,生成另外一个 url + * 如果我们支持自定义 url,我们可以使用用户提供的 url(也需要检查是否重复) + * 把生成的 url 存储到 **SQL 数据库** 的 `pastes` 表里面 + * 存储 paste 的内容数据到 **对象存储** 里面 + * 返回生成的 url + +**向面试官阐明你需要写多少代码** + +`pastes` 表可以有如下结构: + +```sql +shortlink char(7) NOT NULL +expiration_length_in_minutes int NOT NULL +created_at datetime NOT NULL +paste_path varchar(255) NOT NULL +PRIMARY KEY(shortlink) +``` + +我们将在 `shortlink` 字段和 `created_at` 字段上创建一个[数据库索引](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#使用正确的索引),用来提高查询的速度(避免因为扫描全表导致的长时间查询)并将数据保存在内存中,从内存里面顺序读取 1MB 的数据需要大概 250 微秒,而从 SSD 上读取则需要花费 4 倍的时间,从硬盘上则需要花费 80 倍的时间。 1 + +为了生成唯一的 url,我们可以: + +* 使用 [**MD5**](https://en.wikipedia.org/wiki/MD5) 来哈希用户的 IP 地址 + 时间戳 + * MD5 是一个普遍用来生成一个 128-bit 长度的哈希值的一种哈希方法 + * MD5 是一致分布的 + * 或者我们也可以用 MD5 哈希一个随机生成的数据 +* 用 [**Base 62**](https://www.kerstner.at/2012/07/shortening-strings-using-base-62-encoding/) 编码 MD5 哈希值 + * 对于 urls,使用 Base 62 编码 `[a-zA-Z0-9]` 是比较合适的 + * 对于每一个原始输入只会有一个 hash 结果,Base 62 是确定的(不涉及随机性) + * Base 64 是另外一个流行的编码方案,但是对于 urls,会因为额外的 `+` 和 `-` 字符串而产生一些问题 + * 以下 [Base 62 伪代码](http://stackoverflow.com/questions/742013/how-to-code-a-url-shortener) 执行的时间复杂度是 O(k),k 是数字的数量 = 7: + +```python +def base_encode(num, base=62): + digits = [] + while num > 0 + remainder = modulo(num, base) + digits.push(remainder) + num = divide(num, base) + digits = digits.reverse +``` + +* 取输出的前 7 个字符,结果会有 62^7 个可能的值,应该足以满足在 3 年内处理 3.6 亿个短链接的约束: + +```python +url = base_encode(md5(ip_address+timestamp))[:URL_LENGTH] +``` + +我们将会用一个公开的 [**REST 风格接口**](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#表述性状态转移rest): + +```shell +$ curl -X POST --data '{"expiration_length_in_minutes":"60", \"paste_contents":"Hello World!"}' https://pastebin.com/api/v1/paste +``` + +Response: + +```json +{ + "shortlink": "foobar" +} +``` + +用于内部通信,我们可以用 [RPC](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#远程过程调用协议rpc)。 + +### 用例:用户输入一个 paste 的 url 后可以看到它存储的内容 + +* **客户端** 发送一个获取 paste 请求到 **Web Server** +* **Web Server** 转发请求给 **读取接口** 服务器 +* **读取接口** 服务器执行如下操作: + * 在 **SQL 数据库** 检查这个生成的 url + * 如果这个 url 在 **SQL 数据库** 里面,则从 **对象存储** 获取这个 paste 的内容 + * 否则,返回一个错误页面给用户 + +REST API: + +```shell +curl https://pastebin.com/api/v1/paste?shortlink=foobar +``` + +Response: + +```json +{ + "paste_contents": "Hello World", + "created_at": "YYYY-MM-DD HH:MM:SS", + "expiration_length_in_minutes": "60" +} +``` + +### 用例: 服务跟踪分析页面 + +因为实时分析不是必须的,所以我们可以简单的 **MapReduce** **Web Server** 的日志,用来生成点击次数。 + +```python +class HitCounts(MRJob): + + def extract_url(self, line): + """Extract the generated url from the log line.""" + ... + + def extract_year_month(self, line): + """Return the year and month portions of the timestamp.""" + ... + + def mapper(self, _, line): + """Parse each log line, extract and transform relevant lines. + + Emit key value pairs of the form: + + (2016-01, url0), 1 + (2016-01, url0), 1 + (2016-01, url1), 1 + """ + url = self.extract_url(line) + period = self.extract_year_month(line) + yield (period, url), 1 + + def reducer(self, key, values): + """Sum values for each key. + + (2016-01, url0), 2 + (2016-01, url1), 1 + """ + yield key, sum(values) +``` + +### 用例: 服务删除过期的 pastes + +为了删除过期的 pastes,我们可以直接搜索 **SQL 数据库** 中所有的过期时间比当前时间更早的记录, +所有过期的记录将从这张表里面删除(或者将其标记为过期)。 + +## 第四步:扩展这个设计 + +> 给定约束条件,识别和解决瓶颈。 + +![Imgur](http://i.imgur.com/4edXG0T.png) + +**重要提示: 不要简单的从最初的设计直接跳到最终的设计** + +说明您将迭代地执行这样的操作:1)**Benchmark/Load 测试**,2)**Profile** 出瓶颈,3)在评估替代方案和权衡时解决瓶颈,4)重复前面,可以参考[在 AWS 上设计一个可以支持百万用户的系统](../scaling_aws/README.md)这个用来解决如何迭代地扩展初始设计的例子。 + +重要的是讨论在初始设计中可能遇到的瓶颈,以及如何解决每个瓶颈。比如,在多个 **Web 服务器** 上添加 **负载平衡器** 可以解决哪些问题? **CDN** 解决哪些问题?**Master-Slave Replicas** 解决哪些问题? 替代方案是什么和怎么对每一个替代方案进行权衡比较? + +我们将介绍一些组件来完成设计,并解决可伸缩性问题。内部的负载平衡器并不能减少杂乱。 + +**为了避免重复的讨论**, 参考以下[系统设计主题](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#系统设计主题的索引)获取主要讨论要点、权衡和替代方案: + +* [DNS](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#域名系统) +* [CDN](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#内容分发网络cdn) +* [负载均衡器](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#负载均衡器) +* [水平扩展](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#水平扩展) +* [反向代理(web 服务器)](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#反向代理web-服务器) +* [应用层](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#应用层) +* [缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#缓存) +* [关系型数据库管理系统 (RDBMS)](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#关系型数据库管理系统rdbms) +* [SQL write master-slave failover](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#故障切换) +* [主从复制](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#主从复制) +* [一致性模式](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#一致性模式) +* [可用性模式](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#可用性模式) + +**分析存储数据库** 可以用比如 Amazon Redshift 或者 Google BigQuery 这样的数据仓库解决方案。 + +一个像 Amazon S3 这样的 **对象存储**,可以轻松处理每月 12.7 GB 的新内容约束。 + +要处理 *平均* 每秒 40 读请求(峰值更高),其中热点内容的流量应该由 **内存缓存** 处理,而不是数据库。**内存缓存** 对于处理分布不均匀的流量和流量峰值也很有用。只要副本没有陷入复制写的泥潭,**SQL Read Replicas** 应该能够处理缓存丢失。 + +对于单个 **SQL Write Master-Slave**,*平均* 每秒 4paste 写入 (峰值更高) 应该是可以做到的。否则,我们需要使用额外的 SQL 扩展模式: + +* [联合](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#联合) +* [分片](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#分片) +* [非规范化](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#非规范化) +* [SQL 调优](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#SQL调优) + +我们还应该考虑将一些数据移动到 **NoSQL 数据库**。 + +## 额外的话题 + +> 是否更深入探讨额外主题,取决于问题的范围和面试剩余的时间。 + +### NoSQL + +* [键值存储](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#键-值存储) +* [文档存储](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#文档类型存储) +* [列型存储](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#列型存储) +* [图数据库](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#图数据库) +* [sql 还是 nosql](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#sql-还是-nosql) + +### 缓存 + +* 在哪缓存 + * [客户端缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#客户端缓存) + * [CDN 缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#cdn-缓存) + * [Web 服务器缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#web-服务器缓存) + * [数据库缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#数据库缓存) + * [应用缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#应用缓存) +* 缓存什么 + * [数据库查询级别的缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#数据库查询级别的缓存) + * [对象级别的缓存](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#对象级别的缓存) +* 何时更新缓存 + * [缓存模式](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#缓存模式) + * [直写模式](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#直写模式) + * [回写模式](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#回写模式) + * [刷新](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#刷新) + +### 异步和微服务 + +* [消息队列](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#消息队列) +* [任务队列](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#任务队列) +* [背压](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#背压) +* [微服务](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#微服务) + +### 通信 + +* 讨论权衡: + * 跟客户端之间的外部通信 - [HTTP APIs following REST](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#表述性状态转移rest) + * 内部通信 - [RPC](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#远程过程调用协议rpc) +* [服务发现](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#服务发现) + +### 安全 + +参考[安全](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#安全)。 + +### 延迟数字 + +见[每个程序员都应该知道的延迟数](https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md#每个程序员都应该知道的延迟数)。 + +### 持续进行 + +* 继续对系统进行基准测试和监控,以在瓶颈出现时解决它们 +* 扩展是一个迭代的过程 diff --git a/solutions/system_design/pastebin/README.md b/solutions/system_design/pastebin/README.md index 19a3587ee1f..756c78c274c 100644 --- a/solutions/system_design/pastebin/README.md +++ b/solutions/system_design/pastebin/README.md @@ -126,11 +126,11 @@ To generate the unique url, we could: * Alternatively, we could also take the MD5 hash of randomly-generated data * [**Base 62**](https://www.kerstner.at/2012/07/shortening-strings-using-base-62-encoding/) encode the MD5 hash * Base 62 encodes to `[a-zA-Z0-9]` which works well for urls, eliminating the need for escaping special characters - * There is only one hash result for the original input and and Base 62 is deterministic (no randomness involved) + * There is only one hash result for the original input and Base 62 is deterministic (no randomness involved) * Base 64 is another popular encoding but provides issues for urls because of the additional `+` and `/` characters * The following [Base 62 pseudocode](http://stackoverflow.com/questions/742013/how-to-code-a-url-shortener) runs in O(k) time where k is the number of digits = 7: -``` +```python def base_encode(num, base=62): digits = [] while num > 0 @@ -142,7 +142,7 @@ def base_encode(num, base=62): * Take the first 7 characters of the output, which results in 62^7 possible values and should be sufficient to handle our constraint of 360 million shortlinks in 3 years: -``` +```python url = base_encode(md5(ip_address+timestamp))[:URL_LENGTH] ``` @@ -194,7 +194,7 @@ Since realtime analytics are not a requirement, we could simply **MapReduce** th **Clarify with your interviewer how much code you are expected to write**. -``` +```python class HitCounts(MRJob): def extract_url(self, line): @@ -218,7 +218,7 @@ class HitCounts(MRJob): period = self.extract_year_month(line) yield (period, url), 1 - def reducer(self, key, value): + def reducer(self, key, values): """Sum values for each key. (2016-01, url0), 2 diff --git a/solutions/system_design/pastebin/pastebin.py b/solutions/system_design/pastebin/pastebin.py index 7cb1f2049aa..7e8d268a0ea 100644 --- a/solutions/system_design/pastebin/pastebin.py +++ b/solutions/system_design/pastebin/pastebin.py @@ -26,7 +26,7 @@ def mapper(self, _, line): period = self.extract_year_month(line) yield (period, url), 1 - def reducer(self, key, value): + def reducer(self, key, values): """Sum values for each key. (2016-01, url0), 2 diff --git a/solutions/system_design/query_cache/README.md b/solutions/system_design/query_cache/README.md index 7e815abe69b..032adf34abd 100644 --- a/solutions/system_design/query_cache/README.md +++ b/solutions/system_design/query_cache/README.md @@ -97,7 +97,7 @@ The cache can use a doubly-linked list: new items will be added to the head whil **Query API Server** implementation: -``` +```python class QueryApi(object): def __init__(self, memory_cache, reverse_index_service): @@ -121,7 +121,7 @@ class QueryApi(object): **Node** implementation: -``` +```python class Node(object): def __init__(self, query, results): @@ -131,7 +131,7 @@ class Node(object): **LinkedList** implementation: -``` +```python class LinkedList(object): def __init__(self): @@ -150,7 +150,7 @@ class LinkedList(object): **Cache** implementation: -``` +```python class Cache(object): def __init__(self, MAX_SIZE): @@ -247,7 +247,7 @@ To handle the heavy request load and the large amount of memory needed, we'll sc ### SQL scaling patterns -* [Read replicas](https://github.com/donnemartin/system-design-primer#master-slave) +* [Read replicas](https://github.com/donnemartin/system-design-primer#master-slave-replication) * [Federation](https://github.com/donnemartin/system-design-primer#federation) * [Sharding](https://github.com/donnemartin/system-design-primer#sharding) * [Denormalization](https://github.com/donnemartin/system-design-primer#denormalization) diff --git a/solutions/system_design/query_cache/query_cache_snippets.py b/solutions/system_design/query_cache/query_cache_snippets.py index 469dc7c640b..19d3f5cdd63 100644 --- a/solutions/system_design/query_cache/query_cache_snippets.py +++ b/solutions/system_design/query_cache/query_cache_snippets.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- + class QueryApi(object): def __init__(self, memory_cache, reverse_index_cluster): @@ -52,7 +53,7 @@ def __init__(self, MAX_SIZE): self.lookup = {} self.linked_list = LinkedList() - def get(self, query) + def get(self, query): """Get the stored query result from the cache. Accessing a node updates its position to the front of the LRU list. diff --git a/solutions/system_design/sales_rank/README.md b/solutions/system_design/sales_rank/README.md index 3ee50985775..71ad1c7d202 100644 --- a/solutions/system_design/sales_rank/README.md +++ b/solutions/system_design/sales_rank/README.md @@ -102,7 +102,7 @@ We'll use a multi-step **MapReduce**: * **Step 1** - Transform the data to `(category, product_id), sum(quantity)` * **Step 2** - Perform a distributed sort -``` +```python class SalesRanker(MRJob): def within_past_week(self, timestamp): diff --git a/solutions/system_design/sales_rank/sales_rank_mapreduce.py b/solutions/system_design/sales_rank/sales_rank_mapreduce.py index bbe844b4306..6eeeb525035 100644 --- a/solutions/system_design/sales_rank/sales_rank_mapreduce.py +++ b/solutions/system_design/sales_rank/sales_rank_mapreduce.py @@ -9,7 +9,7 @@ def within_past_week(self, timestamp): """Return True if timestamp is within past week, False otherwise.""" ... - def mapper(self, _ line): + def mapper(self, _, line): """Parse each log line, extract and transform relevant lines. Emit key value pairs of the form: @@ -25,7 +25,7 @@ def mapper(self, _ line): if self.within_past_week(timestamp): yield (category, product_id), quantity - def reducer(self, key, value): + def reducer(self, key, values): """Sum values for each key. (foo, p1), 2 @@ -74,4 +74,4 @@ def steps(self): if __name__ == '__main__': - HitCounts.run() + SalesRanker.run() diff --git a/solutions/system_design/scaling_aws/README.md b/solutions/system_design/scaling_aws/README.md index 9134983e94a..99af0cfff8d 100644 --- a/solutions/system_design/scaling_aws/README.md +++ b/solutions/system_design/scaling_aws/README.md @@ -83,7 +83,7 @@ Handy conversion guide: * **Web server** on EC2 * Storage for user data - * [**MySQL Database**](https://github.com/donnemartin/system-design-primer#sql) + * [**MySQL Database**](https://github.com/donnemartin/system-design-primer#relational-database-management-system-rdbms) Use **Vertical Scaling**: @@ -309,7 +309,7 @@ As the service continues to grow towards the figures outlined in the constraints We'll continue to address scaling issues due to the problem's constraints: -* If our **MySQL Database** starts to grow too large, we might considering only storing a limited time period of data in the database, while storing the rest in a data warehouse such as Redshift +* If our **MySQL Database** starts to grow too large, we might consider only storing a limited time period of data in the database, while storing the rest in a data warehouse such as Redshift * A data warehouse such as Redshift can comfortably handle the constraint of 1 TB of new content per month * With 40,000 average read requests per second, read traffic for popular content can be addressed by scaling the **Memory Cache**, which is also useful for handling the unevenly distributed traffic and traffic spikes * The **SQL Read Replicas** might have trouble handling the cache misses, we'll probably need to employ additional SQL scaling patterns @@ -344,7 +344,7 @@ We can further separate out our [**Application Servers**](https://github.com/don ### SQL scaling patterns -* [Read replicas](https://github.com/donnemartin/system-design-primer#master-slave) +* [Read replicas](https://github.com/donnemartin/system-design-primer#master-slave-replication) * [Federation](https://github.com/donnemartin/system-design-primer#federation) * [Sharding](https://github.com/donnemartin/system-design-primer#sharding) * [Denormalization](https://github.com/donnemartin/system-design-primer#denormalization) diff --git a/solutions/system_design/social_graph/README.md b/solutions/system_design/social_graph/README.md index b6607a041c8..f7dfd4efe8d 100644 --- a/solutions/system_design/social_graph/README.md +++ b/solutions/system_design/social_graph/README.md @@ -62,7 +62,7 @@ Handy conversion guide: Without the constraint of millions of users (vertices) and billions of friend relationships (edges), we could solve this unweighted shortest path task with a general BFS approach: -``` +```python class Graph(Graph): def shortest_path(self, source, dest): @@ -117,7 +117,7 @@ We won't be able to fit all users on the same machine, we'll need to [shard](htt **Lookup Service** implementation: -``` +```python class LookupService(object): def __init__(self): @@ -132,7 +132,7 @@ class LookupService(object): **Person Server** implementation: -``` +```python class PersonServer(object): def __init__(self): @@ -151,7 +151,7 @@ class PersonServer(object): **Person** implementation: -``` +```python class Person(object): def __init__(self, id, name, friend_ids): @@ -162,7 +162,7 @@ class Person(object): **User Graph Service** implementation: -``` +```python class UserGraphService(object): def __init__(self, lookup_service): @@ -290,7 +290,7 @@ Below are further optimizations: ### SQL scaling patterns -* [Read replicas](https://github.com/donnemartin/system-design-primer#master-slave) +* [Read replicas](https://github.com/donnemartin/system-design-primer#master-slave-replication) * [Federation](https://github.com/donnemartin/system-design-primer#federation) * [Sharding](https://github.com/donnemartin/system-design-primer#sharding) * [Denormalization](https://github.com/donnemartin/system-design-primer#denormalization) diff --git a/solutions/system_design/social_graph/social_graph_snippets.py b/solutions/system_design/social_graph/social_graph_snippets.py index 32941111c20..f0ea4c4b932 100644 --- a/solutions/system_design/social_graph/social_graph_snippets.py +++ b/solutions/system_design/social_graph/social_graph_snippets.py @@ -1,4 +1,12 @@ # -*- coding: utf-8 -*- +from collections import deque +from enum import Enum + + +class State(Enum): + unvisited = 0 + visited = 1 + class Graph(object): @@ -61,3 +69,4 @@ def __init__(self, person_ids, lookup): def bfs(self, source, dest): # Use self.visited_ids to track visited nodes # Use self.lookup to translate a person_id to a Person + pass diff --git a/solutions/system_design/twitter/README.md b/solutions/system_design/twitter/README.md index 415e6467d31..374f5dd2197 100644 --- a/solutions/system_design/twitter/README.md +++ b/solutions/system_design/twitter/README.md @@ -76,7 +76,7 @@ Search * 100 thousand read requests per second * 250 billion read requests per month * (400 requests per second / 1 billion requests per month) * 6,000 tweets per second - * 15 billion tweets delivered on fanout per month * (400 requests per second / 1 billion requests per month) + * 15 billion tweets per month * (400 requests per second / 1 billion requests per month) * 60 thousand tweets delivered on fanout per second * 150 billion tweets delivered on fanout per month * (400 requests per second / 1 billion requests per month) * 4,000 search requests per second @@ -124,7 +124,7 @@ If our **Memory Cache** is Redis, we could use a native Redis list with the foll ``` tweet n+2 tweet n+1 tweet n -| 8 bytes 8 bytes 1 byte | 8 bytes 8 bytes 1 byte | 8 bytes 7 bytes 1 byte | +| 8 bytes 8 bytes 1 byte | 8 bytes 8 bytes 1 byte | 8 bytes 8 bytes 1 byte | | tweet_id user_id meta | tweet_id user_id meta | tweet_id user_id meta | ``` @@ -189,7 +189,7 @@ Response: ### Use case: User views the user timeline -* The **Client** posts a home timeline request to the **Web Server** +* The **Client** posts a user timeline request to the **Web Server** * The **Web Server** forwards the request to the **Read API** server * The **Read API** retrieves the user timeline from the **SQL Database** @@ -249,7 +249,7 @@ We'll introduce some components to complete the design and to address scalabilit The **Fanout Service** is a potential bottleneck. Twitter users with millions of followers could take several minutes to have their tweets go through the fanout process. This could lead to race conditions with @replies to the tweet, which we could mitigate by re-ordering the tweets at serve time. -We could also avoid fanning out tweets from highly-followed users. Instead, we could search to find tweets for high-followed users, merge the search results with the user's home timeline results, then re-order the tweets at serve time. +We could also avoid fanning out tweets from highly-followed users. Instead, we could search to find tweets for highly-followed users, merge the search results with the user's home timeline results, then re-order the tweets at serve time. Additional optimizations include: diff --git a/solutions/system_design/web_crawler/README.md b/solutions/system_design/web_crawler/README.md index 358cb913226..d95dc1071c6 100644 --- a/solutions/system_design/web_crawler/README.md +++ b/solutions/system_design/web_crawler/README.md @@ -100,7 +100,7 @@ We could store `links_to_crawl` and `crawled_links` in a key-value **NoSQL Datab `PagesDataStore` is an abstraction within the **Crawler Service** that uses the **NoSQL Database**: -``` +```python class PagesDataStore(object): def __init__(self, db); @@ -134,7 +134,7 @@ class PagesDataStore(object): `Page` is an abstraction within the **Crawler Service** that encapsulates a page, its contents, child urls, and signature: -``` +```python class Page(object): def __init__(self, url, contents, child_urls, signature): @@ -146,7 +146,7 @@ class Page(object): `Crawler` is the main class within **Crawler Service**, composed of `Page` and `PagesDataStore`. -``` +```python class Crawler(object): def __init__(self, data_store, reverse_index_queue, doc_index_queue): @@ -187,7 +187,7 @@ We'll want to remove duplicate urls: * For smaller lists we could use something like `sort | unique` * With 1 billion links to crawl, we could use **MapReduce** to output only entries that have a frequency of 1 -``` +```python class RemoveDuplicateUrls(MRJob): def mapper(self, _, line): @@ -294,7 +294,7 @@ Below are a few other optimizations to the **Crawling Service**: ### SQL scaling patterns -* [Read replicas](https://github.com/donnemartin/system-design-primer#master-slave) +* [Read replicas](https://github.com/donnemartin/system-design-primer#master-slave-replication) * [Federation](https://github.com/donnemartin/system-design-primer#federation) * [Sharding](https://github.com/donnemartin/system-design-primer#sharding) * [Denormalization](https://github.com/donnemartin/system-design-primer#denormalization) diff --git a/solutions/system_design/web_crawler/web_crawler_snippets.py b/solutions/system_design/web_crawler/web_crawler_snippets.py index e85e23610cb..d84a25362ec 100644 --- a/solutions/system_design/web_crawler/web_crawler_snippets.py +++ b/solutions/system_design/web_crawler/web_crawler_snippets.py @@ -1,34 +1,35 @@ # -*- coding: utf-8 -*- + class PagesDataStore(object): - def __init__(self, db); + def __init__(self, db): self.db = db - ... + pass def add_link_to_crawl(self, url): """Add the given link to `links_to_crawl`.""" - ... + pass def remove_link_to_crawl(self, url): """Remove the given link from `links_to_crawl`.""" - ... + pass - def reduce_priority_link_to_crawl(self, url) + def reduce_priority_link_to_crawl(self, url): """Reduce the priority of a link in `links_to_crawl` to avoid cycles.""" - ... + pass def extract_max_priority_page(self): """Return the highest priority link in `links_to_crawl`.""" - ... + pass def insert_crawled_link(self, url, signature): """Add the given link to `crawled_links`.""" - ... + pass def crawled_similar(self, signature): """Determine if we've already crawled a page matching the given signature""" - ... + pass class Page(object): @@ -41,7 +42,7 @@ def __init__(self, url, contents, child_urls): def create_signature(self): # Create signature based on url and contents - ... + pass class Crawler(object):