微服務架構下的系統整合

danny_2018發表於2022-03-16

微服務架構相比單體架構而言的優點,可以列舉出很多:服務個體更小,更內聚,業務職責更清晰,可複用性更強,可以獨立部署釋出等等;從軟體開發的角度,靈活性和效率都會有很大的提升……

然而,微服務架構本質上是分散式系統架構,各個服務需要配合協同來完成產品的需求,業務資料的分散使得服務之間需要通過整合來完成協同工作,那麼問題來了,整合要採用什麼方式?要以什麼樣的原則進行?如何設計才能儘量保證不同服務之間資料的一致性?

一、混亂的現實

微服務架構下推薦使用REST作為服務間同步通訊的方式,對於非實時需求,可以基於事件來實現非同步協作。這個原則非常簡單,也非常容易實現,然而僅遵循這個原則卻很難讓我們沿著微服務的道路走下去。

一些號稱微服務架構的系統,最初服務拆分並無太大問題,但隨著邏輯的不斷擴充套件,跨服務資料交換場景的增加,這個簡單的原則就很難指引日常的決策,甚至引發了一些新的問題,舉幾個例子。

1.1 服務迴圈依賴

在一些場景下服務A依賴服務B,會呼叫服務B的API,而在另外一些場景下,服務B也需要服務A的資料,也會通過呼叫服務A的API來實現。單從實現層面來看,按需獲取資料,實現很方便,可以完成業務要達成的效果;但從長遠來看,兩個服務的耦合越來越緊,未來新增需求的實現成本會越來越高,成為技術債。

1.2 第三方系統整合實現到業務服務中

在一些業務場景下,當前產品需要的業務資料需要從幾個第三方系統獲取並進行整合甚至經過一些計算後才能使用,之前的一些專案在初期實現時,資料從第三方系統獲取後,經過處理直接寫入業務資料庫,就把整合的程式碼直接寫到業務服務中,看起來並沒有太大的問題,只要程式碼上做好隔離就好了。

但實際上,後期發生了一些棘手的問題讓我們不得不作出改變:

一些定時觸發的整合任務,每次只會在一個服務例項上執行,在執行期間可能會有大量的資料讀取、計算、更新、插入等操作,會短時大量佔用當前服務例項的資源,嚴重的情況下當前服務例項甚至無法正常對外提供服務。

相似的整合以同樣的方式整合到業務服務中,比如不同品牌的產品庫存會從多個第三方系統獲取,業務服務變的臃腫。

整合方的一些變化直接影響到業務服務,比如API的升級,這種改變必須要重新升級部署業務服務才能完成。

1.3 整合介面不冪等

無論在第三方系統整合和內部服務的呼叫過程中,介面不冪等都會造成資料不一致的問題。最典型的場景是服務A呼叫服務B的介面更新或寫入資料,服務B處理成功,但由於網路原因,服務A沒有收到服務B的響應,服務A重試呼叫介面,此時,服務B由於介面不冪等返回異常的響應,導致業務流程無法繼續下去。

理想是豐滿的,現實是骨感的,大多數的專案開始於滿懷激情的整潔架構的夢想,而開發工作並不像想象的那麼順利,伴隨著專案人員更替、交付壓力大、人員能力不足等等,架構開始逐漸走向大家不期望的方向,技術債臺高築,攻城獅們疲於奔命的追趕進度的同時,只能望債臺興嘆。

二、整合的原則

當問題發生時,架構師們都能第一時間站出來說這個設計太爛了,怎麼能做成這樣;事後諸葛是我們積累經驗的重要手段,從高築的技術債臺,從疲於救火的線上問題,從接了新需求確找不到合理方案……我們一直在總結經驗,為了避免再次摔倒在同一個地方,有哪些架構設計原則可以先行呢?

2.1 單向依賴

微服務拆分之初都定義了各個服務的上下游關係,我們可以定義上下游服務的依賴關係如下:

下游服務可以直接依賴上游服務,下游服務可以通過上游服務提供的API同步對上游服務的資料進行讀寫。

上游服務不依賴下游服務,上游服務資料狀態變化如果會對下游服務產生影響,可以通過釋出領域事件,由下游系統監聽事件作出對應的操作。

2.2 服務間僅冗餘引用資訊

微服務的各個領域實體之間存在著各式各樣的關係,當領域實體A依賴領域實體B的資訊時,通常需要在領域實體A中保留一部分領域實體B的副本資訊,那這份副本資訊中該包含哪些資訊呢?

舉個例子,領域實體A是訂單,領域實體B是客戶,客戶端每次查詢訂單資訊時,都要求同時查出客戶的姓名、性別和手機號碼,將這3個關鍵資訊冗餘在訂單的服務中就可以輕鬆滿足需求了,一切聽起來是那麼的美好。

然而,這3個關鍵資訊如果是可以變化的,那麼問題就來了,如果領域實體B中的資訊更新了,領域實體A中的資訊要不要更新,如果不更新會造成資料不一致,如果更新無端增加了複雜度,而很有可能因此而產生迴圈依賴。

因此,在無法確定資料變化的準確情況時,在副本中只保留引用資訊最保險,需要完整資訊時可以通過引用查詢相關資訊。

2.3 為第三方系統構建外觀服務

面對第三方系統整合,在系統整合過程中要考慮的更周全,一般情況下,我們無法控制第三方系統,一旦整合出現問題,需要溝通解決方案,排期開發,聯調測試等等,修復週期很長。

另一個問題是第三方系統通常採用的技術棧或整合方式可能和我們的系統完全不同。比如它可能是個非常老舊的系統,提供的介面是基於XML的SOAP;再比如它可能無法提供API,只能通過匯出檔案到某個SFTP或傳送郵件的方式進行整合……

為了讓第三方系統整合產生儘量小的影響,我們傾向於構建外觀服務來隱藏第三方系統實現的細節,通過外觀服務對第三方系統的功能進行包裝,提供和當前系統更加一致的整合方式。我們可以把外觀服務和第三方系統看做是一個整體,那麼第三方系統的整合對於當前系統內的服務來說,服務間的整合就可以和內部服務一樣處理。而對於第三方系統整合相關的細節內容被隔離在外觀服務中,第三方系統整合的變化,只需要修改外觀服務就可以了。

2.4 整合介面實現要考慮冪等性

這個原則非常簡單,但實現過程中非常容易被忽略,如果不在設計好的測試用例中,測試過程中也很難發現問題;多數情況下是到了線上,使用者使用的真實場景才會發現問題,這時已經產生了業務影響。

因此在涉及整合的介面中,要特別關注,業務上是否要求介面的冪等性,介面不冪等的情況下業務是否能夠正常的流轉。

2.5 契約測試

服務提供的介面通常不只有一個消費者,不同消費者關心的資訊往往可能也不一樣,隨著服務數量的增加,在沒有契約測試的情況下,很有可能發生因為一個需求修改了當前服務介面的實現,而影響其他已有功能。而往往這個問題直到全面迴歸的時候才能完全發現,甚至可能發生因改動範圍很小,迴歸不夠,在上線前也難以發現。

契約測試可以很好的解決這個問題,一方面測試前置,儘早提供反饋,另一方面也起到了架構守護的作用。

小結

系統整合是分散式系統中一定會談及的問題,而且是個大問題,因為它直接影響到當前系統的架構,一個微不足道的改動很可能就破壞了整個系統架構的原則,久而久之原則便形同虛設。

微服務架構也不例外,在缺少架構約束的情況下,只圖一時之快的實現往往會葬送了微服務的優勢,一個個微小的不合理改動會逐漸將整個架構大廈摧毀,所謂千里之堤,潰於蟻穴就是這個道理。

因此,在微服務架構設計之初,我們就要在團隊內建立一些原則,明確系統間整合需要遵守的一些規範,並且在實踐過程中定期review,必要時可以採用一些架構守護的輔助工具,來保護架構的健康度。

來自 “ 碼猿外 ”, 原文作者:麻廣廣;原文連結:https://mp.weixin.qq.com/s/7nUirt4qWBf5n2SjDHQ71w,如有侵權,請聯絡管理員刪除。

相關文章