微服務設計原則
良好的微服務設計可以使後期的升級維護更加輕鬆,否則將會令人非常頭疼。
下面幾個設計原則強烈建議採用:
-
單一職責
-
高內聚
-
低耦合
-
隱藏內部實現
-
避免代碼庫共享
-
避免數據過度暴露
-
避免數據庫共享
-
最小化同步調用
-
最小化硬件共享
-
避免使用平臺獨特性技術
這三大原則是面向對象設計中的核心,同樣適用於微服務設計。
- 單一職責
每個微服務只應擔負一個職責。
比如一個微服務中有兩大功能:
-
商品分類管理
-
購物車
把它們放在一起看起來問題不大,因爲使用的技術相同、功能和數據上會有比較緊密的聯繫,在組織結構上,通常是由同一個開發小組負責。
但是,這會造成兩個功能有大量的代碼耦合。
時間長了之後,會帶來和單體架構一樣的問題,維護難、測試難、部署難 ……
所以,按照 “單一職責” 原則,應該分爲兩個微服務。
- 高內聚
關係緊密的行爲應放在一起。
比如有 2 個微服務:
-
訂單管理
-
訂單金額統計
“訂單金額統計” 服務需要請求 “訂單管理” 服務,以獲取所需數據。
例如價格、稅、服務費 ……
剛開始一切安好,但突然某一天上頭增加稅種了,需要更改新的計算規則。
那麼,訂單服務就要提供新的數據,金額統計服務也需要更改計算方式。
也就是說,每次變更基本都需要兩個服務一起改,是緊耦合的。
因爲訂單金額統計服務的邏輯只與訂單相關,所以應該併入訂單服務。
把緊密相關的行爲放在一起,實現高內聚。
- 低耦合
一個服務的變更不要影響其他服務。
此原則涉及到多個方面。
3.1 隱藏內部實現
比如上一節 “高內聚” 中,把金額統計服務併入了訂單管理服務,那麼,之前金額統計服務中的 “統計接口” 還需要對外暴露嗎?
現在已經是訂單服務的內部功能了,統計結果可以作爲訂單對象中的數據,所以無需對外暴露,防止誤操作和造成不必要的耦合關係。
3.2 避免共享代碼庫
共享代碼的確非常方便,但是會造成底層代碼關聯度太強。
對於以後的升級非常不便,例如某個服務想把語言版本升級,但共享庫使用的是低版本,其中某些用法在高版本中是過期的,這就很尷尬了。
想要完美的避免也是不現實的,只能儘量規避。
例如不共享,各服務重新造輪子,這樣服務之間就有邊界了。
但這個方式只適用於需要共享的庫是非常穩定的,不怎麼需要改了,否則的話相關服務都需要改。
再比如把共享庫的粒度縮小,避免形成功能特別全的大庫。
大庫必然導致被引用的範圍非常廣,影響面大。
如果粒度很小的話,涉及的服務也就少。
3.3 避免數據過度暴露
例如用戶服務有一個獲取用戶詳情的接口,返回用戶所有信息。
購物車服務獲取用戶信息時,就會拿到很全的數據,例如包括支付信息。
這是沒必要的,只需要返回用戶的基本屬性即可。
特殊的屬性應通過另外的接口提供。
過度暴露會增加服務間的耦合度。
3.4 避免數據庫共享
一個服務想獲取另一個服務的數據時,只應該通過接口,而不是直接從對方的數據庫中拿。
否則,這種數據層面的耦合會帶來噩夢。
3.5 最小化同步調用
比如訂單服務創建訂單的時候需要調用很多其他服務,例如用戶、商品、支付、庫存、物流。
直接同步調用各個服務的接口嗎?
不現實,如果其中有一個服務接口調用失敗,那麼創建訂單就失敗了。
最好使用事件驅動的異步調用。
同步調用會產生網絡的阻塞,對被調用服務的可用性要求極高,所以要慎重使用。
3.6 避免硬件基礎設施的共享
服務設計得很好,但如果硬件部署沒有規劃好,一樣非常痛苦。
例如兩個服務部署在一臺服務器上,服務 B 非常消耗資源,那麼服務 A 可能就沒法用了。
所以,不能忽略硬件這個關鍵點,要根據各個服務的特點做好均衡部署。
3.7 避免使用平臺特性技術
例如 Java RMI 做遠程調用不錯,但它是平臺特性,要求服務雙方都用一套技術,這種高耦合就不如平臺獨立的 REST 更自由了。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Q-XFyFRzemKgEdSCwa4eLg