第1篇 架構是什麼
系統 泛指由一群有關聯的個體組成,根據某種規則運作,能完成個別元件不能單獨完成的工作的群體(能力)。
從邏輯的角度拆分系統後,得到的單元就是“模塊”,從物理的角度拆分系統後,得到的單元就是“組件”。劃分模塊的主要目的是職責分離,劃分組件的主要目的是單元複用。
框架是組件規範,提供基礎功能的產品。軟件架構指軟件系統的“基礎結構”,創造這些基礎結構的準則,以及這些結構的描述。框架關注的是“規範”,架構關注的是“結構”。
軟件架構指軟件系統的頂層結構:
* 架構需要明確系統包含哪些“個體”,個體可以是 子系統、模塊、組件等。
* 架構需要明確個體的運作和協作的規則。
* 頂層結構可以更好地區分系統和子系統。
自話:軟件架構確定了系統中應該包含哪些個體,以及個體之間應該如何協作,以提供某種能力,從而實現系統的價值。
第2篇 架構設計的歷史背景
“模塊”“對象”“組件”本質上都是對達到一定規模的軟件進行拆分,區別只是在於隨著軟件的複雜度不斷增加,拆分的粒度越來越粗,拆分的層次越來越高。
第3篇 架構設計的目的
架構設計的主要目的是為了解決軟件系統複雜度帶來的問題。
架構設計首先要分析系統的複雜度所在,然後針對這些複雜度進行設計、制定方案。
軟件系統中高性能帶來的複雜度主要體現在兩方面,一方面是單臺計算機內部為了提高性能帶來的複雜度;另一方面是多臺計算機集群為了高性能帶來的複雜度。
系統的高可用本質都是通過“冗餘”來實現的,方法是增加機器。
高性能增加機器的目的在於“提升”處理性能,高可用增加機器的目的在於“冗餘”處理單元。
存儲高可用的難點不在於如何備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。
高可用狀態決策:無論是計算高可用還是存儲高可用,其基礎都是“狀態決策”,即系統能夠判斷當前狀態是正常還是異常,如果出現異常就要採取行動來保證高可用。
決策方式:
* 獨裁式:所有冗餘的個體向一個獨立的決策主體上報狀態信息,決策者進行決策。問題在於決策者本身是個單點。
* 協商式:兩個獨立的個體通過交流信息,然後根據規則進行決策,最常用的協商式決策就是主備決策。難點在於兩者的信息交換出現問題時如何決策。
* 民主式:指多個獨立的個體通過投票的方式來進行決策。缺陷是腦裂:原來統一的集群因為連接中斷,造成兩個獨立分隔的子集群,每個子集群單獨進行選舉,選出兩個決策者。解決方法是要求“投票節點數必須超過系統總結點數一半”。
可擴展性是指為了應對將來需求變化而提供的一種擴展能力。
設計具備良好可擴展性的系統,有兩個基本條件:正確預測變化、完美封裝變化。
預測變化的複雜性在於:不能每個設計點都考慮可擴展性、不能完全不考慮可擴展性、所有的預測都存在出錯的可能性。
設計具備良好可擴展性的系統,有兩個思考角度:從業務維度,對業務深入理解,對可預計的業務變化進行預測;從技術維度,利用擴展性好的技術,實現對變化的封裝。
應對變化的常見方案一是將“變化”封裝在一個“變化層”,將不變的部分封裝在一個獨立的“穩定層”。
方案二是提煉出一個“抽象層”和一個“實現層”,抽象是文檔的,實現可根據具體業務需要定製開發,加入新的功能時,只需要增加新的實現,無需修改抽象層。
舉例:設計一個支付網關對接不同的支付機構,為業務系統提供支付能力。每家支付機構的通信方式、請求/響應格式都是不一樣的,但基本參數都是四要素信息(銀行卡號、預留手機號、姓名、身份證號)、扣款金額等,扣款結果一般就是成功/失敗/等通知,因此可以抽象出統一的接口,對接不同支付機構的具體實現類實現這個接口、完成具體的調用邏輯,當要對接新的支付機構時只需要添加一個實現類;業務系統只需訪問這個統一的接口。
第7篇 複雜度來源:低成本、安全、規模
低成本是架構設計的一個約束條件,不是首要目標,本質上與高性能/高可用衝突。
從技術的角度,安全可以分為兩類:功能上的安全,架構上的安全。
功能安全一般與具體的編碼相關,是實現的問題。功能安全是一個逐步完善的過程,往往都是在問題出現之後才能針對性的提出解決方案,也無法預測下一個漏洞在哪裡。
架構安全是防止暴力破壞,典型的就是防止DDOS攻擊。
規模帶來複雜度的主要原因是“量變引起質變”,當數量超過一定的閾值後,複雜度會發生質的變化。
常見的規模帶來的複雜度有:功能越來越多,導致系統複雜度指數級上升;數據越來越多,系統複雜度發生質變;
第8篇 架構設計三原則
合適原則:合適優於業界領先。真正優秀的架構都是在企業當前人力、條件、業務等各種約束下設計出來的,能夠合理地將資源整合在一起併發揮出最大功效,並且能夠快速落地。
簡單優於複雜。(複雜分結構複雜和邏輯複雜)
對於建築,永恆是主題;對於軟件,變化才是主題。軟件架構需要根據業務發展不斷變化。
第10篇 架構設計流程1:識別複雜度
深入研究業務需求、通過“排查法”分析複雜度所在。
第11篇 架構設計流程2:設計備選方案
成熟的架構師需要對已經存在的技術非常熟悉,對已經經過驗證的架構模式爛熟於心,然後根據對業務的理解,挑選合適的架構模式進行組合,再對組合的方案進行修改和調整。
備選方案:數量3-5個最佳;差異要比較明顯;技術不要只侷限於已經熟悉的技術;不宜過於詳細而忽略整體設計;
第12篇 架構設計流程3:評估和選擇備選方案
列出需要關注的質量屬性點,分別從這些質量熟悉的維度去評估每個方案,再綜合挑選適合當時情況的最優方案。
常見的方案質量熟性有:性能、高可用、成本、複雜度、安全性、可擴展性、可伸縮性等。
第13篇 架構設計流程4:詳細方案設計
詳細方案設計就是將方案涉及的關鍵技術細節確定下來。
架構師不但要進行備選方案設計和選型,還需要對備選方案的關鍵細節有深入的理解。通過分步驟、分階段、分系統等方式,儘量降低方案複雜度,方案本身的複雜度越高,某個細節推翻整個方案的可能性就越高,適當降低複雜性,可以減少這種風險。如果方案本身很複雜,採取設計團隊的方式來進行設計,防止只有1-2個架構師可能出現思維盲點或經驗盲區。;
第14/15篇 高性能數據庫集群
讀寫分離
將讀壓力分散到集群中的多個節點,但沒有分散存儲壓力。主從複製延遲和分配機制會帶來複雜度。
解決主從延遲的常見方法:寫操作後的讀操作發送給數據庫主服務器(和業務強綁定,侵入業務代碼);讀從機失敗後再讀一次主機(大量二次讀會增加主機讀壓力);關鍵業務讀寫操作全部指向主機,非關鍵業務採用讀寫分離。
讀寫分離的實現一般有兩種方式:程序代碼封裝和中間件封裝。
程序代碼封裝指在代碼中抽象一個數據訪問層,實現讀寫操作分離和數據庫服務器連接的管理。
中間件封裝指的是獨立一套系統出來,實現讀寫操作分離和數據庫服務器連接的管理。
讀寫分離首先需要考慮業務的讀寫比例。
分庫分表
既分散了讀壓力,又分散了存儲壓力。
分庫帶來的問題:join 操作問題,事務問題,成本問題。
水平分表相比垂直分表,引入的複雜性主要體現在:
* 路由:用於確定某條數據所在切分後的子表。常見的路由算法有 範圍路由、hash路由、配置路由。
* join 操作
* count 操作
* order by 操作
第17篇 高性能緩存架構
緩存穿透
指緩存沒有發揮作用,業務系統雖然去緩存查詢數據,但緩存中沒有數據,業務系統需要再次去存儲系統查詢數據。
緩存雪崩
指當緩存失效(過期)後引起系統性能急劇下降的情況。
常見的解決方法有兩種:
* 更新鎖機制:對緩存更新操作進行加鎖保護,保證只有一個線程能夠進行緩存更新,未能獲取更新鎖的線程要麼等待鎖釋放後重新讀取緩存,要麼直接返回空值或者默認值。
* 後臺更新機制:緩存本身的有效期設置為永久,後臺線程定時更新緩存。
緩存熱點:對於特別熱點的數據,可以複製多份緩存副本,將請求分散到多個緩存服務器上,減輕緩存熱點導致的單臺服務器壓力。
閱讀更多 架構師的修煉之路 的文章