您的微服務是分散式整體嗎? -軟體工程日報

發表於2021-04-22

轉移到微服務不僅涉及將整體應用程式重新包裝到容器中。架構上存在根本差異,影響到從傳輸資料到故障恢復的所有方面。無法解決這些差異可能導致可擴充套件性受限,效能下降以及意外中斷。

您的團隊已決定將您的整體應用程式遷移到微服務架構。您已經對業務邏輯進行了模組化,對程式碼庫進行了容器化,允許開發人員進行多語言程式設計,用API呼叫替換了函式呼叫,構建了Kubernetes環境,並微調了部署策略。

但是在部署之後不久,您就開始注意到問題。服務需要很長時間才能啟動,故障從一個容器級聯到另一個容器,小的更改涉及重新部署整個應用程式。微服務不應該解決這些問題嗎?

如果聽起來很熟悉,那麼您可能已經陷入了常見的微服務反模式:分散式整體(distributed-monolith)。在本文中,我們將解釋什麼是分散式整體,為什麼要避免使用它們,以及如何使用Chaos Engineering來驗證您的應用程式是否屬於這種反模式。

 

分散式整體,為什麼不好?

分散式整體是一種像微服務一樣部署但卻像整體一樣構建的應用程式。它利用Kubernetes之類的平臺和分散式系統架構,但無法高效或可靠。

在單體/整體(monolith)架構中,整個應用程式被捆綁到一個單獨的程式包中,該程式包包含原始碼,庫,配置以及執行它所需的所有其他依賴性。整體結構並不是天生就不好,但是它們有侷限性:

  • 部署工件通常很大,啟動速度很慢,並且會佔用大量資源。
  • 更改應用程式的一部分意味著重新構建和重新部署整個應用程式,從而降低了開發人員的工作效率。
  • 水平縮放效率不高,因為整體不是為分散式系統設計的。

相比之下,微服務將應用程式分為離散的單元,這些單元具有明確定義的服務邊界,資源密集度較低且易於擴充套件。這些好處是以部署複雜性,管理開銷和可觀察性挑戰為代價的。除了管理我們的應用程式之外,我們現在還需要管理影像和容器,編排工具,網路和安全策略,分散式資料等等。

有了分散式整體,我們將擁有整體的繁重和靈活性,微服務的複雜性以及這兩種體系結構的諸多好處。我們的部署速度仍然很慢,可伸縮性很差,但是現在我們增加了運維的複雜性並消除了服務之間的隔離。

我們的工程師需要學習新的體系結構,採用新的工具並重建其應用程式,以適應動態變化的容器世界,從而增加了大量的時間和勞力。

您如何判斷微服務是否是分散式整體,這對您的開發策略和應用程式可靠性意味著什麼?我們將列出此反模式的一些共同特徵,並向您展示如何使用Chaos Engineering測試它們。

 

標誌#1:服務緊密耦合

耦合是指兩個功能之間的可分離程度。在整體中,由於共享公共程式碼庫並在相同的處理空間中執行,因此不同的功能緊密耦合。緊耦合可以採用不同的形式,例如:

  • 要求依賴項可用於完成任務(行為耦合)。
  • 要求與其他服務進行快速,低延遲的通訊(時間耦合)。
  • 由於更改單個服務(實現耦合)而必須更改多個服務。

考慮一個電子商務應用程式。當客戶檢視產品頁面時,我們需要:

  • 查詢資料庫以獲取有關產品的資訊。
  • 在後端處理該資訊。
  • 在頁面上渲染它。

使用傳統的整體應用程式,我們可能會建立一個模型檢視控制器(MVC)框架,以邏輯方式將後端邏輯(獲取產品詳細資訊)與前端邏輯(呈現網頁)分離。這是由兩個不同的開發團隊開發的兩個不同的功能,但是它們屬於相同的整體程式碼庫。如果不對另一個做同樣的事情,我們將無法部署或修改一個。

現在,讓我們將該應用程式重組為微服務。我們將建立兩個服務:一個用於前端,另一個用於產品目錄。我們將用API呼叫替換直接函式呼叫,並通過網路連線服務。一切看起來都不錯,並且執行良好,但是隨後我們的產品目錄服務崩潰了。前端發生了什麼?儘管出現故障,它是否仍可以繼續工作,還是我們的服務如此緊密地耦合在一起,以至於前端也出現故障?如果我們的後端團隊將修復程式部署到產品目錄,是否還需要將修復程式部署到前端?最重要的是,發生這種情況時,客戶會感到什麼?

 

如何測試緊密耦合?

在測試緊密耦合時,我們需要確定更改一項服務的狀態是否會影響另一項服務。為了說明這一點,我們將使用一個基於微服務的開源電子商務網站Online Boutique。Online Boutique使用十項獨特的服務來提供諸如前端,付款處理和購物車管理之類的功能。我們要驗證產品目錄是否與前端分離。

我們將使用企業SaaS Chaos Engineering平臺Gremlin進行此測試。我們將建立一個混亂的實驗,這是有意,主動地將傷害注入到工作系統中,以測試其恢復能力,以達到改善的目的。通過故意在產品目錄服務中造成故障並觀察對前端的影響,我們將瞭解這些服務的緊密耦合或鬆散耦合。

我們可以通過降低超時閾值或使我們的API呼叫非同步來採取快速措施來減輕耦合這種情況,以便我們的前端在響應使用者之前不必等待產品目錄。通過使用域驅動設計(DDD)在微服務之間設定明確定義的邊界(稱為有界上下文),我們可以降低與其他服務緊密耦合的風險。開始向微服務遷移之前,最好執行此步驟,但是即使開發已經開始,它仍然是有益的。

 

標誌#2:服務擴充套件不容易

假設我們的網站流量激增,我們需要水平擴充套件前端以處理增加的連線數。對於整體,我們需要部署整個應用程式及其所有依賴項的新例項。與真正的微服務相比,此過程不僅複雜而且容易失敗,而且花費的時間更長且使用資源的效率更低。

在測試分散式整體時,我們想知道應用程式擴充套件所需的時間,擴充套件時潛在的故障點以及對其他服務(特別是依賴項)的影響。

對於此測試,我們將使用Bitnami Helm圖表WordPress(一種開源CMS)部署到Kubernetes叢集。此圖表將WordPress應用程式部署在一個Pod中,並將其附加的MariaDB資料庫部署在另一個Pod中。

請注意新Pod的部署需要多長時間。將流量平衡到新Pod的負載後,請監視資料庫上的負載量。在需要擴充套件資料庫的地方,是否還有足夠大的增加?如果是這樣,您可能有一個分散式的整體。

無論您是否認為應用程式都是整體應用程式,這都是一個有用的實驗,因為它可以幫助您為流量高峰​​做準備,並在意外負載期間保持較高的吞吐量。

標誌#3:服務飽和

由於增加了網路呼叫的延遲,因此在分散式系統之間共享資料具有挑戰性。在整體中,資料幾乎可以在各個功能之間即時流動。但是在微服務中,服務之間的廣泛通訊將大大降低應用程式的吞吐量,可能會導致超時和其他意外故障。

例如,WordPress使用MySQL(或MariaDB)資料庫儲存資料,例如使用者帳戶,頁面內容,配置設定等。一次頁面載入可以生成多個MySQL查詢。因此,WordPress最好與低延遲(理想情況下是本地)資料庫連線一起使用,但這會在兩個服務之間造成時間依賴性。

在Kubernetes中,一種選擇是將WordPress和MySQL一起部署在同一Pod中。但這會建立一個Pod,該Pod具有多種功能,需要大量的系統資源,啟動時間更長,需要資料複製和同步,並且由應用程式和資料庫團隊共同擁有。換句話說,它是作為微服務打包的整體。

在我們的網路飽和或降級之前,將兩個服務聯網似乎不是問題。使用Chaos Engineering,我們可以看到這可能會對我們的應用程式產生影響。

為了減輕延遲的影響,請減少服務之間的往返網路呼叫次數。考慮使呼叫非同步,或使用訊息佇列(如Apache Kafka)將這些服務解耦。與緊密耦合一樣,這是為什麼要使用領域驅動設計將服務和資料拆分到不同域的另一個很好的例子。

 

 

相關文章