国产欧美日韩第一页|日本一二三不卡视频|在线精品小视频,亚洲第一免费播放区,metcn人体亚洲一区,亚洲精品午夜视频

幫助中心 >  行業(yè)資訊 >  其他 >  微服務(wù)化后,需要注意的幾點

微服務(wù)化后,需要注意的幾點

2021-05-07 10:29:41 632

隨著業(yè)務(wù)發(fā)展,很多系統(tǒng)需要經(jīng)歷服務(wù)拆分的過程。微服務(wù)化過程踩坑也是很正常的事。如果在服務(wù)拆分之前做好充分準(zhǔn)備,能幫我們少走很多彎路。本文主要從服務(wù)依賴,接口版本,隔離,數(shù)據(jù)一致等方面說說微服務(wù)化過程應(yīng)該注意的點。

一、循環(huán)依賴問題

微服務(wù)化之后服務(wù)之間會存在各種依賴關(guān)系,不過依賴需要遵循一定的規(guī)則,不能太隨意。否則,就會出現(xiàn)循環(huán)依賴的問題,而且會讓調(diào)用關(guān)系變得錯綜復(fù)雜難于維護(hù)。下面是服務(wù)依賴的幾條規(guī)則:

1,上層服務(wù)可以調(diào)用下層服務(wù)。

2,同級服務(wù)之間不能產(chǎn)生依賴關(guān)系,及不能產(chǎn)生調(diào)用關(guān)系。

3,下層服務(wù)不能調(diào)用上層服務(wù)。

4,服務(wù)之間的調(diào)用關(guān)系只能是單向的。

例如,在電商系統(tǒng)里包括支付服務(wù)(Pay),庫存服務(wù)(Inventory),訂單服務(wù)(Order)。支付服務(wù)和庫存服務(wù)屬于基礎(chǔ)服務(wù),訂單服務(wù)屬于上層服務(wù)。支付服務(wù)和庫存服務(wù)是同級的服務(wù),他們之間不能存在調(diào)用關(guān)系。訂單服務(wù)屬于上層服務(wù),訂單服務(wù)可以調(diào)用支付服務(wù)和庫存服務(wù),但是支付服務(wù)和庫存服務(wù)不能調(diào)用上層的訂單服務(wù)。 

假設(shè)我們不管這些規(guī)則,讓Order和Pay可以互相調(diào)用。這樣就會產(chǎn)生循環(huán)依賴,Order調(diào)用Pay,Pay也調(diào)用Order,這樣彼此都會依賴對方。

循環(huán)依賴導(dǎo)致哪些問題?

1,無限遞歸調(diào)用

假如,Order調(diào)用Pay的A方法,Pay調(diào)用Order的B方法。然后,A方法里又調(diào)用了Order的B方法,B方法里又調(diào)用了Pay的A方法。這樣就會產(chǎn)生無限的遞歸調(diào)用,后果自然不言而喻了。

 

image.png



image.png


2,部署依賴問題

假設(shè)Order,Pay,Inventory彼此之間都可以通過API互相調(diào)用。當(dāng)API接口發(fā)生變更時,為了讓其他服務(wù)能夠正常調(diào)用,API需要重新編譯。如果Order和Pay的API都有變化,上線發(fā)布時就需要特別小心。為了保證發(fā)布成功,就需要根據(jù)服務(wù)間API的依賴關(guān)系,詳細(xì)考慮先打包部署哪個服務(wù),后打包部署哪個服務(wù),才不至于發(fā)布失敗。如果有更多的服務(wù)呢?比如10幾個,梳理依賴關(guān)系都會把人搞瘋的。 

3,另外,循環(huán)依賴會讓服務(wù)間的調(diào)用關(guān)系變得錯綜復(fù)雜,系統(tǒng)難于維護(hù)。

二、接口版本兼容

一些初中級程序員往往會忽略接口變更的問題,經(jīng)常會因為接口變更導(dǎo)致線上問題。比如某個小型電商平臺的訂單服務(wù)調(diào)用支付服務(wù)的某個接口,產(chǎn)品突然提了一個需求,這個需求需要在這個支付接口上加一個參數(shù)。開發(fā)這個需求的是個新手,他直接在原來的接口方法上實現(xiàn)了需求并加上了參數(shù),聯(lián)調(diào)測試通過后就發(fā)布上線了。結(jié)果剛上線訂單服務(wù)就開始報錯,因為方法變了,加了參數(shù),訂單服務(wù)找不到老的方法了。所以就會一直報錯,直到訂單服務(wù)上線為止。

所以我們一定要注意接口版本問題。我們可以新加一個方法去重載老的方法,在新方法里實現(xiàn)新的功能,新方法的定義除了多一個參數(shù)外,其他的和老方法一樣。也就是給老方法加了一個新版本。

這樣在支付服務(wù)上線后,訂單服務(wù)上線之前就不會報錯了,因為老方法仍然可用。訂單服務(wù)上線后就直接切到了新版本的方法。

如果我們服務(wù)框架選用的是Dubbo,當(dāng)一個接口的實現(xiàn),出現(xiàn)不兼容升級時,可以用Dubbo的版本號過渡,版本號不同的服務(wù)相互間不引用。

可以按照以下的步驟進(jìn)行版本遷移:

1. 在低壓力時間段,先升級一半提供者為新版本

2. 再將所有消費者升級為新版本

3. 然后將剩下的一半提供者升級為新版本

老版本服務(wù)提供者配置:


image.png


新版本服務(wù)提供者配置:


image.png


老版本服務(wù)消費者配置:


image.png


新版本服務(wù)消費者配置:


image.png


三、關(guān)于隔離的考慮

1.數(shù)據(jù)隔離:

實際上,服務(wù)化的其中一個基本原則就是數(shù)據(jù)隔離,不同服務(wù)應(yīng)該有自己的專屬數(shù)據(jù)庫,而不應(yīng)該共用相同的數(shù)據(jù)庫,數(shù)據(jù)訪問可以通過服務(wù)接口或者消息隊列的方式。

很多公司微服務(wù)化后,只做了代碼工程的拆分,不同服務(wù)對應(yīng)的數(shù)據(jù)仍然存放在同一個數(shù)據(jù)庫中。這樣做至少存在四個問題:

(1)數(shù)據(jù)安全問題。別人的服務(wù)不但可以訪問你的數(shù)據(jù),而且還能修改和刪除你的數(shù)據(jù)。

(2)導(dǎo)致數(shù)據(jù)庫連接耗盡。一旦某個服務(wù)的開發(fā)者寫了一個慢SQL,并且這個服務(wù)也沒有合理限制連接數(shù)??赡軙牡羲械臄?shù)據(jù)庫連接,進(jìn)而造成訪問相同數(shù)據(jù)庫的其他服務(wù)拿不到數(shù)據(jù)庫連接,無法訪問數(shù)據(jù)庫。

(3)表關(guān)聯(lián)查詢。無法避免其他服務(wù)的開發(fā)者,為了快速上線某些需求。直接查詢其他服務(wù)的表,或者跨服務(wù)做表關(guān)聯(lián)查詢。這樣會造成服務(wù)間的耦合越來越嚴(yán)重。

(4)表結(jié)構(gòu)變化的影響。如果某個服務(wù)直接依賴于其他服務(wù)的數(shù)據(jù),一旦表結(jié)構(gòu)發(fā)生任何變化,比如修改表名或者字段。很可能會產(chǎn)生災(zāi)難性后果。

2.部署隔離:

我們經(jīng)常會遇到秒殺業(yè)務(wù)和日常業(yè)務(wù)依賴同一個服務(wù),以及C端服務(wù)和內(nèi)部運營系統(tǒng)依賴同一個服務(wù)的情況,比如說都依賴支付服務(wù)。而秒殺系統(tǒng)的瞬間訪問量很高,可能會對服務(wù)帶來巨大的壓力,甚至壓垮服務(wù)。內(nèi)部運營系統(tǒng)也經(jīng)常有批量數(shù)據(jù)導(dǎo)出的操作,同樣會給服務(wù)帶來一定的壓力。這些都是不穩(wěn)定因素。所以我們可以將這些共同依賴的服務(wù)分組部署,不同的分組服務(wù)于不同的業(yè)務(wù),避免相互干擾。


2.png


3.業(yè)務(wù)隔離:

以秒殺為例。從業(yè)務(wù)上把秒殺和日常的售賣區(qū)分開來,把秒殺做為營銷活動,要參與秒殺的商品需要提前報名參加活動,這樣我們就能提前知道哪些商家哪些商品要參與秒殺,可以根據(jù)提報的商品提前生成商品詳情靜態(tài)頁面并上傳到CDN預(yù)熱,提報的商品庫存也需要提前預(yù)熱,可以將商品庫存在活動開始前預(yù)熱到Redis,避免秒殺開始后大量訪問穿透到數(shù)據(jù)庫。


99.jpg

       

四、數(shù)據(jù)一致性問題

做了微服務(wù)拆分后,還可能會出現(xiàn)數(shù)據(jù)不一致的問題。比如支付服務(wù)中,支付狀態(tài)發(fā)生變更后要通知訂單服務(wù)修改對應(yīng)訂單的狀態(tài)。如果支付服務(wù)沒有正常通知到訂單服務(wù),或者訂單服務(wù)接到通知后沒能正常處理通知,就會導(dǎo)致支付服務(wù)的支付狀態(tài)和訂單服務(wù)的支付狀態(tài)不一致,也就是數(shù)據(jù)會不一致。

1.那么如何避免數(shù)據(jù)不一致的問題產(chǎn)生呢?

我們通常所說的服務(wù)間數(shù)據(jù)一致性,主要包括數(shù)據(jù)強(qiáng)一致性和最終一致性。對于強(qiáng)一致性,使用的業(yè)務(wù)場景很少,而且會有明顯的性能問題。所以這里我們主要討論最終一致性。

一般我們可以采用如下幾種方式來保證服務(wù)間數(shù)據(jù)的最終一致:

2.定時任務(wù)重試,同步調(diào)用接口

這種方式,采用定時任務(wù)去掃表,每次定時任務(wù)掃描所有未成功的記錄,并發(fā)起重試。注意,要保證重試操作的冪等性。

這種方式的優(yōu)點是:實現(xiàn)簡單。缺點是:需要啟動專門的定時任務(wù),定時任務(wù)存在一定的時間間隔,實時性會比較差。而且同步接口調(diào)用的方式,耦合較重,有時無法避免循環(huán)依賴的問題。

比如,Order服務(wù)可以調(diào)用Pay,Pay做為基礎(chǔ)服務(wù)不應(yīng)該調(diào)用Order。當(dāng)Pay的某筆交易狀態(tài)發(fā)生變更后,需要通知Order。如果采用定時任務(wù)的方式就需要Order提供一個接口,定時任務(wù)掃描過程中同步調(diào)用這個接口去更新Order的訂單狀態(tài)。這樣又違反了單向依賴的原則,形成了循環(huán)依賴。

異步消息隊列,發(fā)送事務(wù)型消息

 

100.jpg

 

如上圖,以電商下單流程為例。下單流程最后一步,通知WMS撿貨出庫,是異步消息走消息隊列。

 

image.png


按上面代碼,大家不難發(fā)現(xiàn)問題!如果發(fā)送撿貨出庫消息失敗,數(shù)據(jù)就會不一致!有人說我可以在代碼上加上重試邏輯和回退邏輯,發(fā)消息失敗就重發(fā),多次重試失敗所有操作都回退。這樣一來邏輯就會特別復(fù)雜,回退失敗要考慮,而且還有可能消息已經(jīng)發(fā)送成功了,但是由于網(wǎng)絡(luò)等問題發(fā)送方?jīng)]得到MQ的響應(yīng)。還有可能出現(xiàn)發(fā)送方宕機(jī)的情況。這些問題都要考慮進(jìn)來!

幸好,有些消息隊列幫我們解決了這些問題。比如阿里開源的RocketMQ(目前已經(jīng)是Apache開源項目),4.3.0版本開始支持事務(wù)型消息(實際上早在貢獻(xiàn)給Apache之前曾經(jīng)支持過事務(wù)消息,后來被閹割了,4.3.0版本重新開始支持事務(wù)型消息)。

先看看RocketMQ發(fā)送事務(wù)型消息的流程:


111.jpg


(1)發(fā)送半消息(所有事務(wù)型消息都要經(jīng)歷確認(rèn)過程,從而確定最終提交或回滾(拋棄消息),未被確認(rèn)的消息稱為“半消息”或者“預(yù)備消息”,“待確認(rèn)消息”)

(2)半消息發(fā)送成功并響應(yīng)給發(fā)送方

(3)執(zhí)行本地事務(wù),根據(jù)本地事務(wù)執(zhí)行結(jié)果,發(fā)送提交或回滾的確認(rèn)消息

(4)如果確認(rèn)消息丟失(網(wǎng)絡(luò)問題或者生產(chǎn)者故障等問題),MQ向發(fā)送方回查執(zhí)行結(jié)果

(5)根據(jù)上一步驟回查結(jié)果,確定提交或者回滾(拋棄消息)

看完事務(wù)型消息發(fā)送流程,有些讀者可能沒有完全理解,不要緊,我們來分析一下!

問題1:假如發(fā)送方發(fā)送半消息失敗怎么辦?

半消息(待確認(rèn)消息)是消息發(fā)送方發(fā)送的,如果失敗,發(fā)送方自己是知道的并可以做相應(yīng)處理。

問題2:假如發(fā)送方執(zhí)行完本地事務(wù)后,發(fā)送確認(rèn)消息通知MQ提交或回滾消息時失敗了(網(wǎng)絡(luò)問題,發(fā)送方重啟等情況),怎么辦?

沒關(guān)系,當(dāng)MQ發(fā)現(xiàn)一個消息長時間處于半消息(待確認(rèn)消息)的狀態(tài),MQ會以定時任務(wù)的方式主動回查發(fā)送方并獲取發(fā)送方執(zhí)行結(jié)果。這樣即便出現(xiàn)網(wǎng)絡(luò)問題或者發(fā)送方本身的問題(重啟,宕機(jī)等),MQ通過定時任務(wù)主動回查發(fā)送方基本都能確認(rèn)消息最終要提交還是回滾(拋棄)。當(dāng)然出于性能和半消息堆積方面的考慮,MQ本身也會有回查次數(shù)的限制。

問題3:如何保證消費一定成功呢?

RocketMQ本身有ack機(jī)制,來保證消息能夠被正常消費。如果消費失?。ㄏ⒂嗛喎匠鲥e,宕機(jī)等原因),RocketMQ會把消息重發(fā)回Broker,在某個延遲時間點后(默認(rèn)10秒后)重新投遞消息。

結(jié)合上面幾個同步調(diào)用hmily完整代碼如下:


image.png


image.png


image.png


image.png


如果執(zhí)行到TransactionListenerImpl.executeLocalTransaction方法,說明半消息已經(jīng)發(fā)送成功了,也說明OrderService.makePayment方法的四個步驟都執(zhí)行成功了,此時tcc也到了confirm階段,所以在TransactionListenerImpl.executeLocalTransaction方法里可以直接返回LocalTransactionState.COMMIT_MESSAGE 讓 MQ提交這條消息,同時將該訂單信息和對應(yīng)的消息狀態(tài)保存在共享map里,以備確認(rèn)消息發(fā)送失敗時MQ回查消息狀態(tài)使用。

3.采用TCC,SAGA,Seata等框架

以上就是微服務(wù)化后需要注意的幾點。





提交成功!非常感謝您的反饋,我們會繼續(xù)努力做到更好!

這條文檔是否有幫助解決問題?

非常抱歉未能幫助到您。為了給您提供更好的服務(wù),我們很需要您進(jìn)一步的反饋信息:

在文檔使用中是否遇到以下問題: