1. 程式人生 > 其它 >Java微服務分散式架構

Java微服務分散式架構

摘自《Java微服務分散式架構企業實戰》

1.傳統單體應用架構存在的問題
  一個完整的單體應用程式通常主要由三部分組成:客戶端使用者介面、模組和資料庫,如圖1.1所示。傳統單體應用的開發通常是建立一個由幾個業務模組組成的專案,然後將專案打成一個包,部署在伺服器上。

  專案的早期階段,這種方式很容易開發,部署也很方便。但是,隨著使用者需求的增加、專案功能的擴充套件,之前的小應用變得越來越臃腫、越來越複雜,這樣專案在開發和維護的過程中就會變得非常困難。一旦專案中出現了Bug,程式設計師在修改的過程中,會時刻處在“牽一髮而動全身”的窘境之中。在單體應用中,每個服務的更新或改變都會導致重新部署整個應用,可維護性、靈活性逐漸降低,維護成本越來越高,效率越來越低。因此,隨著業務需求的發展,傳統的單體應用很難滿足網際網路時代不斷變化的需求。

 2.分散式系統開發的複雜性

  分散式系統的重要特性就是面向服務,它把整個系統拆分成不同的服務,然後將這些服務放在不同的伺服器上、減少單體伺服器的壓力,提高併發量和效能。它是由一系列計算機伺服器組成的,由於使用者並不知道它背後的邏輯,所以感覺就像在訪問單個計算機一樣。分散式系統雖然在效能上表現很好,但是也帶來了系統的複雜性,例如分散式事務、分散式鎖、分散式Session、資料一致性等都是現在分散式系統中需要解決的難題。分散式系統設計遵循CAP定理、CAP是Consistency(一致性)、Availability(可用性)和Partition tolerance(分割槽容錯性)的簡稱。CAP定理認為,CAP的三種特性中,只能同時滿足其中兩種特性。1. 5節將詳細講解CAP定理。分散式系統如圖1. 2所示。

3.傳統架構與微服務架構的區別

  傳統架構與微服務架構在開發、部署方面都有很大的差別,接下來將通過對比兩者的缺點,及適用場景幫助更直觀地發現傳統架構與微服務架構的區別。

  1.傳統架構

  1)優點

    (1)結構簡單,容易理解。

    (2)請求響應快速。

    (3)部署簡單,所有功能一次打包。

  2)缺點

    (1)模組之間的耦合度太高,其中一個模組升級其他模組都得升級。

    (2)開發困難,開發人員可能需要排隊等待。

    (3)系統的擴充套件性差。

    (4)不能靈活地進行分散式部署。適用場景:傳統架構更適用於對請求響應時間要求較高的應用、簡單的小型應用程式以及初創型企業資源緊張的初期專案,能夠節省資源,減少成本。

  2.微服務架構

  1)優點

    (1)專案被拆分,降低了耦合度,服務自治。

    (2)專案被拆分成若干個子專案,不同的團隊負責不同的子專案,提高了開發效率。

    (3)技術多樣性,可以根據業務上下文選擇合適的語言、工具進行構建,每個服務可以使用不同的技術,服務之間互相獨立。

    (4)易於擴充套件。增加功能時再增加一個子專案,呼叫其他系統的介面即可。

    (5)服務間採用輕量級通訊機制相互溝通(通常是基於HTTP的Restful API).

    (6)可以靈活地進行分散式部署。

  2)缺點

    (1)系統之間互動需要使用遠端通訊,介面開發會增加工作量。

    (2)HTTP請求速度慢,通常一個操作可能涉及多個微服務的相互呼叫,如果為了完成一個操作而多次從服務端呼叫不同的微服務,HTTP請求的耗時可能會成為瓶頸。

    (3)測試工作更加困難,部署更加複雜。

    (4)微服務應用是分散式系統,由此會帶來固有的複雜性。適用場景:適用於業務功能需求大、專案版本更新迭代快的大型分散式專案的開發。

 4.網際網路架構的演變

  隨著網際網路的發展,應用程式的使用者越來越多,產生的資料量也越來越大,隨之而來的一系列併發問題和儲存問題,使傳統的架構很難滿足開發的需要。因此,網際網路架構也逐步發展成為多種形態滿足不同的開發需求。目前比較主流的架構都是時代進化的產物,由簡單的單體架構到水平分層架構、SOA架構,最後再到微服務架構的開發,這些架構都是順應時代而生的,也承擔著不同的使命。沒有最好的架構,只有最合適的架構,在選擇一種架構開發應用程式之前就應當仔細瞭解該架構與要開發程式的應用場景是否匹配。接下來分別講解這幾種架構的特點。

  1)單體架構

  在應用程式開發完成後,打一個歸檔包(例如war格式),其中包含了該應用中的所有功能。單體應用結構簡單、容易理解,可以方便快速地打包部署到Jetty或者Tomcat 容器中,一次部署完成即可執行整個應用程式,還可以通過執行多個副本和結合負載均衡器擴充套件應用。單體架構如圖1. 4所示。

  從圖1. 4可以看出,單體架構是一個整體,所有業務邏輯、資料管理都在一起進行,模組的邊界模糊,每修改一處程式碼就可能會面臨很多問題的出現,程式碼開發的效率低、擴充套件性差。

  2)水平分層架構

  在單體架構的基礎上,水平方向上將應用進行拆分為閘道器層、業務邏輯層、資料訪問層,每一層都是一個獨立的程序。常見的MVC模式的開發就是三層結構:模型(Model)、檢視(View)和控制器(Controller).每個層都各司其職,模型(Model)是應用程式中用於處理應用程式資料邏輯的部分,通常負責應用程式的持久化操作;檢視(View)是應用程式中處理資料顯示的部分;控制器(Controller)是應用程式中處理使用者互動的部分。MVC將不同職責劃分到獨立的層次,各個層的依賴關係比較靈活,降低了單體架構中的耦合性,應用程式業務擴充套件較單體架構更為方便。每一層都可以根據業務需求進行獨立部署,如圖1. 5所示。

圖1. 5可以看出,一個應用程式被拆分為閘道器層、業務邏輯層、資料訪問層。分層架構設計最核心的一點就是需要保證各層之間的差異足夠清晰,邊界足夠明顯,並且分層架構能較好地支撐系統擴充套件性。例如閘道器層只需要處理PC端的邏輯,業務邏輯層只需要處理相關的業務邏輯,這樣在擴充套件某層的時候,其他層不受影響。

  3)SOA架構SOA架構是面向服務的架構。它是在單體架構的基礎上按照業務功能進一步垂直拆分的,SOA的元件之間是鬆耦合的,每一個服務都包含了自己的業務邏輯和多個介面卡。把模組拆分,使用介面通訊,降低了模組之間的耦合度,把專案拆分成若干個子專案,不同的團隊負責不同的子專案,使開發效率得到了提升,增加功能時只需要再增加一個子專案,然後呼叫其他系統的介面就可以實現,還可以靈活地進行分散式部署。SOA架構通常以獨立的形式存在於作業系統程序中,各個服務之間通過網路通訊,如圖1. 6所示。

  圖1. 6按照業務功能將專案進行了拆分,每個服務都是一個獨立的單體,它們之間通過企業服務匯流排進行互動,每個服務也可以被其他服務呼叫,在水平方向上並沒有進行拆分。因此,SOA的拆分也不夠徹底,是粗粒度、鬆耦合、無狀態的服務。

  4)微服務架構微服務架構的出現解決了SOA架構拆分不徹底的問題。微服務首先根據不同的業務功能進行垂直拆分,然後對垂直拆分後的服務,在水平方向繼續進行拆分。一個單體專案被劃分為一個個網格的樣式,它解決了複雜問題,把可能會變得龐大的單體應用程式分解成一套服務。雖然功能數量不變,但是應用程式已經被分解成可管理的塊或者服務,每個服務都有一個明確的邊界。使用微服務架構模式,個體服務能夠被更快地開發,提高了開發效率,並且更容易理解與維護。微服務架構模式還可以實現每個微服務的獨立部署,不需要依賴其他微服務及其相關資源,如資料庫、記憶體快取系統等。例如,前端如果想更改頁面樣式或者變更實現的技術語言,在完成開發後,重新部署與該改動相關的服務即可,並不需要重新部署整個專案,微服務架構模式使得持續部署成為可能。微服務架構如圖1. 7所示。

 5.微服務架構常見的設計模式

  1 聚合器微服務設計模式
  聚合器微服務設計模式如圖1. 8所示。

  由圖1. 8可知,該模式通過負載均衡使用聚合器呼叫多個服務,其中每個服務都有自己的快取伺服器和資料庫。所有的服務的介面都會暴露出來,最終由聚合器把所有檢索到的資料進行處理和展示,也可以把檢索到的資料增加業務邏輯形成新的微服務。這也是一種最常見也最簡單的設計模式。

  2 代理微服務設計模式
  代理微服務設計模式如圖1. 9所示。該模式是由聚合模式變化而來,這種模式在客戶端不會聚合資料,但是會根據業務需求的差別來呼叫不同的微服務。代理可以委派請求,也可以進行資料轉換工作。每個微服務都有自己獨立的快取和資料庫系統,彼此獨立。

  3 鏈式微服務設計模式
  鏈式微服務設計模式如圖1. 10所示。由圖1. 10可知,當服務A接收到訊息後會與服務B進行通訊,然後服務B和服務C進行通訊。由於是鏈式的,因此服務之間的訊息是同步傳遞的,客戶端發出請求後,在沒收到響應的這段時間內一直是處於阻塞的,直到整個鏈條全部走完,響應給客戶端。因此,在使用鏈式微服務設計模式時應該特別注意服務鏈不應該太長,以免導致客戶端的長時間等待。

 

  4.分支微服務設計模式

  分支微服務設計模式如圖1.11所示。

  由圖1. 11可以看出,分支微服務設計模式更像是聚合器微服務設計模式和鏈式微服務設計模式的結合體。可以同時呼叫兩個服務鏈,當客戶端傳送請求呼叫服務A時,服務A需要呼叫服務B同時也需要呼叫服務C,而服務C需要呼叫服務D.因此,就形成了分支微服務模式。

  5.資料共享微服務設計模式
  資料共享微服務設計模式如圖1. 12所示。

  在使用了微服務架構以後,資料庫不再設定外來鍵,此時,就開始違反三大正規化,即SQL資料庫反規範。所以資料就會出現冗餘或重複,這是不可避免的。因此,在拆分重構階段的時候可以採取如圖1. 12所示的設計模式。
  6.非同步訊息傳遞微服務設計模式非同步訊息傳遞微服務設計模式如圖1. 13所示。

   由圖1. 13可以看出,服務A請求服務C時,服務C需要請求服務B,服務B也需要請求服務D,此時,雖然REST請求非常流行,但是同步會導致阻塞,因此,部分基於微服務的架構會採用訊息佇列來替代REST的請求/響應。在圖1. 13中服務C是生產者,服務B是消費者,服務C只負責生產,訊息佇列則負責持久化服務C生產的訊息,佇列會幫助快取訊息,直到消費服務開始工作。

 6.CAP原則

1 CAP的定義

  CAP原則又被稱為CAP定理,它是指在一個分散式系統中,Consistency(一致性)、Availability(可用性)和Partition Tolerance(分割槽容錯性)三者在實際開發的過程中並不能同時兼顧,如圖1. 14所示。

  圖1. 14中的Consistency(一致性)指的是使用者在執行完(一致性)更新操作成功並返回客戶端後,所有節點在同一時間能夠查詢到的資料會保持完全一致,這就是分散式的一致性。例如,在A、B節點下現有某條資料記錄值為M,使用者向A發起一個寫操作,將M更改為N,接下來,使用者在執行讀操作時,取資料時就會得到N,這就叫一致性。使用者還有可能向B節點發起讀操作,由於B節點中的值沒有發生變化,因此返回的還是M,A節點和B節點讀操作的結果不一致,這就不滿足一致性了,如圖1. 15所示。

  為了讓M節點中的資料也能變為N,就要在向A節點執行寫操作的時候,讓A節點向B節點發送一條訊息,要求B節點中的資料也改成N,如圖1. 16所示

  這樣,使用者向B節點發起讀操作,就也能得到N了。資料一致性的問題是分散式系統中需要正視的,對於客戶端來說,一致性指的是在進行併發訪問時已經更新過的資料如何才能夠準確地獲取到。從服務端來看,就是如何將更新能夠實時地同步到整個分散式系統中,確保資料最終的一致性。

  Availability(可用性)是指服務一直處於可用狀態,一旦接收到使用者的請求,伺服器就必須給出迴應,而且是正常響應時間。保持可用性主要就是為了使系統能夠反饋給使用者更好的體驗,不會出現如操作失敗、訪問連結超時等情況。

   Partition Tolerance(分割槽容錯性)指的是單臺伺服器或多臺伺服器出現問題後,其他正常服務的伺服器依然可以正常的提供服務。在分散式系統中如果遇到某些節點或網路分割槽故障的時候,仍然能夠繼續對外提供滿足一致性和可用性的服務。大多數分散式系統都會存在多個子網路,而每個子網路都可以稱為一個區(Partition).如B圖1. 7所示,A節點和B節點分別存在於兩臺跨區的伺服器上。A節M點向B節點發送一條訊息,B節點可能無法收到該訊息,這種情況是系統設計時必須要考慮到的。

  一般來說分割槽容錯是不可避免的,所以在CAP中情況中通常認為認P總是成立的。由於CAP定理可知,CAP三者之間不能同時兼顧,因此剩下的C和A必定無法同時做到。

  雖然面對的應用是一個分散式系統,但是分割槽容錯性要求整個系統在執行時更像是一個運轉正常的整體,當一個分散式系統中的一個機器宕機後,剩下的機器還能夠通過運轉滿足系統的需求,從而讓使用者在體驗上感覺並未受到影響。

2 CAP定理的證明

  接下來舉個簡單的小例子證明CAP不能夠同時滿足三個特性,並解釋其原因。假設現有兩臺伺服器,在其中的一臺伺服器中存放應用A和資料庫a,在另外一臺伺服器中存放應用B和資料庫b,保持這兩臺伺服器之間的連通性,模擬分散式系統的兩個子部分。在系統需要滿足Consistency(一致性)的情況下資料庫a和資料庫b中的資料是一樣的,此時無論使用者請求兩臺伺服器中的哪一臺,都能夠取得同樣的響應資料結果,如果兩臺伺服器中任意一臺機器宕機或網路原因導致不可用,也不會影響正常的運作。
  當用戶在應用A上發起向資料庫更改的請求後,資料庫a的資料將被更改,此時,用過分散式系統的同步更新的操作也會把資料庫b中的資料進行更新,那麼當用戶再通過應用B向資料庫發起查詢請求時,得到的響應結果也必然是更新後的資料。
  當然,這種情況是理想狀況下的正常運作,但是微服務系統開發免不了考慮網路傳輸過程中所發生的一切不可預測的因素。也就是說,當兩臺伺服器之間的通訊網路在不可用的情況下該如何處理,此時還能否同時滿足一致性和可用性原則。
  面對以上問題,可以想象到當兩臺伺服器之間的通訊斷開後,如果使用者嚮應用A傳送更新請求,緊接著資料庫a中的資料固然是改變了,但是資料庫b中的資料還是之前的資料,倘若再有使用者訪問應用B並向資料庫發起讀操作,那麼如果立即響應返回,得到的必然不是準確的資料。這時候就會面臨兩種選擇:要麼犧牲資料一致性,立刻返回更新前的資料庫b中的資料;要麼犧牲可用性,形成阻塞等待,直至網路恢復連線,等待資料庫b中的資料更新完成後再響應給使用者。
  通過以上例子可以看出,在滿足容錯性的情況下,一致性和可用性只能取其一,即分散式系統不能夠同時滿足CAP特性。因此,就需要在搭建系統時考慮如何進行取捨。

3.取捨策略

  因為分散式系統中CAP三特性只能同時滿足其中兩個特性,因此,取捨策略就會有三種:CA/CP/AP

  如果選擇CA策略,就是希望能夠使系統同事滿足一致性和可用性,這就意味著放棄了分割槽容錯性。在分散式系統中放棄P就不能夠部署子節點,放棄了系統的可擴充套件性,這種做法顯然已經違背了分散式系統設計的初衷,不能分割槽的系統也不能稱為分散式系如果選擇CP策略,就是希望能夠使系統同時滿足一致性和分割槽容錯性,這就意味著所統了。要的資料更新操作都必須在同步完成後才能響應返回結果,這就需要在網路發生故障或服務宕機時犧牲可用性,從而影響使用者的體驗。  

  如果選擇AP策略,就是希望能夠使系統同時滿足可用性和分割槽容錯性,放棄一致性。這樣一來每個節點中的資料只能為本地應用提供服務,導致全域性不一致性。典型的例子就是當雙11在網上搶購商品時,有時候開啟購物頁面發現還有商品庫存,但是當你立刻搶購時卻發現反饋提示商品已經售空,這就是因為在可用性的前提下,犧牲了資料一致性。這樣雖然或多或少會影響一些使用者的體驗,但不會造成嚴重阻塞。

4 CAP總結

  當今大多數的大型網際網路應用都是以叢集部署的,主機很多,部署也相對分散,隨著業務的發展,節點也會變得越來越多,因此,節點的故障和網路不可測導致故障都將會是分散式系統面臨的常態問題,所以大多數的應用也就只能在C和P中做取捨。還有一部分例如銀行等傳統行業,涉及的金錢資料是必須要保證資料一致性的,不能有絲毫偏差,因此,在搭建這種專案之前,首先考慮的是滿足一致性,如果出現網路故障,寧可停止繼續提供服務,也不能讓髒資料產生。總而言之,策略沒有好壞之分,一個好的系統是根據業務場景進行架構設計的,只有最合適的策略才是最好策略。