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