作者 | 陳璐
在軟件開發(fā)領域,解耦這個詞相信大家都不陌生。在面向對象的語境下,我們會應用SOLID原則來構建高內聚低耦合的應用,實現(xiàn)模塊間的解耦;在復雜業(yè)務系統(tǒng)分析和建模時,會通過DDD的戰(zhàn)略和戰(zhàn)術設計幫助劃分領域并實現(xiàn)分布式系統(tǒng)中服務的解耦;當我們在組織大型敏捷開發(fā)團隊協(xié)同工作時,通過組建自治團隊來減少摩擦,從而實現(xiàn)團隊級別的解耦。
可以看到解耦無處不在,并且以此為目的投入,大家都會覺得是無比的政治正確,因為實現(xiàn)了解耦,我們的系統(tǒng)和應用就能更快速的擴展和演進,我們的團隊就能更順暢的合作并能更加快速的實現(xiàn)業(yè)務價值。
但是,當我們暫時拋開將得到的種種好處,思考要如何去實現(xiàn)它時,卻發(fā)現(xiàn)解耦這個詞表達的意義過于抽象和模糊,它既沒有描述最終的狀態(tài)也沒有提供實現(xiàn)的方法。那當我們談解耦的時候,具體內容是什么呢?
從字面上理解的所謂耦合,通常是指兩個或兩個以上的物體或者體系之間相互作用彼此影響,對應到軟件研發(fā)的以上場景,我們可以轉換成是指兩個或兩個以上的模塊/系統(tǒng)/團隊之間相互作用彼此影響。
在軟件需要解決的業(yè)務問題越來復雜的今天,單個的系統(tǒng)或者團隊很難在不依賴外部的情況下去實現(xiàn)業(yè)務目標,所以我理解的解耦并不是要消除耦合(彼此的作用和影響/依賴),而是指我們應該如何通過一定的方式和規(guī)則,來設計和管理以上提到的多個元素之間的依賴,降低耦合程度來使整個系統(tǒng)有序順暢的運轉。
本文將從服務間上下游的思維來討論如何在系統(tǒng)架構演進過程中,持續(xù)的保持服務間的松耦合,實現(xiàn)解耦的目標。
上下游思維定義
關于服務的上下游的定義,在DDD建模方法中,在確定了限界上下文(bounded context)后通過在上下文映射(context mapping)中使用上下游來表示上下文依賴的方向,其確定的依據(jù)是下游需要了解上游的領域知識實現(xiàn)業(yè)務,反之則不會。引申的含義就是上游的業(yè)務能力可以不用關心下游業(yè)務的存在,下游業(yè)務的開展依賴于上游提供的業(yè)務能力。下圖是限界上下文映射的一個例子:
圖片出處:https://www.oreilly.com/library/view/what-is-domain-driven/9781492057802/ch04.html
當我們基于以上的限界上下文設計領域模型并落地時,理想的情況是一個限界上下文對應一個應用服務。參考限界上下文的上下游關系,我把上下游思維定義為:上游服務不受下游服務的業(yè)務能力和可用性影響,反之則相反。我們會發(fā)現(xiàn)服務間的上下游關系比限界上下文中領域知識的上下游關系更復雜,而且上下游關系也會隨著集成方式的不同而變化。
基于上下游思維的耦合級別
基于服務上下游的思維,我把服務間依賴按以下維度進行耦合度分級:
- Level4: 領域知識互為上下游,業(yè)務可用性互為上下游
- Level3: 領域知識互為上下游, 業(yè)務可用性為單向上下游
- Level2: 領域知識為單向上下游,業(yè)務可用性互為上下游
- Level1: 領域知識為單向上下游,業(yè)務可用性為單向上下游
由于松耦合的業(yè)務模型利于松耦合的架構設計和業(yè)務的演進,同時松耦合的架構也利于組建松耦合的團隊結構。業(yè)務模型作為松耦合設計的基礎,以上的級別依據(jù)于這個思路定義的。
一種常見的Level4級別的情況是處于伙伴關系的上下文。比如訂單服務與派送服務之間通過同步API的方式進行通信,用戶訂單下單成功,通知派送服務,派送服務完成,更新訂單狀態(tài)。兩個服務通過API進行集成,服務需要相互知道對方的部分領域知識來完成API的調用以實現(xiàn)功能,同時業(yè)務的可用性互相關聯(lián),一方服務不可用,導致整個業(yè)務的中斷。
如果希望耦合度向level3演進,不希望服務的可用性產(chǎn)生直接的依賴,我們通常會通過引入消息中間件來進行解耦,服務間通過消息的方式進行集成,由于某些原因,它們都按照對方的領域模型定義的消息結構進行通信。那么這種情況下,服務間的領域知識相互耦合,業(yè)務可用性與具體的服務解耦,與消息中間件的可用性耦合,我們需要關注如何提高消息中間件的可用性來保障業(yè)務的高可用。
Level2級別的耦合度是建立在清晰的領域限界上下文邊界基礎上的,在上面包含的訂單服務和派送服務的業(yè)務中,派送服務作為上游在完成派送進行訂單更新這個業(yè)務時,它將派送更新的內容發(fā)送至訂單服務,訂單服務再解析派送更新內容并更新關聯(lián)的訂單狀態(tài)。那么在通過API的方式進行集成時,它們就處于領域知識的單向上下游和業(yè)務可用性互為上下游的狀態(tài)。具體構建服務時,根據(jù)團隊的組織結構和話語權的大小,又可以通過不同的方式來進行服務的集成。上游服務通常使用Open Host Service(OHS) / Published Language(PL)來提供業(yè)務能力,下游服務通過遵循上游的領域模型或者通過防腐層(Anti Cruption Layer - ACL)來完成領域模型的轉換。處于這個級別耦合度的上下游服務在開放主機接口不變的情況下可以獨立的進行迭代更新,否則需要通知下游服務評估影響并同步進行變更。
接下來可以更近一步,我們通常會通過引入消息中間件來對服務可用性依賴進行解耦來達到Level1的級別。處在這一級別的服務之間,由于有明確的上下文邊界和依賴關系,消息的結構也是上游系統(tǒng)來定義和維護的。那么如何基于業(yè)務場景來設計消息結構、集成規(guī)則,以及支持兼容性的消息格式更新方式是這一級別需要關注的問題。
四種耦合級別中,從高到低對團隊的業(yè)務建模和技術能力要求越來越高,也隨著耦合度的減輕對新業(yè)務的適應能力越來越強。
通過耦合級別來做出架構上的權衡
那么基于上述耦合級別的區(qū)分,如何在設計架構時進行取舍呢?
對于處在level4級別的系統(tǒng),如果服務都在團隊的職責范圍內,在保證高可用的前提下,在業(yè)務需求變化不頻繁的情況下,它暫時可以工作。如果系統(tǒng)由不同的團隊維護,或者需求變更頻繁的情況下,需要對業(yè)務模型進行優(yōu)化,通過定義清楚的上下游關系以達到level2級別以增強架構的適應性。
對于處在level3級別的系統(tǒng),由于領域知識的耦合,服務都需要有其它領域的知識來完成自己的業(yè)務能力,隨著服務的增多很容易退化成網(wǎng)狀的依賴,通常新的業(yè)務變更需要同時修改多個服務,異步的集成方式也增加了擴展和維護的難度。處在這一層級的系統(tǒng),優(yōu)先級還是通過優(yōu)化業(yè)務模型,定義清楚的上下游關系,至于是否需要使用異步的方式集成,需要綜合權衡業(yè)務的實時性和一致性要求來進行權衡是過度到level2還是level1。
對于處在level2級別的系統(tǒng),由于系統(tǒng)的上下游關系相對清晰,重點可以放在采用合適的方式來完成上下游系統(tǒng)的集成上以實現(xiàn)。一般上游系統(tǒng)通過OHS/PL在保證發(fā)布語言不變化的情況下,可以獨立的進行迭代更新;下游系統(tǒng)是通過跟隨或者添加防腐層來屏蔽上游業(yè)務模型變化帶來的影響,取決于業(yè)務模型變化的頻繁程度和添加新一層的成本。通常在綠地項目中,由于能從零開始進行業(yè)務建模和組建開發(fā)團隊,在統(tǒng)一業(yè)務語言和明確上下游團隊遵從關系的基礎上,采用新的服務構建技術和實踐,在上下游服務間同時使用OHS/PL和ACL會比較好的隔離相互之間的影響。上游服務專注于領域能力的迭代并通過OHS/PL來發(fā)布功能,下游服務通過ACL來隔離上游變化對自身領域模型的影響,同時也可以按需來使用上游提供的新的功能。
對于處在level1級別的系統(tǒng),在業(yè)務和技術上都具備了松耦合的基礎,但是此時需要警惕一種新的依賴產(chǎn)生。由于上游系統(tǒng)在消息格式的設計時沒有按照使用場景來設計,或者消息格式不能很好的在向前兼容的情況下進行更新,這帶來的后果是上游系統(tǒng)會成為下游新增業(yè)務的強依賴,因為任何的新需求可能需要上游系統(tǒng)定義新的消息格式來支持,上游系統(tǒng)會成為響應變化的瓶頸。如果服務在不同的團隊中進行維護,那么帶來的后果就是團隊間的沖突。在這個級別的依賴關系中,合理的消息模式以及兼容性設計是迭代演進的關鍵。
消息集成通常分為兩種風格Event Notification和Event-carried State Transfer,具體又可擴展為以下幾種模式:
- 消息體包含領域事件發(fā)生后領域模型的最新狀態(tài)和變更內容
- 消息體包含領域事件發(fā)生后領域模型的最新狀態(tài)
- 消息體包含領域事件發(fā)生后領域模型的變更內容
- 消息體只包含領域事件發(fā)生后領域模型的標識,需要消費者按需通過API來獲取相關信息
最后
以上是對于分布式系統(tǒng)中關于服務解耦的一些思考,希望上下游的思維能夠在做設計和系統(tǒng)開發(fā)時給大家提供對照參考,幫助我們實現(xiàn)松耦合的目標,同時也有助于減小團隊之間的依賴和摩擦。