消滅微服務(wù)的壞味道 之 循環(huán)依賴

生命以負(fù)熵為生?!Χㄖ@《生命是什么》

歷史上有很多科學(xué)家為之背書的熵增定律,揭示了很多自然界現(xiàn)象的本質(zhì):任何孤立系統(tǒng),在沒有外力作用的情況下,其總混亂度(熵)會(huì)不斷增大。

軟件系統(tǒng)當(dāng)然也不例外,隨著軟件系統(tǒng)的功能不斷增加,系統(tǒng)的混亂度也在不斷增大。為了降低軟件系統(tǒng)混亂的速度,必須要對(duì)其施以外力(重構(gòu))。

重構(gòu)系統(tǒng)和重構(gòu)代碼一樣,首先要先識(shí)別系統(tǒng)的壞味道,Davide Taibi和Valentina Lenarduzzi在文章《On the Definition of Microservice Bad Smells》中定義了微服務(wù)的壞味道,今天我們就來聊聊如何消滅其中的一個(gè)壞味道——循環(huán)依賴。

循環(huán)依賴的危害

微服務(wù)之間的循環(huán)依賴類似于類之間的循環(huán)依賴,當(dāng)依賴關(guān)系形成了環(huán),會(huì)有很多危害:

首先是微服務(wù)之間的耦合性非常強(qiáng),服務(wù)很難做到獨(dú)立部署,這嚴(yán)重違反了微服務(wù)的初衷;這種情況往往是服務(wù)之間的調(diào)用沒有約束導(dǎo)致的,為了方便取到或更新數(shù)據(jù),服務(wù)之間可以隨意的調(diào)用,以”微服務(wù)“為設(shè)計(jì)目標(biāo)的系統(tǒng)會(huì)逐漸演變成一個(gè)分布式大單體,下圖舉例展示了三個(gè)服務(wù)之間的循環(huán)依賴關(guān)系:

循環(huán)依賴示例

另外循環(huán)依賴很可能導(dǎo)致一些循環(huán)調(diào)用或并發(fā)問題,造成一些復(fù)雜難以定位的問題,以上圖中訂單和客戶的循環(huán)依賴為例:

訂單服務(wù)依賴客戶服務(wù)來獲取客戶信息,為了滿足可以根據(jù)客戶姓名查詢訂單的需求,除了記錄客戶的ID,同時(shí)將客戶的姓名冗余到訂單的數(shù)據(jù)中。當(dāng)客戶信息更新時(shí),為保證訂單上數(shù)據(jù)的準(zhǔn)確,客戶服務(wù)會(huì)調(diào)用訂單服務(wù)更新訂單上的客戶信息。

循環(huán)依賴讓事情變得復(fù)雜,不同的實(shí)現(xiàn)會(huì)有不同的問題表現(xiàn),我們來看這樣的場(chǎng)景:當(dāng)訂單狀態(tài)變化時(shí),客戶的狀態(tài)也要跟著變化,訂單服務(wù)會(huì)更新客戶的狀態(tài),而客戶信息的變化反過來需要更新訂單上冗余的客戶信息;假設(shè)在訂單上加了樂觀鎖,同一時(shí)刻的兩次訂單更新因?yàn)闃酚^鎖會(huì)有一個(gè)失敗,排查問題過程中通過現(xiàn)象會(huì)優(yōu)先考慮并發(fā)的問題,然而真相確恰恰相反,參見下圖時(shí)序:


循環(huán)依賴產(chǎn)生的原因

數(shù)據(jù)過度冗余

數(shù)據(jù)冗余是導(dǎo)致服務(wù)之間循環(huán)依賴的主要原因,為了保證多個(gè)服務(wù)之間數(shù)據(jù)的一致性,某個(gè)服務(wù)對(duì)數(shù)據(jù)的修改要同步到其他服務(wù),保證其他服務(wù)冗余字段的信息準(zhǔn)確。

上面訂單上冗余客戶姓名的場(chǎng)景就是個(gè)很好的例子,冗余數(shù)據(jù)在一定程度上增強(qiáng)了業(yè)務(wù)實(shí)現(xiàn)的簡(jiǎn)便性,但為了保證數(shù)據(jù)一致性,也增加了服務(wù)間不必要的調(diào)用。

缺失業(yè)務(wù)概念

和數(shù)據(jù)過度冗余相對(duì)的是在軟件設(shè)計(jì)時(shí)缺少必要的業(yè)務(wù)概念,也同樣會(huì)導(dǎo)致循環(huán)依賴的情況發(fā)生;典型的場(chǎng)景是上游系統(tǒng)的數(shù)據(jù)狀態(tài)需要下游系統(tǒng)的數(shù)據(jù)進(jìn)行計(jì)算得到,當(dāng)需要對(duì)上游系統(tǒng)的數(shù)據(jù)狀態(tài)時(shí),上游服務(wù)會(huì)調(diào)用下游服務(wù)的接口來進(jìn)行計(jì)算。

這種場(chǎng)景也很常見,繼續(xù)用訂單和客戶的例子幫助理解:

如果一個(gè)客戶的所有訂單要么取消,要么已經(jīng)完成開票結(jié)算流程,那么這個(gè)客戶就是一個(gè)成功客戶,否則是一個(gè)服務(wù)中客戶

在軟件設(shè)計(jì)時(shí)如果沒有給客戶定義一個(gè)狀態(tài)來表達(dá)這個(gè)業(yè)務(wù)概念,那么每次需要拿到客戶狀態(tài)時(shí)只能通過訂單服務(wù)來進(jìn)行查詢計(jì)算。

濫用同步調(diào)用

上面兩種場(chǎng)景一旦產(chǎn)生循環(huán)依賴,往往也伴隨著同步調(diào)用的濫用,然而也有一些場(chǎng)景既沒有數(shù)據(jù)過度冗余,也沒有缺少業(yè)務(wù)概念,但仍然可能會(huì)濫用同步調(diào)用。

上文圖中用戶離職更新客戶所有者信息的場(chǎng)景就是一個(gè)很好的例子,雖然使用同步調(diào)用的方式從實(shí)現(xiàn)結(jié)果上來看是非常直接有效的方法,但長(zhǎng)遠(yuǎn)來看,這種無(wú)腦的濫用同步調(diào)用讓系統(tǒng)的復(fù)雜度變的非常高,當(dāng)我們希望替換或重構(gòu)某個(gè)服務(wù),我們很難依據(jù)業(yè)務(wù)分析清楚到底有哪些服務(wù)會(huì)受到影響。

消滅循環(huán)依賴的方法

通過上面對(duì)循環(huán)依賴原因的分析(這里我們不考慮微服務(wù)劃分不合理的場(chǎng)景),可以看出循環(huán)依賴通常是為了滿足某種業(yè)務(wù)需求,在服務(wù)之間增加了不合理的調(diào)用。

要解決循環(huán)依賴,必須要在微服務(wù)之間建立一些原則來約束微服務(wù)之間的通信,定期通過這些原則來審視我們的系統(tǒng),找到問題并進(jìn)行重構(gòu),這些原則應(yīng)該包括:

  • 定義服務(wù)上下游關(guān)系,下游服務(wù)可以直接依賴上游服務(wù),反之則不可
  • 上游服務(wù)的變更對(duì)下游服務(wù)產(chǎn)生影響需要通過領(lǐng)域事件(異步)的方式來實(shí)現(xiàn)
  • 服務(wù)之間要通過數(shù)據(jù)Id(或類Id,能夠唯一代表數(shù)據(jù)且不變的屬性)來進(jìn)行關(guān)聯(lián),盡量不做過多的數(shù)據(jù)冗余
  • 一旦需要上游服務(wù)調(diào)用下游服務(wù)才能完成業(yè)務(wù)時(shí),要考慮是否上游服務(wù)缺少業(yè)務(wù)概念
  • 為滿足前端邏輯而導(dǎo)致的服務(wù)間交互邏輯要放到BFF(Backend for frontend)中,而不是增加服務(wù)間的調(diào)用

小結(jié)

微服務(wù)架構(gòu)提倡把服務(wù)拆的小而獨(dú)立,一個(gè)軟件系統(tǒng)往往會(huì)有很多服務(wù),大部分業(yè)務(wù)需求是需要多個(gè)服務(wù)一起配合才能完成;受限于交付壓力,在對(duì)架構(gòu)的理解不是很透徹的情況下,開發(fā)人員往往傾向于采用更容易的(熵增)方式實(shí)現(xiàn)功能,在這種情況下,循環(huán)依賴是一個(gè)非常容易發(fā)生的壞味道,對(duì)系統(tǒng)的健康具有巨大危害。

我們可以通過一些技術(shù)手段來發(fā)現(xiàn)系統(tǒng)中的循環(huán)依賴問題,比如通過鏈路追蹤系統(tǒng)(如Zipkin)將服務(wù)間依賴關(guān)系可視化出來;也可以在發(fā)現(xiàn)問題時(shí)將有問題的流程時(shí)序圖畫出來,可視化的方式可以很容易幫我們找到系統(tǒng)中循環(huán)依賴的問題,然后我們就可以對(duì)癥下藥,消滅壞味道。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 微服務(wù)架構(gòu)的流行源于它能夠帶來更快的變化響應(yīng)能力,比如獨(dú)立部署,每個(gè)服務(wù)的能力職責(zé)是獨(dú)立的,可以按需獨(dú)立發(fā)布;再比...
    碼猿外閱讀 816評(píng)論 0 1
  • 微服務(wù)架構(gòu)相比單體架構(gòu)而言的優(yōu)點(diǎn),可以列舉出很多:服務(wù)個(gè)體更小,更內(nèi)聚,業(yè)務(wù)職責(zé)更清晰,可復(fù)用性更強(qiáng),可以獨(dú)立部署...
    碼猿外閱讀 935評(píng)論 0 0
  • 前言 一直對(duì)微服務(wù)非常感興趣,因?yàn)楣镜募軜?gòu)改造正好有機(jī)會(huì)能夠接觸微服務(wù),買來一些書,請(qǐng)教了很多微服務(wù)大牛同時(shí)自己...
    小程故事多閱讀 1,764評(píng)論 2 33
  • 《微服務(wù)設(shè)計(jì)》由 ThoughtWorks 的技術(shù)專家 Sam Newman 編寫,整書 200 多頁(yè),從 “是什...
    emmg閱讀 291評(píng)論 0 1
  • 前言 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD)的普及和應(yīng)用讓微服務(wù)拆分和落地有了理論的指導(dǎo),有章可循,有法可依。特別是在一個(gè)產(chǎn)品或者...
    碼猿外閱讀 926評(píng)論 0 1

友情鏈接更多精彩內(nèi)容