這樣設計系統,能拿下大廠的Offer嗎?
在技術面試中,系統設計能力被認為是非常重要的一項技能,尤其是對于中高級工程師或架構師職位。這種能力不僅僅是編寫代碼的技巧,還涉及到解決復雜問題、設計高效和可擴展系統的能力。那么,有沒有什么結構化的方法,可以幫助我們更好地設計系統?這篇文章,我們來聊一聊。
設計思想
在系統設計中,主要包括兩個關鍵階段:High Level(也稱宏觀設計)和 Low Level(也稱為詳細設計)。
宏觀設計是系統設計的初始階段,主要關注系統的整體架構和主要組件的設計。這一階段的目標是定義系統的結構、各組件之間的關系以及系統如何滿足高層次的需求。
微觀設計是系統設計的后續階段,關注具體組件和模塊的詳細實現。這一階段的目標是為每個組件和模塊提供詳細的設計,以指導開發工作。
為了更好地理解上面的設計思想,我們通過下面的 7個步驟來詳細說明系統設計過程。
第1步: 明確需求
不管是系統設計還是業務開發,都必須先弄清楚需求,這好比是回答別人的提問,如果連對方的問題都沒有弄清楚,后面所有的回答都可能是答非所問。
因此,系統設計的第一步是徹底理解需求,從實際工作經驗來看,需求主要包括 2種類型:功能性需求和非功能性需求。
1() 功能性需求
功能性需求是指系統需要執行的功能和行為,也就是系統實實在在要完成的功能,主要包含以下幾個點:
- 系統應支持哪些核心功能?
- 是否有任何特定功能比其他功能更重要?
- 誰將使用這個系統(客戶、技術團隊、客服等)?
- 用戶應該能夠在系統上執行哪些特定操作?
- 用戶將如何與系統交互(Web、移動應用程序、API 等)?
- 系統是否需要支持多語言?
- 系統必須處理哪些關鍵數據類型(文本、圖像、結構化數據等)?
- 系統是否需要集成外部系統或三方服務?
(2) 非功能性需求
非功能性需求是指系統的質量屬性和性能,主要包含以下幾個點:
- 系統的預期規模是多少?
- 系統預計要處理多少數據量?
- 系統的輸入和輸出是什么?
- 預期的讀寫比是多少?
- 系統是否可以停機,或者是否需要高可用性?
- 是否有任何特定的延遲要求?
- 數據一致性有多重要?為了可用性,是否可以容忍一些最終的一致性?
- 是否有任何特定的非功能性需求(性能、可伸縮性、可靠性)我們應該關注?
需求是整個系統設計的風向標,因此,明確需求是整個系統設計的第一步,盡早地弄清楚需求,可以幫助我們更好的把握系統走向。
第2步: 系統容量預估
在明確了需求之后,第二步要完成的事情就是評估系統的容量,只有知道了系統的容量,才能更好的預算開發周期、人力投入、服務器投入以及其他的投入,幫助我們更好地做好后期決策。
系統容量預估,一般需要評估以下幾個指標:
- 用戶數:預估系統需要支撐的總用戶數以及高峰時段的活躍用戶數和最大并發用戶數。
- 流量:計算日常TPS/QPS,以及峰值時的TPS/QPS。
- 存儲:需要存儲的數據類型(結構化、非結構化等),以及所需的存儲總量(及其增長率)。
- 內存:估計系統可能消耗的內存總量。
- 網絡:根據估計的流量和數據傳輸大小估算帶寬需求。
另外,系統設計還需要做未來增長和可伸縮性要求考慮,比如支持數據幾倍的增長以及支撐幾年的數據增長,以確保系統能夠處理隨時間推移而增加的負載。
第3步: 架構設計
在做完需求分析和容量評估這些準備工作之后,我們就可以進入真正的設計階段,系統設計(High-Level Design,HLD)是軟件開發生命周期中最重要也是最難的一個階段。
架構設計是一個宏觀上的考慮,旨在定義系統的總體結構和高層次的架構,在這個階段需要完成系統整體設計的藍圖,幫助開發團隊理解和規劃系統的各個組件及其相互關系,下圖是 Google的一張系統設計藍圖:
通過上述的藍圖可以看出:系統設計藍圖中包含以下主要組件:
- DNS:DNS是一種分布式系統,由許多域名服務器和域名解析器組成,提供名稱解析服務,將域名轉換成IP。
- 客戶端應用程序:表明用戶將如何與系統(Web 瀏覽器、移動應用程序、桌面應用程序等)進行交互。
- Web服務器:處理和響應客戶端請求的服務器。
- 負載均衡器:用于將流量均勻地分配到服務器以處理大量流量。
- 應用程序服務:實現系統核心功能的后端邏輯層。
- 數據庫:指定數據庫類型:SQL 與 NoSQL,并簡要說明原因。
- 緩存層:指定緩存(例如。Redis, Memcached),用于減少數據庫的負載。
- 消息隊列:如果系統需要使用異步通信。
- 外部服務:如果系統依賴于第三方 API(例如支付網關),請將其包括在內。
對于每個組件,一定要考慮權衡取舍,并說明為什么選擇特定的技術或架構,關于設計圖的繪制時,不要過度考慮小細節,而是更多站在宏觀的角度。小細節可以在每個組件的設計中去推敲。
第4步: 數據庫設計
絕大多數系統是需要和數據打交道的,因此數據庫的設計也就顯得至關重要,數據庫設計通常包括數據庫選型、數據建模、數據庫結構設計等。
(1) 數據庫選型
數據庫選型通常是根據業務場景以確定最合適的數據庫類型,主要包含以下幾個考慮因素:
- 選擇何種數據庫,關系型數據庫、NoSQL、ES等?還是多種數據庫的組合?
- 是否需要考慮數據結構、可伸縮性、性能、一致性和查詢模式等因素?
- 關系數據庫(例如,MySQL、PostgreSQL)適用于具有復雜關系和 ACID屬性的結構化數據。
- NoSQL數據庫(例如 MongoDB、Cassandra)適用于非結構化或半結構化數據、高可擴展性和最終一致性。
(2) 數據建模
數據建模通常會考慮以下因素:
- 確定系統需要存儲和管理的主要數據實體或對象(例如,用戶、產品、訂單)。
- 考慮實體之間的關系以及它們之間的交互方式。
- 確定與每個實體關聯的屬性或屬性(例如,用戶具有電子郵件、姓名、地址)。
- 標識每個實體的任何唯一標識符或主鍵。
- 考慮規范化技術,以確保數據完整性并最大程度地減少冗余。
(3) 數據庫結構設計
數據庫結構設計也就是真實的表結構設計,主要需要考慮以下因素:
- 根據所選的數據庫類型定義表、列、數據類型和關系。
- 設計主鍵、外鍵等。
- 設置合理的索引以優化查詢性能。
另外,在更宏觀的角度上,還需要考慮分庫分表,多活,災備等問題。
第5步: API設計和通信協議
API和通信協議,它定義了系統內不同的組件間該如何交互以及外部客戶端如何訪問系統的功能,通常會考慮以下因素:
(1) 明確 API要求
- 確定系統需要通過 API公開的主要功能和服務。
- 考慮與 API交互的客戶端類型(例如,Web、移動、第三方服務)。
- 確定每個 API的數據輸入、輸出和其他要求。
(2) 選擇 API類型
- 根據系統要求和客戶需求選擇合適的 API類型。
- RESTful API通常用于基于 Web 的系統,并為資源操作提供統一的接口。
- GraphQL API為客戶端查詢和檢索特定數據字段提供了一種靈活高效的方法。
- RPC(遠程過程調用)API適用于具有明確定義的過程或功能的系統。
(3) 定義API協議
- 根據系統的功能和數據模型設計清晰直觀的 API URL。
- 為API選擇適當的 HTTP方法(例如,GET、POST、PUT、DELETE)。
第6步:細化組件設計
在第3步中,我們分析了架構設計,但是它從宏觀上的一個把握,而不會過分的關注細節,因此在此步驟中,我們需要對第3步中的一些核心組件進行更詳細的設計,這里以 Java后端為例:
作為 Java后端,你需要了解自己業務的領域,比如金融,電商,財務,出行等,因為不同的領域會有一定的差異性。下面是組件細化的一些考慮點:
- 三高系統:是否是高可用,高性能,高擴展性的系統?如何保證三高?
- 微服務:是否采用微服務,微服務的框架是什么,SpringCloud還是 Dubbo?
- 架構:是否需要使用DDD架構?
- 數據庫:是否需要分庫分表?是否需要多活設計?是否需要定時備份?
- 負載均衡器:使用哪些負載均衡技術和算法?
- 緩存:使用什么緩存?緩存放在哪里?如何處理緩存失效?
- 單點故障:是否有單點問題?如何解決單點問題?
- 身份驗證/授權:如何安全地管理用戶訪問和權限?
- 速率限制:如何防止過度使用或濫用 API?
- 安全問題:如何保證系統安全和API安全?
以下都是在后端組件中需要考慮的問題,當然,我們需要根據自己所處的角色和領域,靈活的設計。
第7步: 解決關鍵問題
系統設計中難免會遇到一些技術難點以及核心挑戰,這些挑戰主要包括可擴展性和性能,以及可靠性、安全性和成本問題。為了更好地解決這些問題,下面也給出了具體的思路:
(1) 解決可擴展性和性能問題
- 增加節點進行水平擴展(橫向擴展)。
- 增加單個資源(例如 CPU、內存、存儲)的容量進行垂直擴展(縱向擴展)。
- 增加緩存以減少數據庫壓力并縮短響應時間。
- 優化數據結構和算法。
- 優化數據庫查詢和索引。
- 數據庫分區和分庫分片可提高查詢性能。
- 增加CDN,加速靜態資源訪問。
- 利用異步編程模型高效處理并發請求。
(2) 解決可靠性問題
可靠性是指系統即使在出現故障或錯誤的情況下也能正確和一致地運行的能力。以下是系統在可靠性上的一些關鍵考慮因素:
- 識別系統架構中的單點問題,通過集群等方式消除單點故障。
- 服務或者數據做多活,以防止區域故障或災難。
- 數據備份,確保數據可用性和持久性。
- 限流和降級機制,以防止級聯故障并保護系統免受過載影響。
- 加強監控和警報,以及時檢測故障、性能問題和異常情況。
總結
本文,我們詳細地分析了如何設計系統,從思想層面到具體實施過程,從宏觀角度到微觀落地,并且通過 7個步驟詳細地描述了系統設計的思路。
百種業務百種架構,在現實工作中,很難存在適用于任何業務的萬精油設計,但是思維方式卻是相通的,因此,實際業務中采用什么架構方式需要根據具體情況權衡。