想染指系統架構?看這篇就夠了
系統設計入門
目的
學習如何設計大型系統。
為系統設計的面試做準備。
學習如何設計大型系統
學習如何設計可擴展的系統將會有助于你成為一個更好的工程師。
系統設計是一個很寬泛的話題。在互聯網上, 關于系統設計原則的資源也是多如牛毛。
這個倉庫就是這些資源的 組織收集 ,它可以幫助你學習如何構建可擴展的系統。
從開源社區學習
這是一個不斷更新的開源項目的初期的版本。
歡迎!
為系統設計的面試做準備
在很多科技公司中,除了代碼面試,系統設計也是 技術面試過程 中的一個 必要環節 。
實踐常見的系統設計面試題并且把你的答案和 例子的解答 進行 對照 :討論,代碼和圖表。
面試準備的其他主題:
- 如何處理一個系統設計的面試題
- 系統設計的面試題, 含解答
- 面向對象設計的面試題, 含解答
抽認卡
這里提供的抽認卡堆使用間隔重復的方法,幫助你記憶關鍵的系統設計概念。
隨時隨地都可使用。
代碼資源:互動式編程挑戰
你正在尋找資源以準備 編程面試 嗎?
請查看我們的姐妹倉庫 互動式編程挑戰 ,其中包含了一個額外的抽認卡堆:
貢獻
從社區中學習。
歡迎提交 PR 提供幫助:
- 修復錯誤
- 完善章節
- 添加章節
一些還需要完善的內容放在了。
請查看貢獻指南。
系統設計主題的索引
各種系統設計主題的摘要,包括優點和缺點。 每一個主題都面臨著取舍和權衡 。
每個章節都包含著更的資源的鏈接。
- 系統設計主題:從這里開始
- 第一步:回顧可擴展性的視頻講座
- 第二步: 回顧可擴展性的文章
-
-
- CP - 一致性和分區容錯性
- AP - 可用性和分區容錯性 </ul> </li> </ul> </li>
- 反向代理(web 服務器)
-
- 用戶數據報協議(UDP)
- 遠程控制調用協議(RPC)
- 表述性狀態轉移(REST) </ul> </li> </ul>
- 你的經驗
- 你的技術背景
- 你面試的職位
- 你面試的公司
- 運氣
- 短期 - 以系統設計主題的 廣度 為目標。通過解決 一些 面試題來練習。
- 中期 - 以系統設計主題的 廣度 和 初級深度 為目標。通過解決 很多 面試題來練習。
- 長期 - 以系統設計主題的 廣度 和 高級深度 為目標。通過解決 大部分 面試題來聯系。
- 誰會使用它?
- 他們會怎樣使用它?
- 有多少用戶?
- 系統的作用是什么?
- 系統的輸入輸出分別是什么?
- 我們希望處理多少數據?
- 我們希望每秒鐘處理多少請求?
- 我們希望的讀寫比率?
- 畫出主要的組件和連接
- 證明你的想法
- 生成并儲存一個完整 url 的 hash
- MD5 和Base62
- Hash 碰撞
- SQL 還是 NoSQL
- 數據庫模型
- 將一個 hashed url 翻譯成完整的 url
- 數據庫查找 </ul> </li>
- API 和面向對象設計 </ul>
- 負載均衡
- 水平拓展
- 緩存
- 數據庫分片
- 使用信封的背面做計算
- 每個程序員都應該知道的延遲數
- 主題涵蓋
- 垂直擴展(Vertical scaling)
- 水平擴展(Horizontal scaling)
- 緩存
- 負載均衡
- 數據庫復制
- 數據庫分區
第二步:回顧可擴展性文章
- 主題涵蓋:
</li>
</ul>
接下來的步驟
接下來,我們將看看高階的權衡和取舍:
- 性能 與 可擴展性
- 延遲 與 吞吐量
- 可用性 與 一致性
記住每個方面都面臨取舍和權衡。
然后,我們將深入更具體的主題,如 DNS、CDN 和負載均衡器。
性能與可擴展性
如果服務 性能 的增長與資源的增加是成比例的,服務就是可擴展的。通常,提高性能意味著服務于更多的工作單元,另一方面,當數據集增長時,同樣也可以處理更大的工作單位。 1
另一個角度來看待性能與可擴展性:
- 如果你的系統有 性能 問題,對于單個用戶來說是緩慢的。
- 如果你的系統有 可擴展性 問題,單個用戶較快但在高負載下會變慢。
來源及延伸閱讀
延遲與吞吐量
延遲是執行操作或運算結果所花費的時間。
吞吐量是單位時間內(執行)此類操作或運算的數量。
通常,你應該以 可接受級延遲 下 最大化吞吐量 為目標。
來源及延伸閱讀
可用性與一致性
CAP 理論
在一個分布式計算系統中,只能同時滿足下列的兩點:
- 一致性 ─ 每次訪問都能獲得最新數據但可能會收到錯誤響應
- 可用性 ─ 每次訪問都能收到非錯響應,但不保證獲取到最新數據
- 分區容錯性 ─ 在任意分區網絡故障的情況下系統仍能繼續運行
網絡并不可靠,所以你應要支持分區容錯性,并需要在軟件可用性和一致性間做出取舍。
CP ─ 一致性和分區容錯性
等待分區節點的響應可能會導致延時錯誤。如果你的業務需求需要原子讀寫,CP 是一個不錯的選擇。
AP ─ 可用性與分區容錯性
響應節點上可用數據的最近版本可能并不是最新的。當分區解析完后,寫入(操作)可能需要一些時間來傳播。
如果業務需求允許,或當有外部故障時要求系統繼續運行,AP 是一個不錯的選擇。
來源及延伸閱讀
一致性模式
有同一份數據的多份副本,我們面臨著怎樣同步它們的選擇,以便讓客戶端有一致的顯示數據。回想中的一致性定義 ─ 每次訪問都能獲得最新數據但可能會收到錯誤響應
弱一致性
在寫入之后,訪問可能看到,也可能看不到(寫入數據)。盡力優化之讓其能訪問最新數據。
這種方式可以 memcached 等系統中看到。弱一致性在 VoIP,視頻聊天和實時多人游戲等真實用例中表現不錯。打個比方,如果你在通話中丟失信號幾秒鐘時間,當重新連接時你是聽不到這幾秒鐘所說的話的。
最終一致性
在寫入后,訪問最終能看到寫入數據(通常在數毫秒內)。數據被異步復制。
DNS 和 email 等系統使用的是此種方式。最終一致性在高可用性系統中效果不錯。
強一致性
在寫入后,訪問立即可見。數據被同步復制。
文件系統和關系型數據庫(RDBMS)中使用的是此種方式。強一致性在需要記錄的系統中運作良好。
來源及延伸閱讀
可用性模式
有兩種支持高可用性的模式: 故障切換(fail-over) 和 復制(replication) 。
故障切換
工作到備用切換(Active-passive)
關于工作到備用的故障切換流程是,工作服務器發送周期信號給待機中的備用服務器。如果周期信號中斷,備用服務器切換成工作服務器的 IP 地址并恢復服務。
宕機時間取決于備用服務器處于“熱”待機狀態還是需要從“冷”待機狀態進行啟動。只有工作服務器處理流量。
工作到備用的故障切換也被稱為主從切換。
雙工作切換(Active-active)
在雙工作切換中,雙方都在管控流量,在它們之間分散負載。
如果是外網服務器,DNS 將需要對兩方都了解。如果是內網服務器,應用程序邏輯將需要對兩方都了解。
雙工作切換也可以稱為主主切換。
缺陷:故障切換
- 故障切換需要添加額外硬件并增加復雜性。
- 如果新寫入數據在能被復制到備用系統之前,工作系統出現了故障,則有可能會丟失數據。
復制
主─從復制和主─主復制
這個主題進一步探討了部分:
域名系統
域名系統是把 www.example.com 等域名轉換成 IP 地址。
域名系統是分層次的,一些 DNS 服務器位于頂層。當查詢(域名) IP 時,路由或 ISP 提供連接 DNS 服務器的信息。較底層的 DNS 服務器緩存映射,它可能會因為 DNS 傳播延時而失效。DNS 結果可以緩存在瀏覽器或操作系統中一段時間,時間長短取決于存活時間 TTL。
- NS 記錄(域名服務) ─ 指定解析域名或子域名的 DNS 服務器。
- MX 記錄(郵件交換) ─ 指定接收信息的郵件服務器。
- A 記錄(地址) ─ 指定域名對應的 IP 地址記錄。
- CNAME(規范) ─ 一個域名映射到另一個域名或 CNAME 記錄( example.com 指向 www.example.com )或映射到一個 A 記錄。
CloudFlare 和Route 53 等平臺提供管理 DNS 的功能。某些 DNS 服務通過集中方式來路由流量:
- 加權輪詢調度
- 防止流量進入維護中的服務器
- 在不同大小集群間負載均衡
- A/B 測試
- 基于延遲路由
- 基于地理位置路由 </ul>
- 雖說緩存可以減輕 DNS 延遲,但連接 DNS 服務器還是帶來了輕微的延遲。
- 雖然它們通常由 政府,網絡服務提供商和大公司 管理,但 DNS 服務管理仍可能是復雜的。
- DNS 服務最近遭受DDoS 攻擊,阻止不知道 Twtter IP 地址的用戶訪問 Twiiter。
- DNS 架構.aspx)
- Wikipedia
- 關于 DNS 的文章
- 從靠近用戶的數據中心提供資源
- 通過 CDN 你的服務器不必真的處理請求
- CDN 成本可能因流量而異,可能在權衡之后你將不會使用 CDN。
- 如果在 TTL 過期之前更新內容,CDN 緩存內容可能會過時。
- CDN 需要更改靜態內容的 URL 地址以指向 CDN。
- 防止請求進入不好的服務器
- 防止資源過載
- 幫助消除單一的故障點
- SSL 終結 ─ 解密傳入的請求并加密服務器響應,這樣的話后端服務器就不必再執行這些潛在高消耗運算了。
- 不需要再每臺服務器上安裝X.509 證書。
- Session 留存 ─ 如果 Web 應用程序不追蹤會話,發出 cookie 并將特定客戶端的請求路由到同一實例。 </ul>
- 隨機
- 最少負載
- Session/cookie
- 輪詢調度或加權輪詢調度算法
- 水平擴展引入了復雜度并涉及服務器復制
- 服務器應該是無狀態的:它們也不該包含像 session 或資料圖片等與用戶關聯的數據。
- session 可以集中存儲在數據庫或持久化(Redis、Memcached)的數據存儲區中。
- 緩存和數據庫等下游服務器需要隨著上游服務器進行擴展,以處理更多的并發連接。 </ul>
- 如果沒有足夠的資源配置或配置錯誤,負載均衡器會變成一個性能瓶頸。
- 引入負載均衡器以幫助消除單點故障但導致了額外的復雜性。
- 單個負載均衡器會導致單點故障,但配置多個負載均衡器會進一步增加復雜性。
- 增加安全性 - 隱藏后端服務器的信息,屏蔽黑名單中的 IP,限制每個客戶端的連接數。
- 提高可擴展性和靈活性 - 客戶端只能看到反向代理服務器的 IP,這使你可以增減服務器或者修改它們的配置。
- 本地終結 SSL 會話 - 解密傳入請求,加密服務器響應,這樣后端服務器就不必完成這些潛在的高成本的操作。
- 免除了在每個服務器上安裝X.509 證書的需要
- 壓縮 - 壓縮服務器響應
- 緩存 - 直接返回命中的緩存結果
- 靜態內容 - 直接提供靜態內容
- HTML/CSS/JS
- 圖片
- 視頻
- 等等 </ul> </li> </ul>
- 當你有多個服務器時,部署負載均衡器非常有用。通常,負載均衡器將流量路由給一組功能相同的服務器上。
- 即使只有一臺 web 服務器或者應用服務器時,反向代理也有用,可以參考上一節介紹的好處。
- NGINX 和 HAProxy 等解決方案可以同時支持第七層反向代理和負載均衡。
- 引入反向代理會增加系統的復雜度。
- 單獨一個反向代理服務器仍可能發生單點故障,配置多臺反向代理服務器(如故障轉移)會進一步增加復雜度。
- 添加由多個松耦合服務組成的應用層,從架構、運營、流程等層面來講將非常不同(相對于單體系統)。
- 微服務會增加部署和運營的復雜度。
- 原子性 - 每個事務內部所有操作要么全部完成,要么全部不完成。
- 一致性 - 任何事務都使數據庫從一個有效的狀態轉換到另一個有效狀態。
- 隔離性 - 并發執行事務的結果與順序執行事務的結果相同。
- 持久性 - 事務提交后,對系統的影響是永久的。
- 將從庫提升為主庫需要額外的邏輯。
- 參考中,主從復制和主主復制 共同 的問題。
- 你需要添加負載均衡器或者在應用邏輯中做改動,來確定寫入哪一個數據庫。
- 多數主-主系統要么不能保證一致性(違反 ACID),要么因為同步產生了寫入延遲。
- 隨著更多寫入節點的加入和延遲的提高,如何解決沖突顯得越發重要。
- 參考中,主從復制和主主復制 共同 的問題。
- 如果主庫在將新寫入的數據復制到其他節點前掛掉,則有數據丟失的可能。
- 寫入會被重放到負責讀取操作的副本。副本可能因為過多寫操作阻塞住,導致讀取功能異常。
- 讀取從庫越多,需要復制的寫入數據就越多,導致更嚴重的復制延遲。
- 在某些數據庫系統中,寫入主庫的操作可以用多個線程并行寫入,但讀取副本只支持單線程順序地寫入。
- 復制意味著更多的硬件和額外的復雜度。
- 如果你的數據庫模式需要大量的功能和數據表,聯合的效率并不好。
- 你需要更新應用程序的邏輯來確定要讀取和寫入哪個數據庫。
- 用server link 從兩個庫聯結數據更復雜。
- 聯合需要更多的硬件和額外的復雜度。
- 你需要修改應用程序的邏輯來實現分片,這會帶來復雜的 SQL 查詢。
- 分片不合理可能導致數據負載不均衡。例如,被頻繁訪問的用戶數據會導致其所在分片的負載相對其他分片高。
- 再平衡會引入額外的復雜度。基于一致性哈希的分片算法可以減少這種情況。
- 聯結多個分片的數據操作更復雜。
- 分片需要更多的硬件和額外的復雜度。 </ul>
- 數據會冗余。
- 約束可以幫助冗余的信息副本保持同步,但這樣會增加數據庫設計的復雜度。
- 非規范化的數據庫在高寫入負載下性能可能比規范化的數據庫差。
- 基準測試 - 用ab 等工具模擬高負載情況。
- 性能分析 - 通過啟用如慢查詢日志等工具來輔助追蹤性能問題。
- 為了實現快速訪問,MySQL 在磁盤上用連續的塊存儲數據。
- 使用 CHAR 類型存儲固定長度的字段,不要用 VARCHAR 。
- CHAR 在快速、隨機訪問時效率很高。如果使用 VARCHAR ,如果你想讀取下一個字符串,不得不先讀取到當前字符串的末尾。
- 使用 TEXT 類型存儲大塊的文本,例如博客正文。 TEXT 還允許布爾搜索。使用 TEXT 字段需要在磁盤上存儲一個用于定位文本塊的指針。
- 使用 INT 類型存儲高達 2^32 或 40 億的較大數字。
- 使用 DECIMAL 類型存儲貨幣可以避免浮點數表示錯誤。
- 避免使用 BLOBS 存儲對象,存儲存放對象的位置。
- VARCHAR(255) 是以 8 位數字存儲的最大字符數,在某些關系型數據庫中,最大限度地利用字節。
- 在適用場景中設置 NOT NULL 約束來提高搜索性能。 </ul>
- 你正查詢( SELECT 、 GROUP BY 、 ORDER BY 、 JOIN )的列如果用了索引會更快。
- 索引通常表示為自平衡的B 樹,可以保持數據有序,并允許在對數時間內進行搜索,順序訪問,插入,刪除操作。
- 設置索引,會將數據存在內存中,占用了更多內存空間。
- 寫入操作會變慢,因為索引需要被更新。
- 加載大量數據時,禁用索引再加載數據,然后重建索引,這樣也許會更快。
- 有性能需要,可以進行非規范化。
- 將熱點數據拆分到單獨的數據表中,可以有助于緩存。
- 在某些情況下,查詢緩存可能會導致性能問題。
- 基本可用 - 系統保證可用性。
- 軟狀態 - 即使沒有輸入,系統狀態也可能隨著時間變化。
- 最終一致性 - 經過一段時間之后,系統最終會變一致,因為系統在此期間沒有收到任何輸入。
- 結構化數據
- 嚴格的模式
- 關系型數據
- 需要復雜的聯結操作
- 事務
- 清晰的擴展模式
- 既有資源更豐富:開發者、社區、代碼庫、工具等
- 通過索引進行查詢非常快
- 半結構化數據
- 動態或靈活的模式
- 非關系型數據
- 不需要復雜的聯結操作
- 存儲 TB (甚至 PB)級別的數據
- 高數據密集的工作負載
- IOPS 高吞吐量
- 埋點數據和日志數據
- 排行榜或者得分數據
- 臨時數據,如購物車
- 頻繁訪問的(“熱”)表
- 元數據/查找表
- 持久性選項
- 內置數據結構比如有序集合和列表
- 行級別
- 查詢級別
- 完整的可序列化對象
- 完全渲染的 HTML
- 很難用復雜的查詢刪除已緩存結果。
- 如果一條數據比如表中某條數據的一項被改變,則需要刪除所有可能包含已更改項的緩存結果。
- 如果對象的基礎數據已經更改了,那么從緩存中刪掉這個對象。
- 允許異步處理:workers 通過使用最新的緩存對象來組裝對象。
- 用戶會話
- 完全渲染的 Web 頁面
- 活動流
- 用戶圖數據
- 在緩存中查找記錄,如果所需數據不在緩存中
- 從數據庫中加載所需內容
- 將查找到的結果存儲到緩存中
- 返回所需內容
負載均衡器與反向代理
不利之處:反向代理
來源及延伸閱讀
應用層
將 Web 服務層與應用層(也被稱作平臺層)分離,可以獨立縮放和配置這兩層。添加新的 API 只需要添加應用服務器,而不必添加額外的 web 服務器。
單一職責原則提倡小型的,自治的服務共同合作。小團隊通過提供小型的服務,可以更激進地計劃增長。
應用層中的工作進程也有可以實現。
微服務
與此討論相關的話題是微服務,可以被描述為一系列可以獨立部署的小型的,模塊化服務。每個服務運行在一個獨立的線程中,通過明確定義的輕量級機制通訊,共同實現業務目標。 1
例如,Pinterest 可能有這些微服務: 用戶資料、關注者、Feed 流、搜索、照片上傳等。
服務發現
像 Consul ,Etcd 和Zookeeper 這樣的系統可以通過追蹤注冊名、地址、端口等信息來幫助服務互相發現對方。Health checks 可以幫助確認服務的完整性和是否經常使用一個路徑。Consul 和 Etcd 都有一個內建的用來存儲配置信息和其他的共享信息。
不利之處:應用層
來源及延伸閱讀
數據庫
關系型數據庫管理系統(RDBMS)
像 SQL 這樣的關系型數據庫是一系列以表的形式組織的數據項集合。
校對注:這里作者 SQL 可能指的是 MySQL
ACID用來描述關系型數據庫事務的特性。
關系型數據庫擴展包括許多技術: 主從復制 、 主主復制 、 聯合 、 分片 、 非規范化 和 SQL調優 。
主從復制
主庫同時負責讀取和寫入操作,并復制寫入到一個或多個從庫中,從庫只負責讀操作。樹狀形式的從庫再將寫入復制到更多的從庫中去。如果主庫離線,系統可以以只讀模式運行,直到某個從庫被提升為主庫或有新的主庫出現。
不利之處:主從復制
主主復制
兩個主庫都負責讀操作和寫操作,寫入操作時互相協調。如果其中一個主庫掛機,系統可以繼續讀取和寫入。
不利之處: 主主復制
不利之處:復制
來源及延伸閱讀
聯合
聯合(或按功能劃分)將數據庫按對應功能分割。例如,你可以有三個數據庫: 論壇 、 用戶 和 產品 ,而不僅是一個單體數據庫,從而減少每個數據庫的讀取和寫入流量,減少復制延遲。較小的數據庫意味著更多適合放入內存的數據,進而意味著更高的緩存命中幾率。沒有只能串行寫入的中心化主庫,你可以并行寫入,提高負載能力。
不利之處:聯合
來源及延伸閱讀:聯合
分片
分片將數據分配在不同的數據庫上,使得每個數據庫僅管理整個數據集的一個子集。以用戶數據庫為例,隨著用戶數量的增加,越來越多的分片會被添加到集群中。
類似的優點,分片可以減少讀取和寫入流量,減少復制并提高緩存命中率。也減少了索引,通常意味著查詢更快,性能更好。如果一個分片出問題,其他的仍能運行,你可以使用某種形式的冗余來防止數據丟失。類似聯合,沒有只能串行寫入的中心化主庫,你可以并行寫入,提高負載能力。
常見的做法是用戶姓氏的首字母或者用戶的地理位置來分隔用戶表。
不利之處:分片
來源及延伸閱讀:分片
非規范化
非規范化試圖以寫入性能為代價來換取讀取性能。在多個表中冗余數據副本,以避免高成本的聯結操作。一些關系型數據庫,比如PostgreSQl 和 Oracle 支持物化視圖,可以處理冗余信息存儲和保證冗余副本一致。
當數據使用諸如和等技術被分割,進一步提高了處理跨數據中心的聯結操作復雜度。非規范化可以規避這種復雜的聯結操作。
在多數系統中,讀取操作的頻率遠高于寫入操作,比例可達到 100:1,甚至 1000:1。需要復雜的數據庫聯結的讀取操作成本非常高,在磁盤操作上消耗了大量時間。
不利之處:非規范化
來源及延伸閱讀:非規范化
SQL 調優
SQL 調優是一個范圍很廣的話題,有很多相關的書可以作為參考。
利用 基準測試 和 性能分析 來模擬和發現系統瓶頸很重要。
基準測試和性能分析可能會指引你到以下優化方案。
改進模式
使用正確的索引
避免高成本的聯結操作
分割數據表
調優查詢緩存
來源及延伸閱讀
NoSQL
NoSQL 是 鍵-值數據庫 、 文檔型數據庫 、 列型數據庫 或 圖數據庫 的統稱。數據庫是非規范化的,表聯結大多在應用程序代碼中完成。大多數 NoSQL 無法實現真正符合 ACID 的事務,支持。
BASE通常被用于描述 NoSQL 數據庫的特性。相比,BASE 強調可用性超過一致性。
除了在之間做選擇,了解哪種類型的 NoSQL 數據庫最適合你的用例也是非常有幫助的。我們將在下一節中快速了解下 鍵-值存儲 、 文檔型存儲 、 列型存儲 和 圖存儲 數據庫。
鍵-值存儲
抽象模型:哈希表
鍵-值存儲通常可以實現 O(1) 時間讀寫,用內存或 SSD 存儲數據。數據存儲可以按字典順序維護鍵,從而實現鍵的高效檢索。鍵-值存儲可以用于存儲元數據。
鍵-值存儲性能很高,通常用于存儲簡單數據模型或頻繁修改的數據,如存放在內存中的緩存。鍵-值存儲提供的操作有限,如果需要更多操作,復雜度將轉嫁到應用程序層面。
鍵-值存儲是如文檔存儲,在某些情況下,甚至是圖存儲等更復雜的存儲系統的基礎。
來源及延伸閱讀
文檔類型存儲
抽象模型:將文檔作為值的鍵-值存儲
文檔類型存儲以文檔(XML、JSON、二進制文件等)為中心,文檔存儲了指定對象的全部信息。文檔存儲根據文檔自身的內部結構提供 API 或查詢語句來實現查詢。請注意,許多鍵-值存儲數據庫有用值存儲元數據的特性,這也模糊了這兩種存儲類型的界限。
基于底層實現,文檔可以根據集合、標簽、元數據或者文件夾組織。盡管不同文檔可以被組織在一起或者分成一組,但相互之間可能具有完全不同的字段。
MongoDB 和 CouchDB 等一些文檔類型存儲還提供了類似 SQL 語言的查詢語句來實現復雜查詢。DynamoDB 同時支持鍵-值存儲和文檔類型存儲。
文檔類型存儲具備高度的靈活性,常用于處理偶爾變化的數據。
來源及延伸閱讀:文檔類型存儲
列型存儲
抽象模型:嵌套的 ColumnFamily<RowKey, Columns<ColKey, Value, Timestamp>> 映射
類型存儲的基本數據單元是列(名/值對)。列可以在列族(類似于 SQL 的數據表)中被分組。超級列族再分組普通列族。你可以使用行鍵獨立訪問每一列,具有相同行鍵值的列組成一行。每個值都包含版本的時間戳用于解決版本沖突。
Google 發布了第一個列型存儲數據庫Bigtable,它影響了 Hadoop 生態系統中活躍的開源數據庫HBase 和 非死book 的Cassandra。像 BigTable,HBase 和 Cassandra 這樣的存儲系統將鍵以字母順序存儲,可以高效地讀取鍵列。
列型存儲具備高可用性和高可擴展性。通常被用于大數據相關存儲。
來源及延伸閱讀:列型存儲
圖數據庫
抽象模型: 圖
在圖數據庫中,一個節點對應一條記錄,一個弧對應兩個節點之間的關系。圖數據庫被優化用于表示外鍵繁多的復雜關系或多對多關系。
圖數據庫為存儲復雜關系的數據模型,如社交網絡,提供了很高的性能。它們相對較新,尚未廣泛應用,查找開發工具或者資源相對較難。許多圖只能通過訪問。
相關資源和延伸閱讀:圖
來源及延伸閱讀:NoSQL
SQL 還是 NoSQL
選取 SQL 的原因:
選取 NoSQL 的原因:
適合 NoSQL 的示例數據:
來源及延伸閱讀:SQL 或 NoSQL
緩存可以提高頁面加載速度,并可以減少服務器和數據庫的負載。在這個模型中,分發器先查看請求之前是否被響應過,如果有則將之前的結果直接返回,來省掉真正的處理。
數據庫分片均勻分布的讀取是最好的。但是熱門數據會讓讀取分布不均勻,這樣就會造成瓶頸,如果在數據庫前加個緩存,就會抹平不均勻的負載和突發流量對數據庫的影響。
客戶端緩存
緩存可以位于客戶端(操作系統或者瀏覽器),或者不同的緩存層。
CDN 緩存
也被視為一種緩存。
Web 服務器緩存
和緩存(比如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 通常用這種方式使用。
添加到緩存中的數據讀取速度很快。緩存模式也稱為延遲加載。只緩存所請求的數據,這避免了沒有被請求的數據占滿了緩存空間。
緩存的缺點:
- 請求的數據如果不在緩存中就需要經過三個步驟來獲取數據,這會導致明顯的延遲。
- 如果數據庫中的數據更新了會導致緩存中的數據過時。這個問題需要通過設置 TTL 強制更新緩存或者直寫模式來緩解這種情況。
- 當一個節點出現故障的時候,它將會被一個新的節點替代,這增加了延遲的時間。
直寫模式
應用使用緩存作為主要的數據存儲,將數據讀寫到緩存中,而緩存負責從數據庫中讀寫數據。
- 應用向緩存中添加/更新數據
- 緩存同步地寫入數據存儲
- 返回所需內容
應用代碼:
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)
由于存寫操作所以直寫模式整體是一種很慢的操作,但是讀取剛寫入的數據很快。相比讀取數據,用戶通常比較能接受更新數據時速度較慢。緩存中的數據不會過時。
直寫模式的缺點:
- 由于故障或者縮放而創建的新的節點,新的節點不會緩存,直到數據庫更新為止。緩存應用直寫模式可以緩解這個問題。
- 寫入的大多數數據可能永遠都不會被讀取,用 TTL 可以最小化這種情況的出現。
回寫模式
在回寫模式中,應用執行以下操作:
- 在緩存中增加或者更新條目
- 異步寫入數據,提高寫入性能。
回寫模式的缺點:
- 緩存可能在其內容成功存儲之前丟失數據。
- 執行直寫模式比緩存或者回寫模式更復雜。
刷新
你可以將緩存配置成在到期之前自動刷新最近訪問過的內容。
如果緩存可以準確預測將來可能請求哪些數據,那么刷新可能會導致延遲與讀取時間的降低。
刷新的缺點:
- 不能準確預測到未來需要用到的數據可能會導致性能不如不使用刷新。
緩存的缺點:
- 需要保持緩存和真實數據源之間的一致性,比如數據庫根據緩存無效。
- 需要改變應用程序比如增加 Redis 或者 memcached。
- 無效緩存是個難題,什么時候更新緩存是與之相關的復雜問題。
相關資源和延伸閱讀
異步
異步工作流有助于減少那些原本順序執行的請求時間。它們可以通過提前進行一些耗時的工作來幫助減少請求時間,比如定期匯總數據。
消息隊列
消息隊列接收,保留和傳遞消息。如果按順序執行操作太慢的話,你可以使用有以下工作流的消息隊列:
- 應用程序將作業發布到隊列,然后通知用戶作業狀態
- 一個 worker 從隊列中取出該作業,對其進行處理,然后顯示該作業完成
不去阻塞用戶操作,作業在后臺處理。在此期間,客戶端可能會進行一些處理使得看上去像是任務已經完成了。例如,如果要發送一條推文,推文可能會馬上出現在你的時間線上,但是可能需要一些時間才能將你的推文推送到你的所有關注者那里去。
Redis是一個令人滿意的簡單的消息代理,但是消息有可能會丟失。
RabbitMQ很受歡迎但是要求你適應「AMQP」協議并且管理你自己的節點。
Amazon SQS是被托管的,但可能具有高延遲,并且消息可能會被傳送兩次。
任務隊列
任務隊列接收任務及其相關數據,運行它們,然后傳遞其結果。 它們可以支持調度,并可用于在后臺運行計算密集型作業。
Celery支持調度,主要是用 Python 開發的。
背壓
如果隊列開始明顯增長,那么隊列大小可能會超過內存大小,導致高速緩存未命中,磁盤讀取,甚至性能更慢。背壓可以通過限制隊列大小來幫助我們,從而為隊列中的作業保持高吞吐率和良好的響應時間。一旦隊列填滿,客戶端將得到服務器忙活著 HTTP 503 狀態碼,以便稍后重試。客戶端可以在稍后時間重試該請求,也許是指數退避。
異步的缺點:
- 簡單的計算和實時工作流等用例可能更適用于同步操作,因為引入隊列可能會增加延遲和復雜性。
相關資源和延伸閱讀
通訊
超文本傳輸協議(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
傳輸控制協議(TCP)
TCP 是通過IP 網絡的面向連接的協議。 使用握手建立和斷開連接。 發送的所有數據包保證以原始順序到達目的地,用以下措施保證數據包不被損壞:
- 每個數據包的序列號和校驗碼。
- 確認包)和自動重傳
如果發送者沒有收到正確的響應,它將重新發送數據包。如果多次超時,連接就會斷開。TCP 實行流量控制)和擁塞控制。這些確保措施會導致延遲,而且通常導致傳輸效率比 UDP 低。
為了確保高吞吐量,Web 服務器可以保持大量的 TCP 連接,從而導致高內存使用。在 Web 服務器線程間擁有大量開放連接可能開銷巨大,消耗資源過多,也就是說,一個服務器。連接池 可以幫助除了在適用的情況下切換到 UDP。
TCP 對于需要高可靠性但時間緊迫的應用程序很有用。比如包括 Web 服務器,數據庫信息,SMTP,FTP 和 SSH。
以下情況使用 TCP 代替 UDP:
- 你需要數據完好無損。
- 你想對網絡吞吐量自動進行最佳評估。
用戶數據報協議(UDP)
UDP 是無連接的。數據報(類似于數據包)只在數據報級別有保證。數據報可能會無序的到達目的地,也有可能會遺失。UDP 不支持擁塞控制。雖然不如 TCP 那樣有保證,但 UDP 通常效率更高。
UDP 可以通過廣播將數據報發送至子網內的所有設備。這對DHCP 很有用,因為子網內的設備還沒有分配 IP 地址,而 IP 對于 TCP 是必須的。
UDP 可靠性更低但適合用在網絡電話、視頻聊天,流媒體和實時多人游戲上。
以下情況使用 UDP 代替 TCP:
- 你需要低延遲
- 相對于數據丟失更糟的是數據延遲
- 你想實現自己的錯誤校正方法
來源及延伸閱讀:TCP 與 UDP
遠程過程調用協議(RPC)
在 RPC 中,客戶端會去調用另一個地址空間(通常是一個遠程服務器)里的方法。調用代碼看起來就像是調用的是一個本地方法,客戶端和服務器交互的具體過程被抽象。遠程調用相對于本地調用一般較慢而且可靠性更差,因此區分兩者是有幫助的。熱門的 RPC 框架包括Protobuf、Thrift 和Avro。
RPC 是一個“請求-響應”協議:
- 客戶端程序 ── 調用客戶端存根程序。就像調用本地方法一樣,參數會被壓入棧中。
- 客戶端 stub 程序 ── 將請求過程的 id 和參數打包進請求信息中。
- 客戶端通信模塊 ── 將信息從客戶端發送至服務端。
- 服務端通信模塊 ── 將接受的包傳給服務端存根程序。
- 服務端 stub 程序 ── 將結果解包,依據過程 id 調用服務端方法并將參數傳遞過去。
RPC 調用示例:
GET /someoperation?data=anId
POST /anotheroperation { "data":"anId"; "anotherdata": "another value" }</pre>
RPC 專注于暴露方法。RPC 通常用于處理內部通訊的性能問題,這樣你可以手動處理本地調用以更好的適應你的情況。
當以下情況時選擇本地庫(也就是 SDK):
- 你知道你的目標平臺。
- 你想控制如何訪問你的“邏輯”。
- 你想對發生在你的庫中的錯誤進行控制。
- 性能和終端用戶體驗是你最關心的事。
遵循 REST 的 HTTP API 往往更適用于公共 API。
缺點:RPC
- RPC 客戶端與服務實現捆綁地很緊密。
- 一個新的 API 必須在每一個操作或者用例中定義。
- RPC 很難調試。
- 你可能沒辦法很方便的去修改現有的技術。舉個例子,如果你希望在Squid 這樣的緩存服務器上確保RPC 被正確緩存的話可能需要一些額外的努力了。
表述性狀態轉移(REST)
REST 是一種強制的客戶端/服務端架構設計模型,客戶端基于服務端管理的一系列資源操作。服務端提供修改或獲取資源的接口。所有的通信必須是無狀態和可緩存的。
RESTful 接口有四條規則:
- 標志資源(HTTP 里的 URI) ── 無論什么操作都使用同一個 URI。
- 表示的改變(HTTP 的動作) ── 使用動作, headers 和 body。
- 可自我描述的錯誤信息(HTTP 中的 status code) ── 使用狀態碼,不要重新造輪子。
- HATEOAS(HTTP 中的HTML 接口) ── 你的 web 服務器應該能夠通過瀏覽器訪問。
REST 請求的例子:
GET /someresources/anId
PUT /someresources/anId {"anotherdata": "another value"}</pre>
REST 關注于暴露數據。它減少了客戶端/服務端的耦合程度,經常用于公共 HTTP API 接口設計。REST 使用更通常與規范化的方法來通過 URI 暴露資源, 通過 header 來表述 并通過 GET、POST、PUT、DELETE 和 PATCH 這些動作來進行操作。因為無狀態的特性,REST 易于橫向擴展和隔離。
缺點:REST
- 由于 REST 將重點放在暴露數據,所以當資源不是自然組織的或者結構復雜的時候它可能無法很好的適應。舉個例子,返回過去一小時中與特定事件集匹配的更新記錄這種操作就很難表示為路徑。使用 REST,可能會使用 URI 路徑,查詢參數和可能的請求體來實現。
- REST 一般依賴幾個動作(GET、POST、PUT、DELETE 和 PATCH),但有時候僅僅這些沒法滿足你的需要。舉個例子,將過期的文檔移動到歸檔文件夾里去,這樣的操作可能沒法簡單的用上面這幾個 verbs 表達。
- 為了渲染單個頁面,獲取被嵌套在層級結構中的復雜資源需要客戶端,服務器之間多次往返通信。例如,獲取博客內容及其關聯評論。對于使用不確定網絡環境的移動應用來說,這些多次往返通信是非常麻煩的。
- 隨著時間的推移,更多的字段可能會被添加到 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 嗎
- 什么時候 RPC 比 REST 更合適?
- REST vs JSON-RPC
- 揭開 RPC 和 REST 的神秘面紗
- 使用 REST 的缺點是什么
- 破解系統設計面試
- Thrift
- 為什么在內部使用 REST 而不是 RPC
安全
這一部分需要更多內容。!
安全是一個寬泛的話題。除非你有相當的經驗、安全方面背景或者正在申請的職位要求安全知識,你不需要了解安全基礎知識以外的內容:
- 在運輸和等待過程中加密
- 對所有的用戶輸入和從用戶那里發來的參數進行處理以防止XSS 和SQL 注入。
- 使用參數化的查詢來防止 SQL 注入。
- 使用 最小權限原則 。
來源及延伸閱讀
附錄
一些時候你會被要求做出保守估計。比如,你可能需要估計從磁盤中生成 100 張圖片的縮略圖需要的時間或者一個數據結構需要多少的內存。 2 的次方表 和 每個開發者都需要知道的一些時間數據 (譯注:OSChina 上有這篇文章的譯文)都是一些很方便的參考資料。
2 的次方表
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</pre>
來源及延伸閱讀
每個程序員都應該知道的延遲數
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</pre>
基于上述數字的指標:
- 從磁盤以 30 MB/s 的速度順序讀取
- 以 100 MB/s 從 1 Gbps 的以太網順序讀取
- 從 SSD 以 1 GB/s 的速度讀取
- 以 4 GB/s 的速度從主存讀取
- 每秒能繞地球 6-7 圈
- 數據中心內每秒有 2,000 次往返
延遲數可視化
來源及延伸閱讀
其它的系統設計面試題
常見的系統設計面試問題,給出了如何解決的方案鏈接
問題 引用 設計類似于 Dropbox 的文件同步服務 油Tube.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設計 非死book 的新聞推薦方法 quora.com
quora.com
slideshare.net設計 非死book 的時間線系統 非死book.com
highscalability.com設計 非死book 的聊天系統 erlang-factory.com
非死book.com設計類似 非死book 的圖表搜索系統 非死book.com
非死book.com
非死book.com設計類似 CloudFlare 的內容傳遞網絡 cmu.edu 設計類似 推ter 的熱門話題系統 michael-noll.com
snikolov .wordpress.com設計一個隨機 ID 生成系統 blog.推ter.com
github.com返回一定時間段內次數前 k 高的請求 ucsb.edu
wpi.edu設計一個數據源于多個數據中心的服務系統 highscalability.com 設計一個多人網絡卡牌游戲 indieflashblog.com
buildnewgames.com設計一個垃圾回收系統 stuffwithstuff.com
washington.edu添加更多的系統設計問題 真實架構
關于現實中真實的系統是怎么設計的文章。
不要專注于以下文章的細節,專注于以下方面:
- 發現這些文章中的共同的原則、技術和模式。
- 學習每個組件解決哪些問題,什么情況下使用,什么情況下不適用
- 復習學過的文章
類型 系統 引用 Data processing MapReduce - Google的分布式數據處理 research.google.com Data processing Spark - Databricks 的分布式數據處理 slideshare.net Data processing Storm - 推ter 的分布式數據處理 slideshare.net Data store Bigtable - Google 的列式數據庫 harvard.edu Data store HBase - Bigtable 的開源實現 slideshare.net Data store Cassandra - 非死book 的列式數據庫 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 Google 的架構 Instagram 1400 萬用戶,達到兆級別的照片存儲
是什么在驅動 InstagramJustin.tv Justin.Tv 的直播廣播架構 非死book 非死book 的可擴展 memcached
TAO: 非死book 社交圖的分布式數據存儲
非死book 的圖片存儲Flickr Flickr 的架構 Mailbox 在 6 周內從 0 到 100 萬用戶 Pinterest 從零到每月數十億的瀏覽量
1800 萬訪問用戶,10 倍增長,12 名員工Playfish 月用戶量 5000 萬并在不斷增長 PlentyOfFish PlentyOfFish 的架構 Salesforce 他們每天如何處理 13 億筆交易 Stack Overflow Stack Overflow 的架構 TripAdvisor 40M 訪問者,200M 頁面瀏覽量,30TB 數據 Tumblr 每月 150 億的瀏覽量 推ter Making 推ter 10000 percent faster
每天使用 MySQL 存儲2.5億條 tweet
150M 活躍用戶,300K QPS,22 MB/S 的防火墻
可擴展時間表
推ter 的大小數據
推ter 的行為:規模超過 1 億用戶Uber Uber 如何擴展自己的實時化市場 WhatsApp 非死book 用 190 億美元購買 WhatsApp 的架構 油Tube 油Tube 的可擴展性
油Tube 的架構來自:https://juejin.im/post/58f45b058d6d8100648a69f0
缺陷:DNS
來源及延伸閱讀
內容分發網絡(CDN)
內容分發網絡(CDN)是一個全球性的代理服務器分布式網絡,它從靠近用戶的位置提供內容。通常,HTML/CSS/JS,圖片和視頻等靜態內容由 CDN 提供,雖然亞馬遜 CloudFront 等也支持動態內容。CDN 的 DNS 解析會告知客戶端連接哪臺服務器。
將內容存儲在 CDN 上可以從兩個方面來提供性能:
CDN 推送(push)
當你服務器上內容發生變動時,推送 CDN 接受新內容。直接推送給 CDN 并重寫 URL 地址以指向你的內容的 CDN 地址。你可以配置內容到期時間及何時更新。內容只有在更改或新增是才推送,流量最小化,但儲存最大化。
CDN 拉取(pull)
CDN 拉取是當第一個用戶請求該資源時,從服務器上拉取資源。你將內容留在自己的服務器上并重寫 URL 指向 CDN 地址。直到內容被緩存在 CDN 上為止,這樣請求只會更慢,
存活時間(TTL)決定緩存多久時間。CDN 拉取方式最小化 CDN 上的儲存空間,但如果過期文件并在實際更改之前被拉取,則會導致冗余的流量。
高流量站點使用 CDN 拉取效果不錯,因為只有最近請求的內容保存在 CDN 中,流量才能更平衡地分散。
缺陷:CDN
來源及延伸閱讀
負載均衡器
負載均衡器將傳入的請求分發到應用服務器和數據庫等計算資源。無論哪種情況,負載均衡器將從計算資源來的響應返回給恰當的客戶端。負載均衡器的效用在于:
負載均衡器可以通過硬件(昂貴)或 HAProxy 等軟件來實現。
增加的好處包括:
通常會設置采用或模式的多個負載均衡器,以免發生故障。
負載均衡器能基于多種方式來路由流量:
四層負載均衡
四層負載均衡根據監看的信息來決定如何分發請求。通常,這會涉及來源,目標 IP 地址和請求頭中的端口,但不包括數據包(報文)內容。四層負載均衡執行網絡地址轉換(NAT)來向上游服務器轉發網絡數據包。
七層負載均衡器
七層負載均衡器根據監控來決定怎樣分發請求。這會涉及請求頭的內容,消息和 cookie。七層負載均衡器終結網絡流量,讀取消息,做出負載均衡判定,然后傳送給特定服務器。比如,一個七層負載均衡器能直接將視頻流量連接到托管視頻的服務器,同時將更敏感的用戶賬單流量引導到安全性更強的服務器。
以損失靈活性為代價,四層負載均衡比七層負載均衡花費更少時間和計算資源,雖然這對現代商用硬件的性能影響甚微。
水平擴展
負載均衡器還能幫助水平擴展,提高性能和可用性。使用商業硬件的性價比更高,并且比在單臺硬件上 垂直擴展 更貴的硬件具有更高的可用性。相比招聘特定企業系統人才,招聘商業硬件方面的人才更加容易。
缺陷:水平擴展
缺陷:負載均衡器
來源及延伸閱讀
反向代理(web 服務器)
反向代理是一種可以集中地調用內部服務,并提供統一接口給公共客戶的 web 服務器。來自客戶端的請求先被反向代理服務器轉發到可響應請求的服務器,然后代理再把服務器的響應結果返回給客戶端。
帶來的好處包括:
第四步:度量設計
確認和處理瓶頸以及一些限制。舉例來說就是你需要下面的這些來完成拓展性的議題嗎?
論述可能的解決辦法和代價。每件事情需要取舍。可以使用來處理瓶頸。
信封背面的計算
你或許會被要求通過手算進行一些估算。涉及到的涉及到的是下面的這些資源:
相關資源和延伸閱讀
查看下面的鏈接以獲得我們期望的更好的想法:
系統設計的面試題和解答
普通的系統設計面試題和相關事例的論述,代碼和圖表。
與內容有關的解答在 solutions/ 文件夾中。
問題 設計 Pastebin.com (或者 Bit.ly) 解答 設計 推ter 時間線和搜索 (或者 非死book feed 和搜索) 解答 設計一個網頁爬蟲 解答 設計 Mint.com 解答 為一個社交網絡設計數據結構 解答 為搜索引擎設計一個 key-value 儲存 解答 通過分類特性設計 Amazon 的銷售排名 解答 在 AWS 上設計一個百萬用戶級別的系統 解答 添加一個系統設計問題 設計 Pastebin.com (或者 Bit.ly)
Imgur
設計 推ter 時間線和搜索 (或者 非死book feed 和搜索)
Imgur
設計一個網頁爬蟲
Imgur
設計 Mint.com
Imgur
為一個社交網絡設計數據結構
Imgur
為搜索引擎設計一個 key-value 儲存
Imgur
設計按類別分類的 Amazon 銷售排名
Imgur
在 AWS 上設計一個百萬用戶級別的系統
Imgur
面向對象設計的面試問題及解答
常見面向對象設計面試問題及實例討論,代碼和圖表演示。
與內容相關的解決方案在 solutions/ 文件夾中。
注:此節還在完善中
問題 設計 hash map 解決方案 設計 LRU 緩存 解決方案 設計一個呼叫中心 解決方案 設計一副牌 解決方案 設計一個停車場 解決方案 設計一個聊天服務 解決方案 設計一個環形數組 添加一個面向對象設計問題 系統設計主題:從這里開始
不熟悉系統設計?
首先,你需要對一般性原則有一個基本的認識,知道它們是什么,怎樣使用以及利弊。
第一步:回顧可擴展性(scalability)的視頻講座
學習指引
基于你面試的時間線(短、中、長)去復習那些推薦的主題。
Imgur
問:對于面試來說,我需要知道這里的所有知識點嗎?
答:不,如果只是為了準備面試的話,你并不需要知道所有的知識點。
在一場面試中你會被問到什么取決于下面這些因素:
那些有經驗的候選人通常會被期望了解更多的系統設計的知識。架構師或者團隊負責人則會被期望了解更多除了個人貢獻之外的知識。頂級的科技公司通常也會有一次或者更多的系統設計面試。
面試會很寬泛的展開并在幾個領域深入。這回幫助你了解一些關于系統設計的不同的主題。基于你的時間線,經驗,面試的職位和面試的公司對下面的指導做出適當的調整。
短期 中期 長期 閱讀以獲得一個關于系統如何工作的寬泛的認識 :+1: :+1: :+1: :+1: :+1: :+1: :+1: :+1: :+1: 復習如何處理一個系統設計面試題 :+1: :+1: :+1: 完成系統設計的面試題和解答 一些 很多 大部分 完成面向對象設計的面試題和解答 一些 很多 大部分 一些 很多 大部分 如何處理一個系統設計的面試題
系統設計面試是一個 開放式的對話 。他們期望你去主導這個對話。
你可以使用下面的步驟來指引討論。為了鞏固這個過程,請使用下面的步驟完成系統設計的面試題和解答這個章節。
第一步:描述使用場景,約束和假設
把所有需要的東西聚集在一起,審視問題。不停的提問,以至于我們可以明確使用場景和約束。討論假設。
第二步:創造一個高級的設計
使用所有重要的組件來描繪出一個高級的設計。
第三步:設計核心組件
對每一個核心組件進行詳細深入的分析。舉例來說,如果你被問到 設計一個 url 縮寫服務 ,開始討論:
-