大概有如下這些分類:
架構思維類
這類圖書通常從一些著名的架構理論講起,比如開閉原則、單一職責原則、依賴倒置原則、接口分離原則,等等。這種圖書的問題在於過度理論化。計算機科學歸根到底屬於工程技術類,實踐第一。
設計模式類
這一類圖書則一下子進入架構的局部細節,每個模式的來龍去脈並不容易理解。就算理解了某個具體的模式,但是也很難真正做到活學活用,不知道還是不知道。
分布式系統架構設計類
這類圖書通常從服務端的通用問題如一致性、高可用、高並發挑戰等話題講起,講大型業務系統面臨的挑戰。這些知識是非常有價值的,但無法延伸到通用業務架構,對大部分企業的架構實踐並不具備真正的指導意義。
重構類
這類圖書主要講怎麼把壞代碼一步步改進到好代碼。我認為這是最實用的一類。但在沒有優秀架構師主導的情況下,大部分公司的代碼不可避免地越變越壞,直到不堪重負最後不得不重寫。實際上,一個模塊最初的地基是最重要的,基本決定了這座大廈能夠撐多久,而重構更多側重於大廈建成之後,在服務於人的前提下怎麼去修修補補,延長生命。
什麼是架構思維
降低軟體複雜性,有幾種有效的方式:抽象、分治、復用和迭代,架構思維就是這幾個的集合
抽象思維
架構是為了滿足業務需求而存在,需要通常是一些文字性的描述、原型、UI設計圖,這些最終都會變成代碼讓機器執行。
我們必須先進行抽象,把需求變成計算機能識別的模型。
例如,抽象出各個用戶、訂單、內容等模型,劃清各個角色的責任以及對象交互的方式,隱藏很多無關緊要的細節。
分治思維
對複雜的系統分而治之,分解為小的、簡單的部分。
例如針對高並發場景,可以通過設計將流量分到不同的伺服器,避免單臺伺服器過載。
又例如,將一個1000行的函數,封裝為N個獨立的不超過50行的函數的調用
復用思維
復用是提升開發效率的最簡單有效的方法,通過對相同內容的抽象,讓其能復用於不同的場景。
很多新手程序喜歡複製粘貼代碼,如果需求變化,需要修改所有粘貼過的地方,開發效率低且難以維護,同時還浪費很多測試的精力。
迭代思維
好的架構都是演進過來,很少有架構是一步到位,我們需要保證不影響業務正常進度的基礎上,逐步迭代成最終合理的架構
需求讓技術變複雜。做一個博客和做一個谷歌,技術複雜度不是一個等級
人員讓技術複雜。軟體開發通過是一個團隊,成員水平不一樣,擅長的技術方向也不一樣,如何有效地協作是一個很大的考驗。
技術本身複雜。軟體項目使用的程式語言、框架、組件、資料庫、人工智慧、大數據等技術,都有學習成本
要讓軟體穩定運行也複雜。軟體開發完成上線後,充滿了各種不確定性,比如雲服務商可能宕機,比如明星發個微博可能造成系統癱瘓,又比如有人刪庫跑路了
正因為存在以上這幾個原因,我們需要架構設計去降低這些複雜性
降低開發成本。複雜系統拆分成多個相對簡單的服務,使得普通程式設計師都可以完成,降低了人力成本。
幫助組織人員高效協作。通過抽象和拆分,讓開發人員可以獨立完成功能模塊。
組織好各種技術。選擇合適的程式語言、協議、框架、組件等,最高效地實現需求目標
保障服務穩定運行。利用成熟的架構方案,例如負載均衡、限流、降級、熔斷等,保障服務的高可用。
如何做好架構設計架構設計要做好,需要大量的經驗積累,不過我們可以站在巨人的肩膀上,基於成熟的架構設計方案
改造,變成適合自己業務需求的架構
分析需求。對產品的需求進行抽象,分析用例,了解各種用戶角色和其使用的場景
選擇相似的成熟架構設計方案。例如微服務架構、前後端分離,還要根據團隊選擇合適的開發語言和框架。
自頂向下層層細化。好的實踐是自頂向下的,不過早陷入技術細節中,從整體到局部規劃,設計好部署架構、分層和分模塊、API設計、資料庫設計等。
驗證和優化架構設計方案。完整的架構設計方案,需要有多次的評審,充分收集各方面的反饋,反覆修改後確定,另外,還要考慮架構預期能滿足多長時間的業務增長,比如半年還是一年還是三年。
架構設計需要有高屋建瓴的眼光,不僅要有架構思想,還要有不同場景的架構實踐,更要學習前人實踐經驗的總結。架構設計是更像是一種內功,需要自我不斷地修煉,以便應對各種場景下的挑戰。
在系統架構和設計中,抽象幫助我們從大處著眼(get our mind about big picture),隱藏細節(temporarily hide details)。抽象能力的強弱,直接決定我們所能解決問題的複雜性和規模大小。
下圖是我們小時候玩的積木,我發現小時候喜歡玩搭積木的,並且搭得快和好的小朋友,一般抽象能力都比較強。
上圖右邊的積木城堡就是抽象,這個城堡如果你細看的話,它其實還是由若干個子模塊組成,這些模塊是子抽象單元,左邊的各種形狀的積木是細節。搭積木的時候,小朋友腦袋裡頭先有一個城堡的大圖(抽象),然後他 / 她大腦裡頭會有一個初步的子模塊分解(潛意識中完成),然用利用積木搭建每一個子模塊,最終拼裝出最後的城堡。這裡頭有一個自頂向下的分治設計,然後自底向上的組合過程,這個分治思維非常重要。
我認為軟體系統架構設計和小朋友搭積木無本質差異,只是解決的問題域和規模不同罷了。架構師先要在大腦中形成抽象概念,然後是子模塊分解,然後是依次實現子模塊,最後將子模塊拼裝組合起來,形成最後系統。所以我常說編程和架構設計就是搭積木,優秀的架構師受職業習慣影響,眼睛裡看到的世界都是模塊化拼裝組合式的。
分層思維除了抽象,分層也是我們應對和管理複雜性的基本思維武器,如下圖,為了構建一套複雜系統,我們把整個系統劃分成若干個層次,每一層專註解決某個領域的問題,並向上提供服務。有些層次是縱向的,它貫穿所有其它層次,稱為共享層。分層也可以認為是抽象的一種方式,將系統抽象分解成若干層次化的模塊。
分層架構的案例很多,一個中小型的 Spring Web 應用程式,我們一般會設計成三層架構:
TCP/IP 協議棧也是經典的分層架構,如下圖:
如果你關注人類文明演化史,你會發現今天的人類世界也是以分層方式一層層搭建和演化出來的。今天的網際網路系統可以認為是現代文明的一個層次,其上是基於網際網路的現代商業,其下是現代電子工業基礎設施,諸如此類。
分治思維分而治之 (divide and combine 或者 split and merge) 也是應對和管理複雜性的一般性方法,下圖展示一個分治的思維流程:
對於一個無法一次解決的大問題,我們會先把大問題分解成若干個子問題,如果子問題還無法直接解決,則繼續分解成子子問題,直到可以直接解決的程度,這個是分解 (divide) 的過程;然後將子子問題的解組合拼裝成子問題的解,再將子問題的解組合拼裝成原問題的解,這個是組合 (combine) 的過程。
23種設計模式1. 根據目的來分根據模式是用來完成什麼工作來劃分,這種方式可分為創建型模式、結構型模式和行為型模式 3 種。
創建型模式:用於描述「怎樣創建對象」,它的主要特點是「將對象的創建與使用分離」。GoF 中提供了單例、原型、工廠方法、抽象工廠、建造者等 5 種創建型模式。
結構型模式:用於描述如何將類或對象按某種布局組成更大的結構,GoF 中提供了代理、適配器、橋接、裝飾、外觀、享元、組合等 7 種結構型模式。
行為型模式:用於描述類或對象之間怎樣相互協作共同完成單個對象都無法單獨完成的任務,以及怎樣分配職責。GoF 中提供了模板方法、策略、命令、職責鏈、狀態、觀察者、中介者、迭代器、訪問者、備忘錄、解釋器等 11 種行為型模式。
2. 根據作用範圍來分根據模式是主要用於類上還是主要用於對象上來分,這種方式可分為類模式和對象模式兩種。
類模式:用於處理類與子類之間的關係,這些關係通過繼承來建立,是靜態的,在編譯時刻便確定下來了。GoF中的工廠方法、(類)適配器、模板方法、解釋器屬於該模式。
對象模式:用於處理對象之間的關係,這些關係可以通過組合或聚合來實現,在運行時刻是可以變化的,更具動態性。GoF 中除了以上 4 種,其他的都是對象模式。
下表介紹了這 23 種設計模式的分類。
前面說明了 GoF 的 23 種設計模式的分類,現在對各個模式的功能進行介紹。
單例(Singleton)模式:某個類只能生成一個實例,該類提供了一個全局訪問點供外部獲取該實例,其拓展是有限多例模式。
原型(Prototype)模式:將一個對象作為原型,通過對其進行複製而克隆出多個和原型類似的新實例。
工廠方法(Factory Method)模式:定義一個用於創建產品的接口,由子類決定生產什麼產品。
抽象工廠(AbstractFactory)模式:提供一個創建產品族的接口,其每個子類可以生產一系列相關的產品。
建造者(Builder)模式:將一個複雜對象分解成多個相對簡單的部分,然後根據不同需要分別創建它們,最後構建成該複雜對象。
代理(Proxy)模式:為某對象提供一種代理以控制對該對象的訪問。即客戶端通過代理間接地訪問該對象,從而限制、增強或修改該對象的一些特性。
適配器(Adapter)模式:將一個類的接口轉換成客戶希望的另外一個接口,使得原本由於接口不兼容而不能一起工作的那些類能一起工作。
橋接(Bridge)模式:將抽象與實現分離,使它們可以獨立變化。它是用組合關係代替繼承關係來實現,從而降低了抽象和實現這兩個可變維度的耦合度。
裝飾(Decorator)模式:動態的給對象增加一些職責,即增加其額外的功能。
外觀(Facade)模式:為多個複雜的子系統提供一個一致的接口,使這些子系統更加容易被訪問。
享元(Flyweight)模式:運用共享技術來有效地支持大量細粒度對象的復用。
組合(Composite)模式:將對象組合成樹狀層次結構,使用戶對單個對象和組合對象具有一致的訪問性。
模板方法(TemplateMethod)模式:定義一個操作中的算法骨架,而將算法的一些步驟延遲到子類中,使得子類可以不改變該算法結構的情況下重定義該算法的某些特定步驟。
策略(Strategy)模式:定義了一系列算法,並將每個算法封裝起來,使它們可以相互替換,且算法的改變不會影響使用算法的客戶。
命令(Command)模式:將一個請求封裝為一個對象,使發出請求的責任和執行請求的責任分割開。
職責鏈(Chain of Responsibility)模式:把請求從鏈中的一個對象傳到下一個對象,直到請求被響應為止。通過這種方式去除對象之間的耦合。
狀態(State)模式:允許一個對象在其內部狀態發生改變時改變其行為能力。
觀察者(Observer)模式:多個對象間存在一對多關係,當一個對象發生改變時,把這種改變通知給其他多個對象,從而影響其他對象的行為。
中介者(Mediator)模式:定義一個中介對象來簡化原有對象之間的交互關係,降低系統中對象間的耦合度,使原有對象之間不必相互了解。
迭代器(Iterator)模式:提供一種方法來順序訪問聚合對象中的一系列數據,而不暴露聚合對象的內部表示。
訪問者(Visitor)模式:在不改變集合元素的前提下,為一個集合中的每個元素提供多種訪問方式,即每個元素有多個訪問者對象訪問。
備忘錄(Memento)模式:在不破壞封裝性的前提下,獲取並保存一個對象的內部狀態,以便以後恢復它。
解釋器(Interpreter)模式:提供如何定義語言的文法,以及對語言句子的解釋方法,即解釋器。
必須指出,這 23 種設計模式不是孤立存在的,很多模式之間存在一定的關聯關係。
SOA 全稱是: Service Oriented Architecture,中文釋義為 「面向服務的架構」,它是一種設計理念,其中包含多個服務, 服務之間通過相互依賴最終提供一系列完整的功能。各個服務通常以獨立的形式部署運行,服務之間 通過網絡進行調用。架構圖如下:
跟 SOA 相提並論的還有一個 ESB(企業服務總線),簡單來說 ESB 就是一根管道,用來連接各個服務節點。ESB的存在是為了集成基於不同協議的不同服務,ESB 做了消息的轉化、解釋以及路由的工作,以此來讓不同的服務互聯互通; 隨著我們業務的越來越複雜,會發現服務越來越多,SOA架構下,它們的調用關係會變成如下形式:
很顯然,這樣不是我們所想要的,那這時候如果我們引入ESB的概念,項目調用就又會很清晰,如下:
系統間的集成 : 我們站在系統的角度來看,首先要解決各個系統間的通信問題,目的是將原先系統間散亂、無規劃的網狀結構,梳理成規整、可治理的星形結構,這步的實現往往需要引入一些概念和規範,比如 ESB、以及技術規範、服務管理規範; 這一步解決的核心問題是有序。
系統的服務化 : 我們站在功能的角度,需要把業務邏輯抽象成可復用、可組裝的服務,從而通過服務的編排實現業務的快速再生,目的是要把原先固有的業務功能抽象設計為通用的業務服務、實現業務邏輯的快速復用;這步要解決的核心問題是復用。
業務的服務化 : 我們站在企業的角度,要把企業職能抽象成可復用、可組裝的服務,就要把原先職能化的企業架構轉變為服務化的企業架構,以便進一步提升企業的對外服務的能力。「前面兩步都是從技術層面來解決系統調用、系統功能復用的問題」。而本步驟,則是以業務驅動把一個業務單元封裝成一項服務。要解決的核心問題是 高效。
微服務(Microservices)架構微服務架構和 SOA 架構非常類似,微服務只是的 SOA 升華,只不過微服務架構強調的是「業務需要徹底的組件化及服務化」,原單個業務系統會被拆分為多個可以獨立開發、設計、部署運行的小應用。這些小應用間通過服務化完成交互和集成。 組件表示的就是一個可以獨立更換和升級的單元,就像 PC 中的 CPU、內存、顯卡、硬碟一樣,獨立且可以更換升級而不影響其他單元。若我們把 PC 中的各個組件以服務的方式構建,那麼這臺 PC 只需要維護主板(可以理解為ESB)和一些必要的外部設備就可以。CPU、內存、硬碟等都是以組件方式提供服務,例如PC 需要調用 CPU 做計算處理,只需知道 CPU 這個組件的地址就可以了。
通過服務實現組件化
按業務能力來劃分服務和開發團隊
去中心化
基礎設施自動化(devops、自動化部署)
SOA 和微服務架構的差別微服務不再強調傳統SOA架構裡面比較重的ESB企業服務總線,同時以 SOA 的思想進入到單個業務系統內部實現真正的組件化。
Docker容器技術的出現,為微服務提供了非常便利的條件,比如更小的部署單元,每個服務可以通過類似 Spring Boot 或者 Node 等技術獨立運行。
還有一個點大家應該可以分析出來,SOA 注重的是系統集成,而微服務關注的是完全分離。
關於分布式一致性問題分布式系統中要解決的一個非常重要的問題就是數據的複製。在我們的日常開發經驗中,相信大多數開發人員都遇過這樣的問題 : 在做資料庫讀寫分離的場景中,假設客戶端 A 將系統中的一個值 V 由 V1 變更為 V2,但客戶端 B 無法立即讀取到 V 的最新值,而需要在一段時間之後才能讀取到。這再正常不過了,因為資料庫複製之間存是在延時的。
所謂分布式一致性的問題,就是指在分布式環境中引入數據複製機制後,不同數據節點之間可能會出現的、且無法依靠計算機應用程式自身解決的數據不一致的情況。簡單來說, 數據一致性就是指在對一個副本數據進行變更的時候,必須確保也能夠更新其它的副本,否則不同副本之間的數據將出現不一致。那麼如何去解決這個問題呢?按照正常的思路,我們可能會想到既然是網絡延遲導致的問題,那麼我們就把同步動作進行阻塞,用戶 2 在查詢的時候必須要等數據同步完成以後再來做。但這個方案會非常影響性能。如果同步的數據比較多或比較頻繁,那麼阻塞操作可能會導致整個新系統不可用。故我們沒有辦法找到一種既能夠滿足數據一致性、 又不影響系統性能的方案,所以就誕生了一個一致性的級別:
強一致性 : 這種一致性級別是最符合用戶直覺的,它要求系統寫入的是什麼,讀出來的也要是什麼,用戶體驗好,但實現起來往往對系統的性能影響較大。
弱一致性 : 這種一致性級別約束了系統在寫入成功後, 不保證立即可以讀到寫入的值,也不保證多久之後數據 能夠達到一致,但會儘可能地保證到某個時間級別(如秒級別)後,數據能夠達到一致狀態。
最終一致性 : 最終一致性其實是弱一致性的一個特例,系統會保證在一定時間內,能夠達到數據一致的狀態。這裡之所以將最終一致性單獨提出來,是因為它是弱一致性中非常推崇的一種一致性模型,也是業界在大型分布式系統的數據一致性上用的比較多的一致性模型。
微服務微信交流群添加微信,備註微服務進群交流
關注公眾號 soft張三丰