Web Analytics

system-design-primer

⭐ 318813 stars Traditional Chinese by donnemartin

English日本語简体中文繁體中文 | العَرَبِيَّة‎বাংলাPortuguês do BrasilDeutschελληνικάעבריתItaliano한국어فارسیPolskiрусский языкEspañolภาษาไทยTürkçetiếng ViệtFrançais | Add Translation

協助翻譯本指南!

系統設計入門指南


動機

學習如何設計大型系統。
>
為系統設計面試做準備。

學習如何設計大型系統

學習如何設計可擴展的系統將幫助你成為更優秀的工程師。

系統設計是一個範圍廣泛的主題。網路上有大量分散的資源關於系統設計原則。

本倉庫是一個有組織的資源集合,協助你學習如何構建可擴展的系統。

向開源社群學習

這是一個持續更新的開源專案。

歡迎貢獻

為系統設計面試做準備

除了程式面試外,系統設計也是許多科技公司技術面試流程的必備項目

練習常見的系統設計面試題目,並將你的結果與範例解答(討論、程式碼、與圖示)進行比較

面試準備的其他主題:

Anki 閃卡


提供的 Anki 閃卡套件 使用間隔重複法幫助你記憶重要的系統設計概念。

非常適合在移動中使用。

程式資源:互動式程式挑戰

正在尋找幫助你準備 程式面試 的資源嗎?


請參考相關的倉庫 互動式程式挑戰,其中包含額外的 Anki 閃卡套件:

貢獻

向社群學習。

歡迎提交 pull requests 來協助:

需要進一步潤飾的內容被放置於開發中

請參閱貢獻指南

系統設計主題索引

各種系統設計主題的摘要,包括優缺點。一切都是權衡
>
每個章節都包含更深入資源的連結。


學習指南

根據您的面試時間表(短期、中期、長期)建議回顧的主題。

Imgur

問:面試時需要全部都懂嗎?

答:不需要全部都懂才能準備面試

在面試中會被問到什麼,取決於以下變數:

經驗較豐富的候選人通常預期要懂更多系統設計。架構師或團隊領導者通常要比一般成員懂得更多。頂尖科技公司很可能會有一輪或多輪設計面試。

先從廣泛的主題入手,再深入幾個領域。瞭解各種關鍵系統設計主題的基本知識是有幫助的。請根據你的時間安排、經驗、面試職位及面試公司調整以下指南。

| | 短期 | 中期 | 長期 | |---|---|---|---| | 閱讀系統設計主題索引以廣泛瞭解系統運作方式 | :+1: | :+1: | :+1: | | 閱讀你要面試公司的公司工程部落格中的一些文章 | :+1: | :+1: | :+1: | | 閱讀一些真實世界架構 | :+1: | :+1: | :+1: | | 回顧如何應對系統設計面試問題 | :+1: | :+1: | :+1: | | 練習系統設計面試題及解答 | 部分 | 多數 | 大多數 | | 練習物件導向設計面試題及解答 | 部分 | 多數 | 大多數 | | 回顧其他系統設計面試問題 | 部分 | 多數 | 大多數 |

如何應對系統設計面試問題

如何解決系統設計面試問題。

系統設計面試是一場開放式對話。你需要主導整個討論。

你可以利用以下步驟引導討論。為了鞏固這個流程,請參照以下步驟練習系統設計面試題及解答部分。

步驟 1:列出用例、限制條件與假設

收集需求並界定問題範圍。提出問題以釐清用例和限制條件。討論假設。

步驟 2:建立高層設計

概述包含所有重要組件的高層設計。

步驟三:設計核心元件

針對每個核心元件進行詳細設計。例如,如果題目要求你設計一個網址縮短服務,可以討論:

步驟四:設計可擴展性

在已知限制下,找出並解決瓶頸。例如,為了解決可擴展性問題,你是否需要以下項目?

討論潛在解決方案與權衡。任何設計都是一種取捨。請運用可擴展系統設計原則來解決瓶頸問題。

粗略計算(Back-of-the-envelope calculations)

你可能會被要求手動進行一些估算。請參考附錄中的以下資源:

來源與進一步閱讀

請參考以下連結,獲取更多相關資訊:

系統設計面試題目與解答

常見系統設計面試題目,附有討論範例、程式碼及圖解。
>
解答連結至 solutions/ 資料夾內容。

| 題目 | | |---|---| | 設計 Pastebin.com(或 Bit.ly) | 解答 | | 設計 Twitter 時間軸與搜尋(或 Facebook 動態消息與搜尋) | 解答 | | 設計一個網頁爬蟲 | 解答 | | 設計 Mint.com | 解答 | | 設計社群網路的資料結構 | 解答 | | 為搜尋引擎設計鍵值儲存系統 | 解答 | | 設計亞馬遜依類別銷售排名功能 | 解答 | | 設計在 AWS 上可擴展至百萬用戶的系統 | 解答 | | 新增系統設計題目 | 貢獻 |

設計 Pastebin.com(或 Bit.ly)

查看練習與解答

Imgur

設計 Twitter 時間軸與搜尋(或 Facebook 動態消息與搜尋)

查看練習與解答

Imgur

設計一個網頁爬蟲

查看練習與解答

Imgur

Design Mint.com

View exercise and solution

Imgur

Design the data structures for a social network

View exercise and solution

Imgur

Design a key-value store for a search engine

View exercise and solution

Imgur

Design Amazon's sales ranking by category feature

View exercise and solution

Imgur

Design a system that scales to millions of users on AWS

View exercise and solution

Imgur

Object-oriented design interview questions with solutions

Common object-oriented design interview questions with sample discussions, code, and diagrams.
>
Solutions linked to content in the solutions/ folder.

>Note: This section is under development

| Question | | |---|---| | 設計一個雜湊映射表 | 解答 | | 設計一個最近最少使用快取(LRU Cache) | 解答 | | 設計一個呼叫中心 | 解答 | | 設計一副撲克牌 | 解答 | | 設計一個停車場 | 解答 | | 設計一個即時聊天伺服器 | 解答 | | 設計一個環狀陣列 | 貢獻 | | 新增一題物件導向設計問題 | 貢獻 |

系統設計主題:從這裡開始

系統設計新手?

首先,你需要對常見原則有基本認識,了解它們是什麼、如何使用,以及它們的優缺點。

步驟 1:觀看可擴展性(Scalability)教學影片

哈佛可擴展性講座

步驟 2:閱讀可擴展性文章

可擴展性

下一步

接下來,我們將探討高層級的權衡:

請記住,一切都是權衡

然後我們會深入探討更具體的主題,例如 DNS、CDN 與負載平衡器。

效能 vs 可擴展性

當服務能隨著資源的增加而呈現相應的效能提升時,即稱為可擴展。一般而言,提升效能意味著能處理更多的工作單位,但也可以是處理更大型的工作單位,例如當資料集規模增加時。1

效能與可擴展性還有另一種理解方式:

來源與進一步閱讀

延遲 vs 吞吐量

延遲是執行某個動作或產生某個結果所需的時間。

吞吐量是每單位時間內執行此類動作或產生結果的數量。

一般來說,應以最大化吞吐量並維持可接受的延遲為目標。

來源與進一步閱讀

可用性 vs 一致性

CAP 定理


來源:CAP 定理再探討

在分散式電腦系統中,你只能支援以下三項保證中的兩項:

網路並不可靠,因此你必須支援分區容忍度。你需要在一致性和可用性之間做出軟體取捨。

#### CP - 一致性與分區容忍度

等待被分區節點的回應可能會導致逾時錯誤。如果你的業務需求需要原子性讀寫,CP 是不錯的選擇。

#### AP - 可用性與分區容忍度

回應會返回任何節點上最容易取得的資料版本,這可能不是最新的。當分區恢復時,寫入可能需要一段時間才能傳播。

如果業務需求允許最終一致性,或當系統需要在外部錯誤下繼續運作時,AP 是不錯的選擇。

來源與延伸閱讀

一致性模式

當存在多份相同資料時,我們需要選擇如何同步這些資料,以便客戶端能獲得一致的資料視圖。請回顧 CAP 定理 的一致性定義──每次讀取都會收到最新的寫入或錯誤。

弱一致性

寫入後,讀取有可能看到或看不到該寫入。這是一種盡力而為的做法。

這種方式出現在如 memcached 等系統中。弱一致性非常適用於即時應用場景,如 VoIP、視訊聊天和即時多人遊戲。例如,當你在通話時短暫失去訊號,恢復連線後你不會聽到斷線期間說的內容。

最終一致性

在寫入後,讀取最終會看到該寫入(通常在毫秒內)。資料是非同步複製的。

此方法常見於 DNS 和電子郵件等系統。最終一致性非常適合高可用性系統。

強一致性

在寫入後,讀取會立即看到該寫入。資料是同步複製的。

此方法常見於檔案系統及關聯式資料庫管理系統(RDBMS)。強一致性非常適合需要交易的系統。

資料來源及延伸閱讀

可用性模式

有兩種互補模式支援高可用性:故障切換複製

故障切換

#### 主動-被動

在主動-被動故障切換中,主動伺服器與待命的被動伺服器之間會定期傳送心跳訊號。若心跳中斷,被動伺服器會接管主動伺服器的 IP 位址並恢復服務。

停機時間長度取決於被動伺服器是否已經在「熱」待命狀態,或是需要從「冷」待命狀態啟動。只有主動伺服器會處理流量。

主動-被動故障切換也可以稱為主從故障切換。

#### 主動-主動

在主動-主動模式下,兩台伺服器皆處理流量,分散負載於兩者之間。

若伺服器對外公開,DNS 需知曉兩台伺服器的公開 IP。若伺服器僅供內部使用,應用程式邏輯需知曉兩台伺服器。

主動-主動故障切換也可以稱為主主故障切換。

缺點:故障切換

複製

#### 主從與主主

此主題在資料庫章節中進一步討論:

以數字表示的可用性

可用性通常以運作時間(或停機時間)佔服務可用時間的百分比來量化。可用性通常以9的數量來衡量——一個具有99.99%可用性的服務被描述為有四個9。

#### 99.9% 可用性 - 三個9

| 期間 | 可接受的停機時間 | |---------------------|--------------------| | 每年停機時間 | 8小時45分57秒 | | 每月停機時間 | 43分49.7秒 | | 每週停機時間 | 10分4.8秒 | | 每日停機時間 | 1分26.4秒 |

#### 99.99% 可用性 - 四個9

| 期間 | 可接受的停機時間 | |---------------------|--------------------| | 每年停機時間 | 52分35.7秒 | | 每月停機時間 | 4分23秒 | | 每週停機時間 | 1分5秒 | | 每日停機時間 | 8.6秒 |

#### 並聯與串聯下的可用性

如果一項服務由多個容易故障的元件組成,該服務的整體可用性取決於這些元件是串聯還是並聯。

###### 串聯

當兩個可用性低於 100% 的元件串聯時,整體可用性會下降:

Availability (Total) = Availability (Foo) * Availability (Bar)

如果 FooBar 各自具有 99.9% 的可用性,它們串聯後的總可用性將是 99.8%。

###### 並聯

當兩個可用性低於 100% 的元件並聯時,整體可用性會提升:

Availability (Total) = 1 - (1 - Availability (Foo)) * (1 - Availability (Bar))
如果 FooBar 各自擁有 99.9% 的可用性,則它們並聯的總可用性將達到 99.9999%。

網域名稱系統


來源:DNS 安全簡報

網域名稱系統(DNS)會將像 www.example.com 這樣的網域名稱轉換為 IP 位址。

DNS 是分層的,頂層只有少數權威伺服器。你的路由器或 ISP 會提供查詢時應聯絡哪些 DNS 伺服器的資訊。較低層的 DNS 伺服器會快取映射,這些快取可能因 DNS 傳播延遲而過時。DNS 結果也可能被你的瀏覽器或作業系統快取一段時間,這段時間由 存活時間(TTL) 決定。

CloudFlareRoute 53 這樣的服務提供受管理的 DNS 服務。一些 DNS 服務可以透過多種方法導流:

缺點:DNS

來源與延伸閱讀

內容傳遞網路


來源:為什麼要使用 CDN

內容傳遞網路(CDN)是一個全球分佈的代理伺服器網路,能從更接近使用者的位置提供內容。通常,靜態檔案如 HTML/CSS/JS、照片和影片會由 CDN 傳送,但有些 CDN(如 Amazon 的 CloudFront)也支援動態內容。網站的 DNS 解析會告訴客戶端要聯絡哪一台伺服器。

使用 CDN 傳送內容可以透過以下兩種方式顯著提升效能:

Push CDN

Push CDN 在您的伺服器有新內容變更時即接收內容。您需全權負責提供內容,直接上傳至 CDN 並將網址重新指向 CDN。您可以設定內容何時過期及何時更新。只有新或變更的內容才會被上傳,能最小化流量但最大化儲存空間。

流量較小或內容不常更新的網站很適合使用 Push CDN。內容只需上傳至 CDN 一次,而非定期重新拉取。

Pull CDN

Pull CDN 在第一個使用者請求內容時,才從您的伺服器抓取新內容。您將內容保留在自己的伺服器上,並將網址重新指向 CDN。首次請求時速度較慢,直到內容被快取至 CDN。

一個存活時間(TTL)決定內容快取的時長。Pull CDN 可最小化 CDN 的儲存空間,但若檔案過期且在尚未變更前被重新拉取,可能產生重複流量。

高流量網站適合使用 Pull CDN,因為流量分配更平均,只有最近被請求的內容會留在 CDN 上。

缺點:CDN

來源與延伸閱讀

負載平衡器


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

負載平衡器將進來的客戶端請求分配到運算資源,如應用伺服器和資料庫。每一次,負載平衡器會將運算資源的回應返回給相應的客戶端。負載平衡器的有效作用包括:

負載平衡器可以透過硬體(昂貴)或像 HAProxy 這樣的軟體來實作。

其他優點包括:

為了防止故障,常見做法是設置多個負載平衡器,可以採用主動-被動主動-主動模式。

負載平衡器可根據各種指標導引流量,包括:

第 4 層負載平衡

第 4 層負載平衡器會根據傳輸層的資訊來決定如何分配請求。一般涉及標頭中的來源、目的地 IP 位址及埠號,但不涉及封包內容。第 4 層負載平衡器會將網路封包轉發到上游伺服器並回傳,同時執行網路位址轉換(NAT)

第 7 層負載平衡

第七層負載平衡器會檢查應用層以決定如何分配請求。這可能涉及標頭、訊息和 cookies 的內容。第七層負載平衡器會終止網路流量,讀取訊息,做出負載平衡決策,然後開啟到選定伺服器的連線。例如,第七層負載平衡器可以將影片流量導向主機影片的伺服器,同時將較敏感的使用者帳單流量導向強化安全的伺服器。

以彈性為代價,第四層負載平衡比第七層負載平衡所需的時間和運算資源更少,儘管在現代商用硬體上效能影響可能非常小。

水平擴展

負載平衡器也可以協助水平擴展,提升效能和可用性。利用商用機器進行橫向擴展比在昂貴硬體上擴充單一伺服器(稱為垂直擴展)更具成本效益,也能帶來更高的可用性。相較於專業企業系統,尋找熟悉商用硬體的人才也更容易。

#### 缺點:水平擴展

缺點:負載平衡器

來源及延伸閱讀

反向代理(網頁伺服器)


來源:維基百科

反向代理是一種網頁伺服器,可以集中內部服務並向公眾提供統一介面。客戶端的請求會被轉發到可以滿足該請求的伺服器,然後反向代理再將伺服器的回應返回給客戶端。

額外的好處包括:

負載平衡器 vs 反向代理

缺點:反向代理

來源及進一步閱讀

應用層


來源:系統擴展架構入門

將 Web 層與應用層(也稱為平台層)分離,可以讓您獨立地擴展和配置兩個層級。新增一個 API 僅需增加應用伺服器,不必額外增加 Web 伺服器。單一職責原則主張建立小型且自治的服務共同運作。小型團隊與小型服務能更積極規劃快速成長。

應用層中的工作者也有助於實現非同步

微服務

與此討論相關的是微服務,可描述為一套可獨立部署的小型、模組化服務。每個服務執行獨立程序,並透過明確定義且輕量的機制進行通訊以達成業務目標。1

以 Pinterest 為例,可能會有如下微服務:用戶資料、追蹤者、動態、搜尋、照片上傳等。

服務發現

像是 ConsulEtcdZookeeper 等系統,可協助服務透過追蹤註冊名稱、位址及埠口來彼此尋找。健康檢查可驗證服務的完整性,且通常透過 HTTP 端點進行。Consul 和 Etcd 均內建有鍵值儲存,可用於儲存設定值及其他共用資料。

缺點:應用層

來源及延伸閱讀

資料庫


來源:擴展到你的第一千萬用戶

關聯式資料庫管理系統(RDBMS)

關聯式資料庫如 SQL 是以表格形式組織的資料項集合。

ACID 是關聯式資料庫交易的一組屬性。

有許多技術可用於擴展關聯式資料庫:主從複製主主複製聯邦式架構分片去正規化SQL 調校

#### 主從複製

主節點負責讀寫操作,並將寫入操作複製到一個或多個僅負責讀取的從節點。從節點也可以像樹狀結構般進一步複製到其他從節點。如果主節點離線,系統仍可繼續以唯讀模式運作,直到某個從節點升級為主節點或配置新的主節點。


來源:Scalability, availability, stability, patterns

##### 缺點:主從複製

#### 主主複製

兩個主節點都提供讀寫服務,並在寫入時彼此協調。如果任一主節點故障,系統仍可繼續進行讀寫操作。


來源:Scalability, availability, stability, patterns

##### 缺點:主主複製

##### 缺點:複寫

##### 資料來源與延伸閱讀:複寫

#### 聯邦式架構


來源:Scaling up to your first 10 million users

聯邦(或功能分割)是依據功能將資料庫分割。例如,與其使用單一的整體資料庫,不如設置三個資料庫:論壇用戶以及產品,這樣可以減少每個資料庫的讀寫流量,因此減少複寫延遲。較小的資料庫能有更多資料被放入記憶體,進而提升快取命中率(因快取區域性提高)。由於沒有單一中央主節點序列化寫入,你可以並行寫入,增加吞吐量。

##### 缺點:聯邦

##### 資料來源與延伸閱讀:聯邦

#### 分片


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

分片(Sharding)將資料分佈到不同的資料庫中,使每個資料庫只管理部分資料。以用戶資料庫為例,隨著用戶數量的增加,可以向叢集新增更多分片。

聯邦的優點類似,分片可以減少讀寫流量、減少複製量並提高快取命中率。索引大小也會縮小,這通常可提升查詢速度與效能。如果某一個分片故障,其他分片仍能運作,雖然你會希望加入某種複製機制以避免資料遺失。像聯邦一樣,沒有單一中央主控序列化寫入,因此可以平行寫入並提升吞吐量。

常見的用戶資料表分片方式包括根據用戶姓氏的首字母或用戶的地理位置進行分配。

##### 缺點:分片

##### 來源及延伸閱讀:分片

#### 非正規化(Denormalization)

非正規化旨在提升讀取效能,但會犧牲部分寫入效能。為避免昂貴的聯合查詢,會將冗餘的資料副本寫入多個資料表。有些關聯式資料庫(如 PostgreSQL 與 Oracle)支援物化檢視表,能自動處理儲存冗餘資訊並保持副本一致性。

一旦資料透過聯邦分片等技術分散後,跨資料中心進行聯合查詢的管理會更加複雜。非正規化有時能避免這類複雜的聯合查詢需求。

在多數系統中,讀取操作通常遠多於寫入操作,比例可達 100:1 甚至 1000:1。一個需要複雜資料庫聯合查詢的讀取操作,可能非常昂貴,且需耗費大量磁碟操作時間。

##### 缺點:非正規化

###### 來源及延伸閱讀:非正規化 #### SQL 調校

SQL 調校是一個廣泛的主題,許多書籍已經作為參考資料出版。

進行效能基準測試效能剖析以模擬及發現瓶頸非常重要。

基準測試與效能剖析可能會引導你進行下列優化。

##### 收緊資料表結構

##### 使用良好的索引

##### 避免昂貴的 join

##### 分割資料表

##### 調整查詢快取

##### 來源及延伸閱讀:SQL 調校

NoSQL

NoSQL 是一種以鍵值儲存文件儲存寬欄儲存圖形資料庫表示的資料集合。資料通常是非正規化的,且連接操作一般在應用程式程式碼中完成。大多數 NoSQL 儲存系統缺乏真正的 ACID 交易,並偏好最終一致性

BASE 常用來描述 NoSQL 資料庫的特性。與CAP 定理相比,BASE 選擇可用性而非一致性。

除了選擇SQL 或 NoSQL之外,了解哪一種 NoSQL 資料庫最適合你的使用情境也很重要。接下來我們將介紹鍵值儲存文件儲存寬欄儲存圖形資料庫

#### 鍵值儲存

抽象概念:雜湊表

鍵值儲存通常允許 O(1) 讀取與寫入,且常以記憶體或 SSD 為後端。資料儲存可以維持鍵值的字典序排序,使得鍵範圍的高效檢索成為可能。鍵值儲存可以讓值附帶中繼資料。

鍵值儲存提供高效能,常用於簡單的資料模型或快速變化的資料,如記憶體快取層。由於只提供有限的操作集,若需要更多操作,複雜度會轉移到應用層。

鍵值儲存是更複雜系統(如文件儲存,有時甚至是圖形資料庫)的基礎。

##### 來源及延伸閱讀:鍵值儲存

#### 文件存儲

抽象:以文件作為值的鍵值存儲

文件存儲以文件(XML、JSON、二進位等)為核心,每個文件儲存一個物件的所有資訊。文件存儲提供 API 或查詢語言,可以根據文件本身的內部結構進行查詢。注意,許多鍵值存儲包含處理值的中繼資料功能,這使得這兩種存儲型態的界線變得模糊。

根據底層實作,文件可以依照集合、標籤、中繼資料或目錄來組織。雖然文件可以被組織或群組在一起,但每個文件的欄位可能完全不同。

一些文件存儲如 MongoDBCouchDB 也提供類 SQL 語言以執行複雜查詢。DynamoDB 同時支援鍵值與文件。

文件存儲提供高度彈性,常用於處理偶爾變動的資料。

##### 來源與延伸閱讀:文件存儲

#### 寬列表存儲


來源:SQL & NoSQL,簡史

抽象:巢狀 map ColumnFamily>

寬列表存儲的基本資料單位是欄(名稱/值配對)。一個欄可以被分組為欄族(類似 SQL 的資料表)。超級欄族則進一步將欄族分組。你可以用列鍵獨立存取每個欄,具有相同列鍵的欄組成一列。每個值都包含一個時間戳記,用於版本控制與衝突解決。

Google 推出 Bigtable 作為第一個寬列表存儲,影響了開源的 HBase,常見於 Hadoop 生態系,以及 Facebook 的 Cassandra。BigTable、HBase 和 Cassandra 等存儲會以字典順序維護鍵,讓特定鍵範圍的檢索更有效率。

寬列表存儲提供高可用性和高擴展性。它們常用於處理極大規模資料集。

##### 來源與延伸閱讀:寬列表存儲

#### 圖形資料庫


來源:圖形資料庫

抽象:圖形

在圖形資料庫中,每個節點是一筆記錄,每個弧則是兩個節點間的關係。圖形資料庫針對表示具有許多外鍵或多對多關係的複雜關係進行了優化。

圖形資料庫對於具有複雜關係的資料模型(如社交網路)提供高效能。由於相對較新,目前尚未被廣泛使用;開發工具和資源可能較難取得。許多圖形資料庫只能透過 REST API 存取。

##### 來源及進一步閱讀:圖形

#### 來源及進一步閱讀:NoSQL

SQL 還是 NoSQL


來源:從 RDBMS 過渡到 NoSQL

選擇 SQL 的原因:

選擇 NoSQL 的原因:

適合 NoSQL 的範例資料:

##### 資料來源及延伸閱讀:SQL 或 NoSQL

快取


來源:Scalable system design patterns

快取能提升頁面載入速度,並減少伺服器和資料庫的負擔。在此模型中,分派器會先查詢該請求是否曾被提出過,並嘗試尋找先前的結果來回應,以節省實際執行的資源。

資料庫通常受益於其分區上的讀寫均勻分佈。熱門項目可能會使分佈失衡,造成瓶頸。在資料庫前加入快取可協助吸收不均勻的負載與流量高峰。

用戶端快取

快取可以部署在用戶端(作業系統或瀏覽器)、伺服器端 或獨立快取層。

CDN 快取

CDN 被視為一種類型的快取。

網頁伺服器快取

反向代理 和如 Varnish 之類的快取能直接服務靜態及動態內容。網頁伺服器也可以快取請求,回傳回應而無須聯絡應用程式伺服器。

資料庫快取

資料庫通常在預設配置中包含某種程度的快取,針對一般用例進行最佳化。根據特定使用模式微調這些設定可以進一步提升效能。

應用程式快取

記憶體快取如 Memcached 與 Redis 是位於應用程式和資料儲存之間的鍵值儲存。由於資料儲存在 RAM 中,讀取速度遠快於一般將資料存於硬碟的資料庫。RAM 容量較硬碟有限,因此可利用 快取失效 演算法,如 最近最少使用 (LRU)),來清除「冷」項目並將「熱」資料保留在 RAM 中。

Redis 還具備以下額外功能:

快取有多個層級,主要分為兩大類:資料庫查詢物件

通常應避免使用檔案型快取,因為這會使複製和自動擴充變得困難。

在資料庫查詢層級進行快取

每當你查詢資料庫時,將查詢內容進行雜湊,作為鍵並將結果存入快取。這種方法存在過期相關的問題:

在物件層級進行快取

將你的資料視為物件,類似你在應用程式碼中所做的。讓你的應用程式將資料集從資料庫組合成類別實例或資料結構:

建議可快取的內容:

何時更新快取

由於快取只能儲存有限量的資料,你需要判斷哪種快取更新策略最適合你的使用情境。

#### Cache-aside


來源:From cache to in-memory data grid

應用程式負責從儲存空間讀寫資料。快取並不直接和儲存空間互動。應用程式執行以下操作:

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 通常以此方式使用。

隨後從快取中讀取已加入的資料非常迅速。Cache-aside 也被稱為 lazy loading(延遲載入)。只有被請求的資料才會被快取,這可避免快取中充斥未被請求的資料。

##### 缺點:cache-aside

#### Write-through(直寫快取)


來源:Scalability, availability, stability, patterns

應用程式將快取作為主要資料存儲區,對快取進行資料的讀寫,而快取則負責與資料庫的資料讀寫:

應用程式程式碼:

set_user(12345, {"foo":"bar"})

快取程式碼:

def set_user(user_id, values):
    user = db.query("UPDATE Users WHERE id = {0}", user_id, values)
    cache.set(user_id, user)
寫入直通(Write-through)由於寫入操作而導致整體運作較慢,但隨後對剛剛寫入的資料進行讀取時則非常快速。使用者在更新資料時通常比在讀取資料時更能容忍延遲。快取中的資料不會過時。

##### 缺點:寫入直通

#### 寫入後端(Write-behind/Write-back)


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

在寫入後端中,應用程式會執行以下操作:

##### 缺點:寫入後端

#### 預先刷新(Refresh-ahead)


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

你可以配置快取,使其在任何最近存取的快取條目到期之前自動刷新。

如果快取能夠準確預測未來可能需要的項目,預先刷新能比讀取直通降低延遲。

##### 缺點:預先刷新

缺點:快取

來源與延伸閱讀

非同步性


來源:規模化系統架構入門

非同步工作流程有助於減少需要高耗時操作的請求時間,這些操作若同步執行會拖慢整體流程。它們也能提前執行費時的工作,例如定期彙總數據。

訊息佇列

訊息佇列負責接收、保存並傳遞訊息。如果某項操作過於緩慢而無法同步執行,可以用訊息佇列搭配以下流程:

用戶端不會被阻塞,工作會在背景執行。在這段期間,用戶端也可以選擇執行少量處理,讓任務看起來好像已經完成。例如發送推文時,推文可以立即顯示在你的時間軸上,但實際送達所有粉絲可能還需要一段時間。

Redis 可作為簡單的訊息代理,但訊息有可能遺失。

RabbitMQ 很受歡迎,但你需要適應 'AMQP' 協議並自行管理節點。 Amazon SQS 是託管式服務,但可能有較高的延遲,且訊息有可能被重複傳送。

任務佇列

任務佇列接收任務及其相關資料,執行任務,然後傳送其結果。它們可以支援排程,並可用於在背景執行高運算密集的作業。

Celery 支援排程,主要支援 Python。

背壓

如果佇列開始顯著成長,佇列大小可能超過記憶體,導致快取失效、磁碟讀取,甚至效能更慢。背壓 可以透過限制佇列大小來幫助維持高吞吐率,以及良好的佇列中工作回應時間。當佇列已滿時,客戶端會收到伺服器忙碌或 HTTP 503 狀態碼,請稍後再試。客戶端可在稍後重試請求,也許可用 指數退避

缺點:非同步性

來源及進階閱讀

通訊


來源:OSI 七層模型

超文字傳輸協定(HTTP)

HTTP 是用於編碼及傳輸資料的用戶端與伺服器間的方法。它是請求/回應協定:用戶端發出請求,伺服器回應相關內容及請求完成狀態。HTTP 是自包含的,允許請求與回應經由多個中介路由器與伺服器流通,這些設備可執行負載均衡、快取、加密及壓縮。

基本的 HTTP 請求包含一個動詞(方法)和一個資源(端點)。以下是常見的 HTTP 動詞:

| 動詞 | 描述 | 達冪性* | 安全性 | 可快取 |

| GET | 讀取資源 | 是 | 是 | 是 | | POST | 創建資源或觸發處理資料的流程 | 否 | 否 | 若回應包含新鮮度資訊則為是 | | PUT | 創建或替換資源 | 是 | 否 | 否 | | PATCH | 部分更新資源 | 否 | 否 | 若回應包含新鮮度資訊則為是 | | DELETE | 刪除資源 | 是 | 否 | 否 |

*可以多次呼叫且結果不會不同。

HTTP 是一種應用層協定,依賴於如 TCPUDP 等較低層的協定。

#### 來源及進一步閱讀:HTTP

傳輸控制協定(TCP)


來源:如何製作多人遊戲

TCP 是一種在 IP 網路 上的面向連線協定。連線的建立和終止是透過 握手 完成的。所有發送的封包都保證以原始順序且無損壞地到達目的地,透過以下方式:

如果發送端未收到正確的回應,會重新傳送封包。若多次逾時,連線將被中斷。TCP 也實作了 流量控制) 和 壅塞控制。這些保證造成延遲,通常比 UDP 傳輸效率低。

為了確保高吞吐量,Web 伺服器可保持大量 TCP 連線開啟,導致高記憶體使用率。若 Web 伺服器執行緒與如 memcached 伺服器間有大量開啟連線,則成本昂貴。可以採用 連線池,或者在適用時改用 UDP。

TCP 適用於需要高可靠性但對時間要求較低的應用,例如 Web 伺服器、資料庫資訊、SMTP、FTP 和 SSH。

當下列情況時選用 TCP 而非 UDP:

使用者資料包協定(UDP)


來源:如何製作多人遊戲

UDP 是無連線式的。資料包(類似於封包)僅在資料包層級被保證。資料包可能無序抵達目的地,甚至完全未抵達。UDP 不支援壅塞控制。由於缺少 TCP 提供的保證,UDP 通常更有效率。

UDP 可以廣播,將資料包發送給子網路上的所有設備。這在 DHCP 中很有用,因為客戶端尚未獲取 IP 位址,因此無法讓 TCP 在沒有 IP 位址時進行串流。

UDP 的可靠性較低,但在即時用途如 VoIP、視訊聊天、串流及即時多人遊戲中表現良好。

在下列情況下選擇 UDP 而非 TCP:

#### 來源與進一步閱讀:TCP 和 UDP

遠端程序呼叫(RPC)


來源:破解系統設計面試

在 RPC 中,客戶端會在不同的位址空間(通常是遠端伺服器)上執行某個程序。該程序的編碼方式就像是本地程序呼叫,將與伺服器溝通的細節從客戶端程式中抽象出來。遠端呼叫通常比本地呼叫慢且不可靠,因此區分 RPC 呼叫與本地呼叫是有幫助的。知名的 RPC 框架包括 ProtobufThriftAvro

RPC 是一種請求-回應協定:

範例 RPC 呼叫:

GET /someoperation?data=anId

POST /anotheroperation { "data":"anId"; "anotherdata": "another value" }

RPC 著重於暴露行為。RPC 通常用於內部通訊以提升效能,因為你可以手工打造原生呼叫以更符合你的使用案例。

當符合以下情境時,請選擇原生函式庫(即 SDK):

遵循 REST 的 HTTP API 通常更常用於公開 API。

#### 缺點:RPC

表現層狀態轉換(REST)

REST 是一種強制客戶端/伺服器模式的架構風格,其中客戶端操作由伺服器管理的一組資源。伺服器提供資源的表現與可操作資源或取得新表現的動作。所有通訊必須是無狀態且可快取。

RESTful 介面有四大特性:

REST 呼叫範例:

GET /someresources/anId

PUT /someresources/anId {"anotherdata": "another value"}

REST 著重於暴露資料。它最小化了客戶端與伺服器之間的耦合,並且常用於公開的 HTTP API。REST 透過 URI 來暴露資源、以標頭表示、以及以如 GET、POST、PUT、DELETE 和 PATCH 等動詞來執行動作。REST 為無狀態設計,非常適合水平擴展與分割。

#### 缺點:REST

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

安全性

本章節尚可更新。歡迎貢獻

安全是一個廣泛的主題。除非你有豐富的經驗、安全背景,或是申請需要安全知識的職位,否則你大概只需要了解基本知識:

資源與延伸閱讀

附錄

有時你會被要求做「隨手估算」。例如,你可能需要估算從磁碟產生 100 個影像縮圖需要多長時間,或某個資料結構會佔用多少記憶體。二的次方表每個程式設計師都該知道的延遲數據是很好的參考資料。

二的次方表

Power           Exact Value         Approx Value        Bytes
---------------------------------------------------------------
7                             128
8                             256
10                           1024   1 thousand           1 KB
16                         65,536                       64 KB
20                      1,048,576   1 million            1 MB
30                  1,073,741,824   1 billion            1 GB
32                  4,294,967,296                        4 GB
40              1,099,511,627,776   1 trillion           1 TB

#### 來源及進一步閱讀

每位程式設計師都應該知道的延遲數字

Latency Comparison Numbers
--------------------------
L1 cache reference                           0.5 ns
Branch mispredict                            5   ns
L2 cache reference                           7   ns                      14x L1 cache
Mutex lock/unlock                           25   ns
Main memory reference                      100   ns                      20x L2 cache, 200x L1 cache
Compress 1K bytes with Zippy            10,000   ns       10 us
Send 1 KB bytes over 1 Gbps network     10,000   ns       10 us
Read 4 KB randomly from SSD*           150,000   ns      150 us          ~1GB/sec SSD
Read 1 MB sequentially from memory     250,000   ns      250 us
Round trip within same datacenter      500,000   ns      500 us
Read 1 MB sequentially from SSD*     1,000,000   ns    1,000 us    1 ms  ~1GB/sec SSD, 4X memory
HDD seek                            10,000,000   ns   10,000 us   10 ms  20x datacenter roundtrip
Read 1 MB sequentially from 1 Gbps  10,000,000   ns   10,000 us   10 ms  40x memory, 10X SSD
Read 1 MB sequentially from HDD     30,000,000   ns   30,000 us   30 ms 120x memory, 30X SSD
Send packet CA->Netherlands->CA    150,000,000   ns  150,000 us  150 ms

Notes ----- 1 ns = 10^-9 seconds 1 us = 10^-6 seconds = 1,000 ns 1 ms = 10^-3 seconds = 1,000 us = 1,000,000 ns

根據上述數據的實用指標:

#### 延遲數據視覺化

#### 來源及延伸閱讀

更多系統設計面試問題

常見系統設計面試問題,並附有解決方式相關資源連結。

| 問題 | 參考資源 | |---|---| | 設計類似 Dropbox 的檔案同步服務 | youtube.com | | 設計類似 Google 的搜尋引擎 | queue.acm.org
stackexchange.com
ardendertat.com
stanford.edu | | 設計類似 Google 的可擴展網路爬蟲 | quora.com | | 設計 Google docs | code.google.com
neil.fraser.name | | 設計類似 Redis 的鍵值儲存庫 | slideshare.net | | 設計類似 Memcached 的快取系統 | slideshare.net | | 設計類似 Amazon 的推薦系統 | hulu.com
ijcai13.org | | 設計類似 Bitly 的 tinyurl 系統 | n00tc0d3r.blogspot.com | | 設計類似 WhatsApp 的聊天應用程式 | highscalability.com | 設計類似 Instagram 的圖片分享系統 | highscalability.com
highscalability.com | | 設計 Facebook 動態消息功能 | quora.com
quora.com
slideshare.net | | 設計 Facebook 時間軸功能 | facebook.com
highscalability.com | | 設計 Facebook 聊天功能 | erlang-factory.com
facebook.com |

| 設計一個像 Facebook 的圖譜搜尋功能 | facebook.com
facebook.com
facebook.com | | 設計一個像 CloudFlare 的內容傳遞網路 | figshare.com | | 設計一個像 Twitter 的熱門話題系統 | michael-noll.com
snikolov .wordpress.com | | 設計一個隨機 ID 產生系統 | blog.twitter.com
github.com | | 回傳某段時間區間內的前 k 筆請求 | cs.ucsb.edu
wpi.edu | | 設計一個從多個資料中心提供資料的系統 | highscalability.com | | 設計一個線上多人紙牌遊戲 | indieflashblog.com
buildnewgames.com | | 設計一個垃圾回收系統 | stuffwithstuff.com
washington.edu | | 設計一個 API 請求速率限制器 | https://stripe.com/blog/ | | 設計一個交易所(如 NASDAQ 或 Binance) | Jane Street
Golang Implementation
Go Implementation | | 新增系統設計問題 | Contribute |

真實世界架構

關於真實世界系統設計的文章。


來源:Twitter 時間軸的擴展性

對以下文章不要聚焦於細節,而是:

|類型 | 系統 | 參考資料 | |---|---|---| | 資料處理 | MapReduce - Google 的分散式資料處理 | research.google.com | | 資料處理 | Spark - Databricks 的分散式資料處理 | slideshare.net | | 資料處理 | Storm - Twitter 的分散式資料處理 | slideshare.net | | | | | | 資料儲存 | Bigtable - Google 的分散式欄位式資料庫 | harvard.edu | | 資料儲存 | HBase - Bigtable 的開源實作 | slideshare.net | | 資料儲存 | Cassandra - Facebook 的分散式欄位式資料庫 | slideshare.net | 資料儲存 | DynamoDB - Amazon 的文件導向資料庫 | harvard.edu | | 資料儲存 | MongoDB - 文件導向資料庫 | slideshare.net | | 資料儲存 | Spanner - Google 的全球分散式資料庫 | research.google.com | | 資料儲存 | Memcached - 分散式記憶體快取系統 | slideshare.net | | 資料儲存 | Redis - 具持久性與多種值型態的分散式記憶體快取系統 | slideshare.net | | | | | | 檔案系統 | Google File System (GFS) - 分散式檔案系統 | research.google.com | | 檔案系統 | Hadoop File System (HDFS) - GFS 的開源實作 | apache.org | | | | | | 其他 | Chubby - Google 提供的鬆耦合分散式系統鎖服務 | research.google.com | | 其他 | Dapper - 分散式系統追蹤基礎架構 | research.google.com | 其他 | Kafka - LinkedIn 推出的發布/訂閱訊息佇列 | slideshare.net | | 其他 | Zookeeper - 提供同步化的集中式基礎設施與服務 | slideshare.net | | | 新增一個架構 | Contribute |

公司架構

| 公司 | 參考資料 | |---|---| | Amazon | Amazon 架構 | | Cinchcast | 每天產出1,500小時音訊 | | DataSift | 每秒120,000則推文的即時資料探勘 | | Dropbox | 我們如何擴充 Dropbox | | ESPN | 每秒運作100,000次 duh nuh nuhs | | Google | Google 架構 | | Instagram | 1,400萬用戶,數TB照片
Instagram 運作原理 | | Justin.tv | Justin.Tv 的直播影片廣播架構 | | Facebook | Facebook 擴充 Memcached
TAO: Facebook 的分散式社群圖資料儲存
Facebook 的照片儲存
Facebook Live 同時串流80萬人 | | Flickr | Flickr 架構 | | Mailbox | 6週內用戶從0到百萬 | | Netflix | Netflix 全端架構360度總覽
Netflix:按下播放鍵會發生什麼? | | Pinterest | 每月從0到數十億頁檢視
1,800萬訪客,10倍成長,12名員工 | | Playfish | 每月5,000萬用戶且持續成長 | | PlentyOfFish | PlentyOfFish 架構 | | Salesforce | 每天處理13億筆交易的架構 | | Stack Overflow | Stack Overflow 架構 | | TripAdvisor | 4,000萬訪客,2億動態頁檢視,30TB資料 | | Tumblr | 每月150億頁檢視 | | Twitter | Twitter 提升效能10,000%
每天用 MySQL 儲存2.5億則推文
1.5億活躍用戶,30萬QPS,22MB/S資料流
大規模時間軸
Twitter 的大數據與小數據
Twitter 運維:超越1億用戶的擴充
Twitter 每秒處理3,000張圖片 | | Uber | Uber 即時市場平台擴充方式
Uber 擴充到2,000工程師、1,000服務、8,000 Git 儲存庫的經驗教訓 | | WhatsApp | Facebook 以190億美元收購的 WhatsApp 架構 | | YouTube | YouTube 可擴展性
YouTube 架構 |

公司工程部落格

面試公司時的架構參考。
>
遇到的問題可能來自相同領域。

#### 來源與進一步閱讀

想要新增部落格嗎?為了避免重複工作,請考慮將您的公司部落格新增至以下倉庫:

正在開發中

有興趣新增章節或協助完成正在進行的章節嗎?貢獻

鳴謝

本倉庫中各處皆有提供鳴謝與來源。

特別感謝:

聯絡資訊

歡迎隨時聯繫我,討論任何問題、疑問或意見。

我的聯絡資訊可在我的 GitHub 頁面 找到。

授權

我在這個儲存庫中提供的程式碼和資源是以開源授權方式提供給您的。由於這是我的個人儲存庫,您取得的程式碼和資源授權是由我本人,而非我的僱主(Facebook)所提供。

版權所有 2017 Donne Martin

創用CC 姓名標示 4.0 國際授權條款 (CC BY 4.0)

http://creativecommons.org/licenses/by/4.0/

--- Tranlated By Open Ai Tx | Last indexed: 2025-08-09 ---