分散式架構演進
原始分散式時代
這個時代(20世紀70年代末期到80年代初)的計算機計算能力非常有限(記憶體只有幾百K),所以科學家就尋求通過多臺計算機來完成一個功能,這個時代被稱為原始分散式時代。
但是這個時代對分散式系統的嘗試並沒有取得太大的成績。但也不是一無所成,這個時代的探索,出現了遠端呼叫,分散式檔案系統的雛型,為後續計算機學科的發展奠定了基礎。
IBM院士Kyle Brown事後曾評價道,“這次嘗試最大的收穫就是對RPC、DFS等概念的開創,以及得到了一個價值千金的教訓:某個功能能夠進行分散式,並不意味著它就應該進行分散式,強行追求透明的分散式操作,只會自尋苦果。”
無論是DCE還是稍後出現的CORBA,從結果來看,都不能稱得上成功,因為將一個系統拆分到不同的機器中執行,為解決這樣做帶來的服務發現、跟蹤、通訊、容錯、隔離、配置、傳輸、資料一致性和編碼複雜度等方面的問題所付出的代價已遠遠超過了分散式所取得的收益。
關於DCE的一點介紹
DCE是當時業界主流的計算機廠商一起參與,共同制訂了名為“分散式運算環境[2]”(Distributed Computing Environment,DCE)的分散式技術體系。
DCE包含一套相對完整的分散式服務元件規範與參考實現,譬如源自NCA(惠普公司)的遠端服務呼叫規範(Remote Procedure Call,RPC),當時被稱為DCE/RPC,它與後來Sun公司向網際網路工程任務組(Internet Engineering Task Force,IETF)提交的基於通用TCP/IP協議的遠端服務標準ONC RPC被認為是現代RPC的共同鼻祖。
源自AFS(卡內基梅隆大學提出)的分散式檔案系統(Distributed File System,DFS)規範,當時被稱為DCE/DFS;
源自Kerberos(麻省理工大學提出)的服務認證規範;
還有時間服務、命名與目錄服務,甚至現在程式中很常用的通用唯一識別符(Universally Unique Identifier,UUID)也是在DCE中發明出來的。
UNIX分散式設計哲學
保持介面與實現的簡單性,比系統的任何其他屬性,包括準確性、一致性和完整性,都來得更加重要。
但是基於那個時代的計算機技術,想要發展符合UNIX設計哲學的分散式技術不太可能,只能是一種美好的願景。
單體應用時代
20世紀80年代正是摩爾定律開始穩定發揮作用的黃金時期,微型計算機的效能以每兩年增長一倍的驚人速度提升,硬體算力束縛軟體規模的鏈條很快變得鬆動,資訊系統進入以單臺或少量幾臺計算機即可作為伺服器來支撐大型資訊系統運作的單體時代,且在很長的一段時間內,單體都將是軟體架構的絕對主流。
在很多書中都將單體架構作為一種反派角色出現,我甚至在面試過程中遇到過面試官在還沒了解專案需求的情況下就直接說你們這種單體架構是有問題的。其實沒有放之四海而皆準的架構,單體架構在某些情況下可能是最優選擇,單體架構更不應該被打上反派角色。
比如,對於小型系統,單臺機器就足以支撐其良好執行的系統,不僅易於開發、測試、部署,且由於系統中各個功能、模組、方法的呼叫過程都是程序內呼叫,不會發生程序間通訊(Inter-ProcessCommunication,IPC[1]),因此連執行效率也是最高的。
那些不顧需求現狀,為了微服務而微服務的開發者才是真正的“反派”。
單體系統的不足,必須在軟體的效能需求超過了單機、軟體的開發人員規模明顯超過了“2 Pizza Team”(6~12人)範疇的前提下才有討論的價值。
上面講到的是單體架構的優點,在網際網路時代(複雜系統),單體架構存在兩點明顯的缺點:
-
單機效能難以保證:一個應用中功能越堆越多,單臺機器已經難以滿足這些功能,摩爾定律失效讓堆硬體的做法變成了奢望;
-
缺乏自治隔離能力:比如說一部分的程式碼出現Bug可能會導致整個服務不可用,比如說一小個改動點需要上線,整個系統必須上線;
-
還有一個缺點就是單體架構需要技術棧統一,比如說所有功能模組都需要用Java語言來編寫。
單體架構的缺點不在於不可拆分、難以擴充套件(這種想法不完全正確)。
- 從縱向拆分角度來看,現代的單體應用都是會拆分成controller,service和dao層的,不存在不能拆分的說法;
- 從橫向拆分的角度,單體應用完全可以拆分成多個模組,每個模組負責不同的功能,但是最後還是打成一個包,執行在一個程序中;
- 從橫向擴充套件的角度,可以通過負載均衡機制同時部署若干個相同的單體系統副本,以達到分攤流量壓力的效果。
微服務取代單體系統成為潮流趨勢的根本原因,筆者認為最重要的原因是:單體系統很難相容“Phoenix”的特性。這種架構風格潛在的要求是希望系統的每一個部件、每一處程式碼都儘量可靠,儘量不出或少出缺陷。然而戰術層面再優秀,也很難彌補戰略層面的不足。單體系統靠高質量來保證高可靠性的思路,在小規模軟體上還能運作良好,但當系統規模越來越大時,交付一個可靠的單體系統就變得越來越具有挑戰性。如本書前言所說,正是隨著軟體架構演進,構建可靠系統的觀念從“追求儘量不出錯”到正視“出錯是必然”的轉變,才是微服務架構得以挑戰並逐步取代單體架構的底氣所在。
SOA架構時代
SOA架構,面向服務的架構。其包含的許多概念、思想都能在今天的微服務中找到對應的身影了,譬如服務之間的鬆散耦合、註冊、發現、治理,隔離、編排等。
SOA不能簡單視為一種架構風格,而是一套軟體設計的基礎平臺。
- 它擁有領導制定技術標準的組織Open CSA;
- 有清晰的軟體設計的指導原則,譬如服務的封裝性、自治、鬆耦合、可重用、可組合、無狀態,等等;
- 明確了採用SOAP作為遠端呼叫協議,依靠SOAP協議族(WSDL、UDDI和WS-*協議)來完成服務的釋出、發現和治理;
- 利用企業服務匯流排(Enterprise Service Bus,ESB)的訊息管道來實現各個子系統之間的互動,令各服務在ESB的排程下無須相互依賴就能相互通訊,實現了服務鬆耦合,也為以後進一步實施業務流程編排(Business Process Management,BPM)提供了基礎
- 使用服務資料物件(Service Data Object,SDO)來訪問和表示資料,使用服務元件架構(Service Component Architecture,SCA)來定義服務封裝的形式和服務執行的容器
但是SOA技術最終還是偃旗息鼓了,最主要的原因還是SOA基於SOAP協議,SOAP協議過於嚴格的規範定義帶來過度的複雜性,而構建在SOAP基礎之上的ESB、BPM、SCA、SDO等諸多上層建築,進一步加劇了這種複雜性。
SOA自誕生的那一天起,就已經註定只能是少數系統陽春白雪式的精緻奢侈品,它可以實現多個異構大型系統之間的複雜整合互動,卻很難作為一種具有廣泛普適性的軟體架構風格來推廣。SOA最終沒有獲得成功的致命傷與當年的EJB如出一轍,儘管有Sun和IBM等一眾巨頭在背後力挺,EJB仍然敗於以Spring、Hibernate為代表的“草根框架”,可見一旦脫離人民群眾,終究會淹沒在群眾的海洋之中,連資訊科技也不曾例外。
SAO的設計理念和簡單透明相悖甚遠。
微服務架構時代
微服務架構是一種通過多個小型服務組合來構建單個應用的架構風格,這些服務圍繞業務能力而非特定的技術標準來構建。各個服務可以採用不同的程式語言、不同的資料儲存技術,執行在不同的程序之中。服務採取輕量級的通訊機制和自動化的部署機制實現通訊與運維。
微服務的九個核心的業務與技術特徵:
-
圍繞業務能力構建
-
強終端弱管道
微服務和SOA的區別
從以上微服務的定義和特徵中,你應該可以明顯地感覺到微服務追求的是更加自由的架構風格,摒棄了幾乎所有SOA裡可以拋棄的約束和規定,提倡以“實踐標準”代替“規範標準”。
可是,如果沒有了統一的規範和約束,以前SOA解決的那些分散式服務的問題,不也就一下子都重新出現了嗎?的確如此,對於服務的註冊發現、跟蹤治理、負載均衡、故障隔離、認證授權、伸縮擴充套件、傳輸通訊、事務處理等問題,微服務中將不再有統一的解決方案。
即使只討論Java範圍內會使用到的微服務,僅一個服務間遠端呼叫問題,可以列入解決方案的候選清單的就有RMI(Sun/Oracle)、Thrift(Facebook)、Dubbo(阿里巴巴)、gRPC(Google)、Motan2(新浪)、Finagle(Twitter)、brpc(百度)、Arvo(Hadoop)、JSON-RPC、REST,等等;僅一個服務發現問題,可以選擇的就有Eureka(Netflix)、Consul(HashiCorp)、Nacos(阿里巴巴)、ZooKeeper(Apache)、etcd(CoreOS)、CoreDNS(CNCF),等等。其他領域也與此類似。
微服務所帶來的自由是一把雙刃開鋒的寶劍,當軟體架構者拿起這把寶劍,一刃指向SOA定下的複雜技術標準,將選擇的權力奪回的同一時刻,另外一刃也正朝著自己映出冷冷的寒光。
在微服務時代,軟體研發本身的複雜度確實有所降低。一個簡單服務,並不見得會同時面臨分散式中的所有問題,也就沒有必要背上SOA那百寶袋般沉重的技術包袱。需要解決什麼問題,就引入什麼工具;團隊熟悉什麼技術,就使用什麼框架。此外,像Spring Cloud這樣膠水式的全家桶工具集,通過一致的介面、宣告和配置,進一步遮蔽了源自具體工具、框架的複雜性,降低了在不同工具、框架之間切換的成本,所以,作為一個普通的服務開發者,作為一個“螺絲釘”式的程式設計師,微服務架構是友善的。
可是,微服務對架構者卻是滿滿的“惡意”,對架構能力的要求已提升到史無前例的程度。技術架構者的第一職責就是決策權衡,有利有弊才需要決策,有取有舍才需要權衡,如果架構者本身的知識面不足以覆蓋所需要決策的內容,不清楚其中利弊,恐怕將無可避免地陷入選擇困難症的境遇之中。微服務時代充滿著自由的氣息,微服務時代充斥著迷茫的選擇。
後微服務時代(雲原生時代)
容器技術給分散式架構提供了新思路。
當虛擬化的基礎設施從單個服務的容器擴充套件至由多個容器構成的服務叢集、通訊網路和儲存設施時,軟體與硬體的界限便已模糊。一旦虛擬化的硬體能夠跟上軟體的靈活性,那些與業務無關的技術性問題便有可能從軟體層面剝離,悄無聲息地在硬體基礎設施之內解決,讓軟體得以只專注業務,真正圍繞業務能力構建團隊與產品。
從軟體層面獨立應對分散式架構所帶來的各種問題,發展到應用程式碼與基礎設施軟、硬一體,合力應對架構問題,這個新的時代現在常被媒體冠以“雲原生”這個頗為抽象的名字加以宣傳。雲原生時代追求的目標與此前微服務時代追求的目標並沒有本質改變,都是在服務架構演進的歷史程序中,所以筆者更願意稱雲原生時代為“後微服務時代”。
Kubernetes成為容器戰爭勝利者標誌著後微服務時代的開啟,但Kubernetes仍然沒能完美解決全部的分散式問題。
微服務A呼叫了微服務B的兩個服務,稱為B1和B2,假設B1表現正常但B2出現了持續的500錯,那在達到一定閾值之後就應該對B2進行熔斷,以避免產生雪崩效應。如果僅在基礎設施層面來處理,這會遇到一個兩難問題,切斷A到B的網路通路會影響B1的正常呼叫,不切斷則會持續受B2的錯誤影響。
為了解決這一類問題,虛擬化的基礎設施很快完成了第二次進化,引入了今天被稱為“服務網格”(Service Mesh)的“邊車代理模式”(Sidecar Proxy)。
在虛擬化場景中的邊車指的是由系統自動在服務容器(通常是指Kubernetes的Pod)中注入一個通訊代理伺服器,相當於那個挎鬥,以類似網路安全裡中間人攻擊的方式進行流量劫持,在應用毫無感知的情況下,悄然接管應用所有對外通訊。這個代理除了實現正常的服務間通訊外(稱為資料平面通訊),還接收來自控制器的指令(稱為控制平面通訊),根據控制平面中的配置,對資料平面通訊的內容進行分析處理,以實現熔斷、認證、度量、監控、負載均衡等各種附加功能。通過邊車代理模式,便實現了既不需要在應用層面加入額外的處理程式碼,也提供了幾乎不亞於程式程式碼的精細管理能力。
無服務架構時代
無服務現在還沒有一個特別權威的“官方”定義,但它的概念並沒有前面提到的各種架構那麼複雜,本來無服務也是以“簡單”為主要賣點的,它只涉及兩塊內容:後端設施(Backend)和函式(Function)。
-
後端設施是指資料庫、訊息佇列、日誌、儲存等這類用於支撐業務邏輯執行,但本身無業務含義的技術元件,這些後端設施都執行在雲中,在無服務中將它們稱為“後端即服務”(Backend as a Service,BaaS)。
-
函式是指業務邏輯程式碼,這裡函式的概念與粒度都已經很接近於程式編碼角度的函數了,其區別是無服務中的函式執行在雲端,不必考慮算力問題,也不必考慮容量規劃(從技術角度可以不考慮,從計費的角度還是要掂量一下的),在無服務中將其稱為“函式即服務”(Function as a Service,FaaS)。
。。。
分散式和叢集的區別
叢集有哪些種類?