微服務粒度難題:找到合適的微服務大小
序言
在微服務架構風格中,微服務通常設計遵循SRP(單一職責原則),作為一個獨立部署的軟件單元,專注于做一件事,并且做到極致。作為開發人員,我們常常傾向于在沒有考慮為什么的情況下盡可能地將服務做得小。這種關于什么是和不是什么是單一職責的主觀性是我們開發人員在服務粒度方面容易犯錯誤的地方。為了克服開發團隊在微服務尺寸上面臨的這種困境,理解粒度驅動因素至關重要。
粒度
在微服務中,我們有兩個概念——模塊化,涉及將系統分解成獨立部分,另一個是粒度,處理這些獨立部分的大小。
確定正確的粒度水平——服務的大小——是微服務架構中我們開發人員苦苦掙扎的眾多難點之一。粒度不是由服務中的類的數量或代碼行數來定義的,而是由服務的職責來定義的——因此,找到服務粒度的正確之道存在困惑。
服務的粒度分為兩種對立的力量——粒度解耦器和粒度整合器。
粒度解耦器
什么時候我應該考慮將一個服務拆分成更小的部分?
粒度整合器
什么時候我應該考慮將服務重新組合在一起?
粒度解耦器
由于我們生活在微服務和納米服務的時代,大多數開發團隊往往會錯誤地隨意拆分服務,而忽略隨之而來的后果。為了找到合適的大小,應對不同參數進行權衡分析,并在微服務的上下文和邊界上做出明智的決策。
粒度解耦驅動因素提供了何時將服務拆分成更小部分的指導和依據。讓我們看看這些驅動因素如何影響微服務的尺寸,以一個例子為例。
示例:考慮一個典型的通知服務,它執行三項操作:通過短信、電子郵件或郵寄信件通知客戶。
讓我們在解耦驅動因素上分析這個場景,并找到合適的尺寸。我們從:
服務范圍和功能
服務是否在做太多不相關的事情? 范圍和功能主要取決于兩個屬性——第一個是內聚性,指的是特定服務操作之間的相互關系的程度和方式。第二個是組件的總體大小,通常以職責數量、服務的入口點數量或兩者的綜合來衡量。 場景:觀察通知服務,有人可能會說將這個服務拆分成三個單獨的單一職責服務。但這是正確的做法嗎?答案是否定的!因為這個服務具有相對較強的內聚性,即所有這些功能都與一件事有關,即通知,并且具有一個單一的目的。所以,不需要拆分這個服務,它應該是一個服務執行三項操作。 接下來是:
代碼波動性
更改是否僅限于服務的一部分? 代碼波動性是源代碼更改的頻率。我們必須衡量服務中代碼更改的頻率,以合理解釋為什么要拆分服務。 場景:假設我們有以下服務功能的指標:
現在,如果我們依據更改的指標來看,郵寄信件通知部分的頻繁更改也需要測試短信和電子郵件部分,從而作為單一服務,這增加了測試范圍和部署風險。那么我們如何解決這個問題呢?
如果我們將這個服務拆分成兩個單獨的服務,電子通知和郵寄信件通知,那么頻繁的更改現在被隔離在自己的服務中,從而減少了測試范圍并降低了部署風險。
可擴展性和吞吐量
服務的部分是否需要不同的擴展能力? 不同服務功能的可擴展性需求可以客觀地測量,以量化服務是否應拆分。 場景:再次考慮通知服務示例,測量單個服務的可擴展性需求如下:
在這種情況下,作為一個單一服務,電子郵件和郵寄信件功能必須不必要地擴展以滿足短信通知的需求,從而影響成本和彈性(如MTTS,即平均啟動時間)。這完全合理地解釋了將通知服務拆分成獨立的服務——短信、電子郵件和信件,因為這樣可以讓每個服務獨立擴展以滿足它們不同的吞吐量需求。
容錯性
是否存在導致服務關鍵功能失敗的錯誤? 應用程序在特定領域內繼續運行的能力,即使發生了致命崩潰(如OOM)。 場景:考慮我們的通知服務場景,假設電子郵件功能繼續出現OOM錯誤并致命崩潰,整個整合服務將會癱瘓,包括短信和郵寄信件處理。 將這個單一的整合通知服務拆分成三個獨立的服務,為客戶通知領域提供了一定的容錯性。因此,電子郵件功能中的致命錯誤不會影響短信或郵寄信件。 進一步說明:現在,這里可能會出現一個問題,因為電子郵件功能頻繁崩潰,為什么不將短信和郵寄信件功能合并?這是一個有效的問題。如果我們記得,當我們討論代碼波動性場景時,我們將郵寄信件與電子郵件和短信分開,并將它們合并成一個——電子通知。如果我們在那里能這樣做,我們也可以在這里這樣做。那么,為什么不呢? 因為電子郵件和短信是相關的,它們都是電子通知方式。但在這里,短信和郵寄通知沒有任何共同之處可以將它們合并。換句話說,這里沒有內聚性。
注意:記住,如果一個服務難以命名,因為它在做多個不相關的事情,那么考慮拆分服務。第二,每當拆分服務時,無論驅動因素是什么,總是檢查是否可以與“剩余”功能形成強烈的內聚性。 所以,在這里將通知服務拆分成三個獨立的服務是有意義的。 最后一個驅動因素是:
可擴展性
服務是否總是在擴展以添加新功能? 隨著服務擴展,添加額外功能的能力。 場景:假設我們有新的功能要添加到通知服務——比如移動推送通知、桌面通知、社交媒體通知等。這些新功能當然可以添加到一個單一的整合通知服務中。然而,每次添加新通知時,整個通知服務都需要進行測試,并且所有通知功能都需要不必要地部署到生產環境中。
注意:僅當事先知道計劃和希望作為域的一部分的額外整合功能時,才應用此場景。
推薦實踐
1.如果一個服務難以命名,因為它在做多個不相關的事情,那么考慮拆分服務。2.每當拆分服務時,無論驅動因素是什么,總是檢查是否可以與“剩余”功能形成強烈的內聚性。3.根據業務能力而不是技術能力拆分服務。4.在設計微服務時使用單一職責原則(SRP),但要牢記強內聚性的全景。5.使用解耦驅動因素分析拆分服務的權衡。