- 原文地址:github.com/donnemartin…
- 譯文出自:掘金翻譯計劃
- 譯者:XatMassacrE、L9m、Airmacho、xiaoyusilen、jifaxu
- 請持續關注 中文維護連接 獲取最新內容。
有興趣參與翻譯? 如下是正在進行中的翻譯:javascript
學習如何設計大型系統。php
爲系統設計的面試作準備。html
學習如何設計可擴展的系統將會有助於你成爲一個更好的工程師。前端
系統設計是一個很寬泛的話題。在互聯網上,關於系統設計原則的資源也是多如牛毛。java
這個倉庫就是這些資源的組織收集,它能夠幫助你學習如何構建可擴展的系統。python
這是一個不斷更新的開源項目的初期的版本。mysql
歡迎貢獻!react
在不少科技公司中,除了代碼面試,系統設計也是技術面試過程中的一個必要環節。android
實踐常見的系統設計面試題而且把你的答案和例子的解答進行對照:討論,代碼和圖表。ios
面試準備的其餘主題:
這裏提供的抽認卡堆使用間隔重複的方法,幫助你記憶關鍵的系統設計概念。
隨時隨地均可使用。
你正在尋找資源以準備編程面試嗎?
請查看咱們的姐妹倉庫互動式編程挑戰,其中包含了一個額外的抽認卡堆:
從社區中學習。
歡迎提交 PR 提供幫助:
一些還須要完善的內容放在了正在完善中。
請查看貢獻指南。
各類系統設計主題的摘要,包括優勢和缺點。每個主題都面臨着取捨和權衡。
每一個章節都包含着更的資源的連接。
基於你面試的時間線(短、中、長)去複習那些推薦的主題。
問:對於面試來講,我須要知道這裏的全部知識點嗎?
答:不,若是隻是爲了準備面試的話,你並不須要知道全部的知識點。
在一場面試中你會被問到什麼取決於下面這些因素:
那些有經驗的候選人一般會被指望瞭解更多的系統設計的知識。架構師或者團隊負責人則會被指望瞭解更多除了我的貢獻以外的知識。頂級的科技公司一般也會有一次或者更多的系統設計面試。
面試會很寬泛的展開並在幾個領域深刻。這回幫助你瞭解一些關於系統設計的不一樣的主題。基於你的時間線,經驗,面試的職位和麪試的公司對下面的指導作出適當的調整。
短時間 | 中期 | 長期 | |
---|---|---|---|
閱讀 系統設計主題 以得到一個關於系統如何工做的寬泛的認識 | :+1: | :+1: | :+1: |
閱讀一些你要面試的公司工程博客的文章 | :+1: | :+1: | :+1: |
閱讀 真實架構 | :+1: | :+1: | :+1: |
複習 如何處理一個系統設計面試題 | :+1: | :+1: | :+1: |
完成 系統設計的面試題和解答 | 一些 | 不少 | 大部分 |
完成 面向對象設計的面試題和解答 | 一些 | 不少 | 大部分 |
複習 其它的系統設計面試題 | 一些 | 不少 | 大部分 |
系統設計面試是一個開放式的對話。他們指望你去主導這個對話。
你能夠使用下面的步驟來指引討論。爲了鞏固這個過程,請使用下面的步驟完成系統設計的面試題和解答這個章節。
把全部須要的東西彙集在一塊兒,審視問題。不停的提問,以致於咱們能夠明確使用場景和約束。討論假設。
使用全部重要的組件來描繪出一個高級的設計。
對每個核心組件進行詳細深刻的分析。舉例來講,若是你被問到設計一個 url 縮寫服務,開始討論:
確認和處理瓶頸以及一些限制。舉例來講就是你須要下面的這些來完成拓展性的議題嗎?
論述可能的解決辦法和代價。每件事情須要取捨。能夠使用可拓展系統的設計原則來處理瓶頸。
你或許會被要求經過手算進行一些估算。涉及到的附錄涉及到的是下面的這些資源:
查看下面的連接以得到咱們指望的更好的想法:
普通的系統設計面試題和相關事例的論述,代碼和圖表。
與內容有關的解答在
solutions/
文件夾中。
問題 | |
---|---|
設計 Pastebin.com (或者 Bit.ly) | 解答 |
設計 Twitter 時間線和搜索 (或者 Facebook feed 和搜索) | 解答 |
設計一個網頁爬蟲 | 解答 |
設計 Mint.com | 解答 |
爲一個社交網絡設計數據結構 | 解答 |
爲搜索引擎設計一個 key-value 儲存 | 解答 |
經過分類特性設計 Amazon 的銷售排名 | 解答 |
在 AWS 上設計一個百萬用戶級別的系統 | 解答 |
添加一個系統設計問題 | 貢獻 |
常見面向對象設計面試問題及實例討論,代碼和圖表演示。
與內容相關的解決方案在
solutions/
文件夾中。注:此節還在完善中
問題 | |
---|---|
設計 hash map | 解決方案 |
設計 LRU 緩存 | 解決方案 |
設計一個呼叫中心 | 解決方案 |
設計一副牌 | 解決方案 |
設計一個停車場 | 解決方案 |
設計一個聊天服務 | 解決方案 |
設計一個環形數組 | 待解決 |
添加一個面向對象設計問題 | 待解決 |
不熟悉系統設計?
首先,你須要對通常性原則有一個基本的認識,知道它們是什麼,怎樣使用以及利弊。
接下來,咱們將看看高階的權衡和取捨:
記住每一個方面都面臨取捨和權衡。
而後,咱們將深刻更具體的主題,如 DNS、CDN 和負載均衡器。
若是服務性能的增加與資源的增長是成比例的,服務就是可擴展的。一般,提升性能意味着服務於更多的工做單元,另外一方面,當數據集增加時,一樣也能夠處理更大的工做單位。1
另外一個角度來看待性能與可擴展性:
延遲是執行操做或運算結果所花費的時間。
吞吐量是單位時間內(執行)此類操做或運算的數量。
一般,你應該以可接受級延遲下最大化吞吐量爲目標。
在一個分佈式計算系統中,只能同時知足下列的兩點:
網絡並不可靠,因此你應要支持分區容錯性,並須要在軟件可用性和一致性間作出取捨。
等待分區節點的響應可能會致使延時錯誤。若是你的業務需求須要原子讀寫,CP 是一個不錯的選擇。
響應節點上可用數據的最近版本可能並非最新的。當分區解析完後,寫入(操做)可能須要一些時間來傳播。
若是業務需求容許最終一致性,或當有外部故障時要求系統繼續運行,AP 是一個不錯的選擇。
有同一份數據的多份副本,咱們面臨着怎樣同步它們的選擇,以便讓客戶端有一致的顯示數據。回想 CAP 理論中的一致性定義 ─ 每次訪問都能得到最新數據但可能會收到錯誤響應
在寫入以後,訪問可能看到,也可能看不到(寫入數據)。盡力優化之讓其能訪問最新數據。
這種方式能夠 memcached 等系統中看到。弱一致性在 VoIP,視頻聊天和實時多人遊戲等真實用例中表現不錯。打個比方,若是你在通話中丟失信號幾秒鐘時間,當從新鏈接時你是聽不到這幾秒鐘所說的話的。
在寫入後,訪問最終能看到寫入數據(一般在數毫秒內)。數據被異步複製。
DNS 和 email 等系統使用的是此種方式。最終一致性在高可用性系統中效果不錯。
在寫入後,訪問當即可見。數據被同步複製。
文件系統和關係型數據庫(RDBMS)中使用的是此種方式。強一致性在須要記錄的系統中運做良好。
有兩種支持高可用性的模式: 故障切換(fail-over)和複製(replication)。
關於工做到備用的故障切換流程是,工做服務器發送週期信號給待機中的備用服務器。若是週期信號中斷,備用服務器切換成工做服務器的 IP 地址並恢復服務。
宕機時間取決於備用服務器處於「熱」待機狀態仍是須要從「冷」待機狀態進行啓動。只有工做服務器處理流量。
工做到備用的故障切換也被稱爲主從切換。
在雙工做切換中,雙方都在管控流量,在它們之間分散負載。
若是是外網服務器,DNS 將須要對兩方都瞭解。若是是內網服務器,應用程序邏輯將須要對兩方都瞭解。
雙工做切換也能夠稱爲主主切換。
這個主題進一步探討了數據庫部分:
域名系統是把 www.example.com 等域名轉換成 IP 地址。
域名系統是分層次的,一些 DNS 服務器位於頂層。當查詢(域名) IP 時,路由或 ISP 提供鏈接 DNS 服務器的信息。較底層的 DNS 服務器緩存映射,它可能會由於 DNS 傳播延時而失效。DNS 結果能夠緩存在瀏覽器或操做系統中一段時間,時間長短取決於存活時間 TTL。
CNAME
記錄( example.com 指向 www.example.com )或映射到一個 A
記錄。CloudFlare 和 Route 53 等平臺提供管理 DNS 的功能。某些 DNS 服務經過集中方式來路由流量:
內容分發網絡(CDN)是一個全球性的代理服務器分佈式網絡,它從靠近用戶的位置提供內容。一般,HTML/CSS/JS,圖片和視頻等靜態內容由 CDN 提供,雖然亞馬遜 CloudFront 等也支持動態內容。CDN 的 DNS 解析會告知客戶端鏈接哪臺服務器。
將內容存儲在 CDN 上能夠從兩個方面來提供性能:
當你服務器上內容發生變更時,推送 CDN 接受新內容。直接推送給 CDN 並重寫 URL 地址以指向你的內容的 CDN 地址。你能夠配置內容到期時間及什麼時候更新。內容只有在更改或新增是才推送,流量最小化,但儲存最大化。
CDN 拉取是當第一個用戶請求該資源時,從服務器上拉取資源。你將內容留在本身的服務器上並重寫 URL 指向 CDN 地址。直到內容被緩存在 CDN 上爲止,這樣請求只會更慢,
存活時間(TTL)決定緩存多久時間。CDN 拉取方式最小化 CDN 上的儲存空間,但若是過時文件並在實際更改以前被拉取,則會致使冗餘的流量。
高流量站點使用 CDN 拉取效果不錯,由於只有最近請求的內容保存在 CDN 中,流量才能更平衡地分散。
負載均衡器將傳入的請求分發到應用服務器和數據庫等計算資源。不管哪一種狀況,負載均衡器將從計算資源來的響應返回給恰當的客戶端。負載均衡器的效用在於:
負載均衡器能夠經過硬件(昂貴)或 HAProxy 等軟件來實現。
增長的好處包括:
一般會設置採用工做─備用 或 雙工做 模式的多個負載均衡器,以避免發生故障。
負載均衡器能基於多種方式來路由流量:
四層負載均衡根據監看傳輸層的信息來決定如何分發請求。一般,這會涉及來源,目標 IP 地址和請求頭中的端口,但不包括數據包(報文)內容。四層負載均衡執行網絡地址轉換(NAT)來向上遊服務器轉發網絡數據包。
七層負載均衡器根據監控應用層來決定怎樣分發請求。這會涉及請求頭的內容,消息和 cookie。七層負載均衡器終結網絡流量,讀取消息,作出負載均衡斷定,而後傳送給特定服務器。好比,一個七層負載均衡器能直接將視頻流量鏈接到託管視頻的服務器,同時將更敏感的用戶帳單流量引導到安全性更強的服務器。
以損失靈活性爲代價,四層負載均衡比七層負載均衡花費更少時間和計算資源,雖然這對現代商用硬件的性能影響甚微。
負載均衡器還能幫助水平擴展,提升性能和可用性。使用商業硬件的性價比更高,而且比在單臺硬件上垂直擴展更貴的硬件具備更高的可用性。相比招聘特定企業系統人才,招聘商業硬件方面的人才更加容易。
反向代理是一種能夠集中地調用內部服務,並提供統一接口給公共客戶的 web 服務器。來自客戶端的請求先被反向代理服務器轉發到可響應請求的服務器,而後代理再把服務器的響應結果返回給客戶端。
帶來的好處包括:
將 Web 服務層與應用層(也被稱做平臺層)分離,能夠獨立縮放和配置這兩層。添加新的 API 只須要添加應用服務器,而沒必要添加額外的 web 服務器。
單一職責原則提倡小型的,自治的服務共同合做。小團隊經過提供小型的服務,能夠更激進地計劃增加。
應用層中的工做進程也有能夠實現異步化。
與此討論相關的話題是 微服務,能夠被描述爲一系列能夠獨立部署的小型的,模塊化服務。每一個服務運行在一個獨立的線程中,經過明肯定義的輕量級機制通信,共同實現業務目標。1
例如,Pinterest 可能有這些微服務: 用戶資料、關注者、Feed 流、搜索、照片上傳等。
像 Consul,Etcd 和 Zookeeper 這樣的系統能夠經過追蹤註冊名、地址、端口等信息來幫助服務互相發現對方。Health checks 能夠幫助確認服務的完整性和是否常用一個 HTTP 路徑。Consul 和 Etcd 都有一個內建的 key-value 存儲 用來存儲配置信息和其餘的共享信息。
像 SQL 這樣的關係型數據庫是一系列以表的形式組織的數據項集合。
校對注:這裏做者 SQL 可能指的是 MySQL
ACID 用來描述關係型數據庫事務的特性。
關係型數據庫擴展包括許多技術:主從複製、主主複製、聯合、分片、非規範化和 SQL調優。
主庫同時負責讀取和寫入操做,並複製寫入到一個或多個從庫中,從庫只負責讀操做。樹狀形式的從庫再將寫入複製到更多的從庫中去。若是主庫離線,系統能夠以只讀模式運行,直到某個從庫被提高爲主庫或有新的主庫出現。
兩個主庫都負責讀操做和寫操做,寫入操做時互相協調。若是其中一個主庫掛機,系統能夠繼續讀取和寫入。
聯合(或按功能劃分)將數據庫按對應功能分割。例如,你能夠有三個數據庫:論壇、用戶和產品,而不只是一個單體數據庫,從而減小每一個數據庫的讀取和寫入流量,減小複製延遲。較小的數據庫意味着更多適合放入內存的數據,進而意味着更高的緩存命中概率。沒有隻能串行寫入的中心化主庫,你能夠並行寫入,提升負載能力。
分片將數據分配在不一樣的數據庫上,使得每一個數據庫僅管理整個數據集的一個子集。以用戶數據庫爲例,隨着用戶數量的增長,愈來愈多的分片會被添加到集羣中。
相似聯合的優勢,分片能夠減小讀取和寫入流量,減小複製並提升緩存命中率。也減小了索引,一般意味着查詢更快,性能更好。若是一個分片出問題,其餘的仍能運行,你能夠使用某種形式的冗餘來防止數據丟失。相似聯合,沒有隻能串行寫入的中心化主庫,你能夠並行寫入,提升負載能力。
常見的作法是用戶姓氏的首字母或者用戶的地理位置來分隔用戶表。
非規範化試圖以寫入性能爲代價來換取讀取性能。在多個表中冗餘數據副本,以免高成本的聯結操做。一些關係型數據庫,好比 PostgreSQl 和 Oracle 支持物化視圖,能夠處理冗餘信息存儲和保證冗餘副本一致。
當數據使用諸如聯合和分片等技術被分割,進一步提升了處理跨數據中心的聯結操做複雜度。非規範化能夠規避這種複雜的聯結操做。
在多數系統中,讀取操做的頻率遠高於寫入操做,比例可達到 100:1,甚至 1000:1。須要複雜的數據庫聯結的讀取操做成本很是高,在磁盤操做上消耗了大量時間。
SQL 調優是一個範圍很廣的話題,有不少相關的書能夠做爲參考。
利用基準測試和性能分析來模擬和發現系統瓶頸很重要。
基準測試和性能分析可能會指引你到如下優化方案。
CHAR
類型存儲固定長度的字段,不要用 VARCHAR
。
CHAR
在快速、隨機訪問時效率很高。若是使用 VARCHAR
,若是你想讀取下一個字符串,不得不先讀取到當前字符串的末尾。TEXT
類型存儲大塊的文本,例如博客正文。TEXT
還容許布爾搜索。使用 TEXT
字段須要在磁盤上存儲一個用於定位文本塊的指針。INT
類型存儲高達 2^32 或 40 億的較大數字。DECIMAL
類型存儲貨幣能夠避免浮點數表示錯誤。BLOBS
存儲對象,存儲存放對象的位置。VARCHAR(255)
是以 8 位數字存儲的最大字符數,在某些關係型數據庫中,最大限度地利用字節。NOT NULL
約束來提升搜索性能。SELECT
、GROUP BY
、ORDER BY
、JOIN
)的列若是用了索引會更快。NoSQL 是鍵-值數據庫、文檔型數據庫、列型數據庫或圖數據庫的統稱。數據庫是非規範化的,表聯結大多在應用程序代碼中完成。大多數 NoSQL 沒法實現真正符合 ACID 的事務,支持最終一致。
BASE 一般被用於描述 NoSQL 數據庫的特性。相比 CAP 理論,BASE 強調可用性超過一致性。
除了在 SQL 仍是 NoSQL 之間作選擇,瞭解哪一種類型的 NoSQL 數據庫最適合你的用例也是很是有幫助的。咱們將在下一節中快速瞭解下 鍵-值存儲、文檔型存儲、列型存儲和圖存儲數據庫。
抽象模型:哈希表
鍵-值存儲一般能夠實現 O(1) 時間讀寫,用內存或 SSD 存儲數據。數據存儲能夠按字典順序維護鍵,從而實現鍵的高效檢索。鍵-值存儲能夠用於存儲元數據。
鍵-值存儲性能很高,一般用於存儲簡單數據模型或頻繁修改的數據,如存放在內存中的緩存。鍵-值存儲提供的操做有限,若是須要更多操做,複雜度將轉嫁到應用程序層面。
鍵-值存儲是如文檔存儲,在某些狀況下,甚至是圖存儲等更復雜的存儲系統的基礎。
抽象模型:將文檔做爲值的鍵-值存儲
文檔類型存儲以文檔(XML、JSON、二進制文件等)爲中心,文檔存儲了指定對象的所有信息。文檔存儲根據文檔自身的內部結構提供 API 或查詢語句來實現查詢。請注意,許多鍵-值存儲數據庫有用值存儲元數據的特性,這也模糊了這兩種存儲類型的界限。
基於底層實現,文檔能夠根據集合、標籤、元數據或者文件夾組織。儘管不一樣文檔能夠被組織在一塊兒或者分紅一組,但相互之間可能具備徹底不一樣的字段。
MongoDB 和 CouchDB 等一些文檔類型存儲還提供了相似 SQL 語言的查詢語句來實現複雜查詢。DynamoDB 同時支持鍵-值存儲和文檔類型存儲。
文檔類型存儲具有高度的靈活性,經常使用於處理偶爾變化的數據。
抽象模型:嵌套的
ColumnFamily<RowKey, Columns<ColKey, Value, Timestamp>>
映射
類型存儲的基本數據單元是列(名/值對)。列能夠在列族(相似於 SQL 的數據表)中被分組。超級列族再分組普通列族。你能夠使用行鍵獨立訪問每一列,具備相同行鍵值的列組成一行。每一個值都包含版本的時間戳用於解決版本衝突。
Google 發佈了第一個列型存儲數據庫 Bigtable,它影響了 Hadoop 生態系統中活躍的開源數據庫 HBase 和 Facebook 的 Cassandra。像 BigTable,HBase 和 Cassandra 這樣的存儲系統將鍵以字母順序存儲,能夠高效地讀取鍵列。
列型存儲具有高可用性和高可擴展性。一般被用於大數據相關存儲。
抽象模型: 圖
在圖數據庫中,一個節點對應一條記錄,一個弧對應兩個節點之間的關係。圖數據庫被優化用於表示外鍵繁多的複雜關係或多對多關係。
圖數據庫爲存儲複雜關係的數據模型,如社交網絡,提供了很高的性能。它們相對較新,還沒有普遍應用,查找開發工具或者資源相對較難。許多圖只能經過 REST API 訪問。
選取 SQL 的緣由:
選取 NoSQL 的緣由:
適合 NoSQL 的示例數據:
緩存能夠提升頁面加載速度,並能夠減小服務器和數據庫的負載。在這個模型中,分發器先查看請求以前是否被響應過,若是有則將以前的結果直接返回,來省掉真正的處理。
數據庫分片均勻分佈的讀取是最好的。可是熱門數據會讓讀取分佈不均勻,這樣就會形成瓶頸,若是在數據庫前加個緩存,就會抹平不均勻的負載和突發流量對數據庫的影響。
緩存能夠位於客戶端(操做系統或者瀏覽器),服務端或者不一樣的緩存層。
CDN 也被視爲一種緩存。
反向代理和緩存(好比 Varnish)能夠直接提供靜態和動態內容。Web 服務器一樣也能夠緩存請求,返回相應結果而沒必要鏈接應用服務器。
數據庫的默認配置中一般包含緩存級別,針對通常用例進行了優化。調整配置,在不一樣狀況下使用不一樣的模式能夠進一步提升性能。
基於內存的緩存好比 Memcached 和 Redis 是應用程序和數據存儲之間的一種鍵值存儲。因爲數據保存在 RAM 中,它比存儲在磁盤上的典型數據庫要快多了。RAM 比磁盤限制更多,因此例如 least recently used (LRU) 的緩存無效算法能夠將「熱門數據」放在 RAM 中,而對一些比較「冷門」的數據不作處理。
Redis 有下列附加功能:
有多個緩存級別,分爲兩大類:數據庫查詢和對象:
通常來講,你應該儘可能避免基於文件的緩存,由於這使得複製和自動縮放很困難。
當你查詢數據庫的時候,將查詢語句的哈希值與查詢結果存儲到緩存中。這種方法會遇到如下問題:
將您的數據視爲對象,就像對待你的應用代碼同樣。讓應用程序將數據從數據庫中組合到類實例或數據結構中:
建議緩存的內容:
因爲你只能在緩存中存儲有限的數據,因此你須要選擇一個適用於你用例的緩存更新策略。
應用從存儲器讀寫。緩存不和存儲器直接交互,應用執行如下操做:
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 一般用這種方式使用。
添加到緩存中的數據讀取速度很快。緩存模式也稱爲延遲加載。只緩存所請求的數據,這避免了沒有被請求的數據佔滿了緩存空間。
應用使用緩存做爲主要的數據存儲,將數據讀寫到緩存中,而緩存負責從數據庫中讀寫數據。
應用代碼:
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)複製代碼
因爲存寫操做因此直寫模式總體是一種很慢的操做,可是讀取剛寫入的數據很快。相比讀取數據,用戶一般比較能接受更新數據時速度較慢。緩存中的數據不會過期。
在回寫模式中,應用執行如下操做:
你能夠將緩存配置成在到期以前自動刷新最近訪問過的內容。
若是緩存能夠準確預測未來可能請求哪些數據,那麼刷新可能會致使延遲與讀取時間的下降。
異步工做流有助於減小那些本來順序執行的請求時間。它們能夠經過提早進行一些耗時的工做來幫助減小請求時間,好比按期彙總數據。
消息隊列接收,保留和傳遞消息。若是按順序執行操做太慢的話,你能夠使用有如下工做流的消息隊列:
不去阻塞用戶操做,做業在後臺處理。在此期間,客戶端可能會進行一些處理使得看上去像是任務已經完成了。例如,若是要發送一條推文,推文可能會立刻出如今你的時間線上,可是可能須要一些時間才能將你的推文推送到你的全部關注者那裏去。
Redis 是一個使人滿意的簡單的消息代理,可是消息有可能會丟失。
RabbitMQ 很受歡迎可是要求你適應「AMQP」協議而且管理你本身的節點。
Amazon SQS 是被託管的,但可能具備高延遲,而且消息可能會被傳送兩次。
任務隊列接收任務及其相關數據,運行它們,而後傳遞其結果。 它們能夠支持調度,並可用於在後臺運行計算密集型做業。
Celery 支持調度,主要是用 Python 開發的。
若是隊列開始明顯增加,那麼隊列大小可能會超過內存大小,致使高速緩存未命中,磁盤讀取,甚至性能更慢。背壓能夠經過限制隊列大小來幫助咱們,從而爲隊列中的做業保持高吞吐率和良好的響應時間。一旦隊列填滿,客戶端將獲得服務器忙活着 HTTP 503 狀態碼,以便稍後重試。客戶端能夠在稍後時間重試該請求,也許是指數退避。
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)的應用層協議。
TCP 是經過 IP 網絡的面向鏈接的協議。 使用握手創建和斷開鏈接。 發送的全部數據包保證以原始順序到達目的地,用如下措施保證數據包不被損壞:
若是發送者沒有收到正確的響應,它將從新發送數據包。若是屢次超時,鏈接就會斷開。TCP 實行流量控制)和擁塞控制。這些確保措施會致使延遲,並且一般致使傳輸效率比 UDP 低。
爲了確保高吞吐量,Web 服務器能夠保持大量的 TCP 鏈接,從而致使高內存使用。在 Web 服務器線程間擁有大量開放鏈接可能開銷巨大,消耗資源過多,也就是說,一個 memcached 服務器。鏈接池 能夠幫助除了在適用的狀況下切換到 UDP。
TCP 對於須要高可靠性但時間緊迫的應用程序頗有用。好比包括 Web 服務器,數據庫信息,SMTP,FTP 和 SSH。
如下狀況使用 TCP 代替 UDP:
UDP 是無鏈接的。數據報(相似於數據包)只在數據報級別有保證。數據報可能會無序的到達目的地,也有可能會遺失。UDP 不支持擁塞控制。雖然不如 TCP 那樣有保證,但 UDP 一般效率更高。
UDP 能夠經過廣播將數據報發送至子網內的全部設備。這對 DHCP 頗有用,由於子網內的設備尚未分配 IP 地址,而 IP 對於 TCP 是必須的。
UDP 可靠性更低但適合用在網絡電話、視頻聊天,流媒體和實時多人遊戲上。
如下狀況使用 UDP 代替 TCP:
Source: Crack the system design interview
在 RPC 中,客戶端會去調用另外一個地址空間(一般是一個遠程服務器)裏的方法。調用代碼看起來就像是調用的是一個本地方法,客戶端和服務器交互的具體過程被抽象。遠程調用相對於本地調用通常較慢並且可靠性更差,所以區分二者是有幫助的。熱門的 RPC 框架包括 Protobuf、Thrift 和 Avro。
RPC 是一個「請求-響應」協議:
RPC 調用示例:
GET /someoperation?data=anId
POST /anotheroperation
{
"data":"anId";
"anotherdata": "another value"
}複製代碼
RPC 專一於暴露方法。RPC 一般用於處理內部通信的性能問題,這樣你能夠手動處理本地調用以更好的適應你的狀況。
當如下狀況時選擇本地庫(也就是 SDK):
遵循 REST 的 HTTP API 每每更適用於公共 API。
REST 是一種強制的客戶端/服務端架構設計模型,客戶端基於服務端管理的一系列資源操做。服務端提供修改或獲取資源的接口。全部的通訊必須是無狀態和可緩存的。
RESTful 接口有四條規則:
REST 請求的例子:
GET /someresources/anId
PUT /someresources/anId
{"anotherdata": "another value"}複製代碼
REST 關注於暴露數據。它減小了客戶端/服務端的耦合程度,常常用於公共 HTTP API 接口設計。REST 使用更一般與規範化的方法來經過 URI 暴露資源,經過 header 來表述並經過 GET、POST、PUT、DELETE 和 PATCH 這些動做來進行操做。由於無狀態的特性,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 嗎
這一部分須要更多內容。一塊兒來吧!
安全是一個寬泛的話題。除非你有至關的經驗、安全方面背景或者正在申請的職位要求安全知識,你不須要了解安全基礎知識之外的內容:
一些時候你會被要求作出保守估計。好比,你可能須要估計從磁盤中生成 100 張圖片的縮略圖須要的時間或者一個數據結構須要多少的內存。2 的次方表和每一個開發者都須要知道的一些時間數據(譯註:OSChina 上有這篇文章的譯文)都是一些很方便的參考資料。
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 100 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複製代碼
基於上述數字的指標:
常見的系統設計面試問題,給出瞭如何解決的方案連接
問題 | 引用 |
---|---|
設計相似於 Dropbox 的文件同步服務 | youtube.com |
設計相似於 Google 的搜索引擎 | queue.acm.org stackexchange.com ardendertat.com stanford.edu |
設計相似於 Google 的可擴展網絡爬蟲 | quora.com |
設計 Google 文檔 | code.google.com neil.fraser.name |
設計相似 Redis 的建值存儲 | slideshare.net |
設計相似 Memcached 的緩存系統 | slideshare.net |
設計相似亞馬遜的推薦系統 | hulu.com ijcai13.org |
設計相似 Bitly 的短連接系統 | 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 的內容傳遞網絡 | cmu.edu |
設計相似 Twitter 的熱門話題系統 | michael-noll.com snikolov .wordpress.com |
設計一個隨機 ID 生成系統 | blog.twitter.com github.com |
返回必定時間段內次數前 k 高的請求 | ucsb.edu wpi.edu |
設計一個數據源於多個數據中心的服務系統 | highscalability.com |
設計一個多人網絡卡牌遊戲 | indieflashblog.com buildnewgames.com |
設計一個垃圾回收系統 | stuffwithstuff.com washington.edu |
添加更多的系統設計問題 | 貢獻 |
關於現實中真實的系統是怎麼設計的文章。
Source: Twitter timelines at scale
不要專一於如下文章的細節,專一於如下方面:
類型 | 系統 | 引用 |
---|---|---|
Data processing | MapReduce - Google的分佈式數據處理 | research.google.com |
Data processing | Spark - Databricks 的分佈式數據處理 | slideshare.net |
Data processing | Storm - Twitter 的分佈式數據處理 | slideshare.net |
Data store | Bigtable - Google 的列式數據庫 | harvard.edu |
Data store | HBase - Bigtable 的開源實現 | slideshare.net |
Data store | Cassandra - Facebook 的列式數據庫 | slideshare.net |
Data store | DynamoDB - Amazon 的文檔數據庫 | harvard.edu |
Data store | MongoDB - 文檔數據庫 | slideshare.net |
Data store | Spanner - Google 的全球分佈數據庫 | research.google.com |
Data store | Memcached - 分佈式內存緩存系統 | slideshare.net |
Data store | Redis - 可以持久化及具備值類型的分佈式內存緩存系統 | slideshare.net |
File system | Google File System (GFS) - 分佈式文件系統 | research.google.com |
File system | Hadoop File System (HDFS) - GFS 的開源實現 | apache.org |
Misc | Chubby - Google 的分佈式系統的低耦合鎖服務 | research.google.com |
Misc | Dapper - 分佈式系統跟蹤基礎設施 | research.google.com |
Misc | Kafka - LinkedIn 的發佈訂閱消息系統 | slideshare.net |
Misc | Zookeeper - 集中的基礎架構和協調服務 | slideshare.net |
添加更多 | 貢獻 |
Company | Reference(s) |
---|---|
Amazon | Amazon 的架構 |
Cinchcast | 天天產生 1500 小時的音頻 |
DataSift | 每秒實時挖掘 120000 條 tweet |
DropBox | 咱們如何縮放 Dropbox |
ESPN | 每秒操做 100000 次 |
Google 的架構 | |
1400 萬用戶,達到兆級別的照片存儲 是什麼在驅動 Instagram |
|
Justin.tv | Justin.Tv 的直播廣播架構 |
Facebook 的可擴展 memcached TAO: Facebook 社交圖的分佈式數據存儲 Facebook 的圖片存儲 |
|
Flickr | Flickr 的架構 |
Mailbox | 在 6 周內從 0 到 100 萬用戶 |
從零到每個月數十億的瀏覽量 1800 萬訪問用戶,10 倍增加,12 名員工 |
|
Playfish | 月用戶量 5000 萬並在不斷增加 |
PlentyOfFish | PlentyOfFish 的架構 |
Salesforce | 他們天天如何處理 13 億筆交易 |
Stack Overflow | Stack Overflow 的架構 |
TripAdvisor | 40M 訪問者,200M 頁面瀏覽量,30TB 數據 |
Tumblr | 每個月 150 億的瀏覽量 |
Making Twitter 10000 percent faster 天天使用 MySQL 存儲2.5億條 tweet 150M 活躍用戶,300K QPS,22 MB/S 的防火牆 可擴展時間表 Twitter 的大小數據 Twitter 的行爲:規模超過 1 億用戶 |
|
Uber | Uber 如何擴展本身的實時化市場 |
Facebook 用 190 億美圓購買 WhatsApp 的架構 | |
YouTube | YouTube 的可擴展性 YouTube 的架構 |
你即將面試的公司的架構
你面對的問題可能就來自於一樣領域
有興趣加入添加一些部分或者幫助完善某些部分嗎?加入進來吧!
整個倉庫都提供了證書和源
特別鳴謝:
歡迎聯繫我討論本文的不足、問題或者意見。
能夠在個人 GitHub 主頁上找到個人聯繫方式
Creative Commons Attribution 4.0 International License (CC BY 4.0)
http://creativecommons.org/licenses/by/4.0/複製代碼
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、React、前端、後端、產品、設計 等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃。