當(dāng)前位置:
首頁(yè) >
第四章:集成
發(fā)布時(shí)間:2025/7/14
49
豆豆
集成是微服務(wù)相關(guān)技術(shù)中最重要的一個(gè)。做得好的話,你的微服務(wù)可以保持自治性,可以獨(dú)立修改和發(fā)布他們,如果做的不好的話,會(huì)帶來(lái)災(zāi)難。 4.1尋找理想的集成技術(shù) 微服務(wù)間的通訊選擇性很多,REST、SOAP、RPC、Protocol buffers等。 4.11避免破壞性修改 有些時(shí)候?qū)σ粋€(gè)微服務(wù)的修改會(huì)造成該服務(wù)消費(fèi)者的修改,例如:微服務(wù)A增加了一個(gè)字段,如果處理不好的話,會(huì)導(dǎo)致A服務(wù)的消費(fèi)者B服務(wù)也必須增加該字段才能保證服務(wù)B能夠正常調(diào)用A服務(wù)。 4.12保證API的技術(shù)無(wú)關(guān)性 保證微服務(wù)間的技術(shù)無(wú)關(guān)性非常重要,這意味著不應(yīng)該選擇那種對(duì)微服務(wù)的具體實(shí)現(xiàn)技術(shù)有限制的集成方式。 4.13使你的服務(wù)易于消費(fèi)方使用 消費(fèi)方應(yīng)該很容易的調(diào)用我們的服務(wù)。理想情況下,消費(fèi)方可以使用任何技術(shù)來(lái)實(shí)現(xiàn); 另一方面,提供一個(gè)客戶端庫(kù)也可以簡(jiǎn)化消費(fèi)方的使用,但是消費(fèi)方使用客戶端庫(kù)也會(huì)造成微服務(wù)間的耦合。 4.14隱藏內(nèi)部實(shí)現(xiàn)細(xì)節(jié) 我們不希望消費(fèi)方和服務(wù)的內(nèi)部實(shí)現(xiàn)細(xì)節(jié)綁定在一起,因?yàn)檫@會(huì)增加耦合。 與細(xì)節(jié)綁定意味著,如果改動(dòng)服務(wù)內(nèi)部的一些實(shí)現(xiàn),消費(fèi)方就需要跟著做出修改,這會(huì)增加成本,因此我們要避免。 這也會(huì)導(dǎo)致我們?yōu)榱吮苊庀M(fèi)方的修改而盡量少的對(duì)服務(wù)本身進(jìn)行修改,從而導(dǎo)致服務(wù)內(nèi)部技術(shù)債的增加。 因此,所有傾向于暴露內(nèi)部實(shí)現(xiàn)細(xì)節(jié)的技術(shù)都不應(yīng)該被采用。 4.2為用戶創(chuàng)建接口 以MusicCrop為例,創(chuàng)建客戶這個(gè)業(yè)務(wù),包括新客戶的創(chuàng)建、付賬設(shè)置、發(fā)送歡迎郵件等接口; 接下來(lái)會(huì)以這個(gè)業(yè)務(wù)為例說(shuō)明集成的各種方式。 4.3共享數(shù)據(jù)庫(kù) 業(yè)界最常見的集成形式就是共享數(shù)據(jù)。使用這種方式時(shí),如果其他服務(wù)想要從一個(gè)服務(wù)獲取信息,可以直接訪問(wèn)數(shù)據(jù)庫(kù)。如果想要修改,也可以直接在數(shù)據(jù)庫(kù)中修改。這種方式看起來(lái)非常簡(jiǎn)單,而且可能是最快的集成方式,這也正是它流行的原因。 共享數(shù)據(jù)庫(kù)的方式有以下缺點(diǎn): 多個(gè)服務(wù)同時(shí)訪問(wèn)相同共享數(shù)據(jù)庫(kù),會(huì)造成外部服務(wù)能夠查看到內(nèi)部實(shí)現(xiàn)細(xì)節(jié),并與其綁定在一起。存儲(chǔ)在數(shù)據(jù)庫(kù)中的數(shù)據(jù)對(duì)所有人來(lái)說(shuō)都是公平的,所有服務(wù)都可以完全訪問(wèn)該數(shù)據(jù)庫(kù)。如果我們更改數(shù)據(jù)庫(kù)表結(jié)構(gòu),那么消費(fèi)方就無(wú)法進(jìn)行工作。共享數(shù)據(jù)庫(kù)是一個(gè)大的共享API,但同時(shí)也非常不穩(wěn)定。 消費(fèi)方與特定的技術(shù)進(jìn)行了綁定,這說(shuō)的是所有服務(wù)都與共享數(shù)據(jù)庫(kù)進(jìn)行了綁定。如果一個(gè)某個(gè)服務(wù)使用非關(guān)系型數(shù)據(jù)庫(kù)更好,那么會(huì)為以后這種形式的修改帶來(lái)很大的困難。這也造成了服務(wù)間的耦合。 微服務(wù)的設(shè)計(jì)核心:高內(nèi)聚和松耦合。因此通過(guò)共享數(shù)據(jù)庫(kù)的方式很難滿足設(shè)計(jì)要求。 4.4同步和異步 服務(wù)間的協(xié)作包括兩種方式“同步和異步。 如果使用同步通信,發(fā)起一個(gè)遠(yuǎn)程服務(wù)調(diào)用后,調(diào)用方會(huì)阻塞自己并等到整個(gè)操作的完成。 如果使用異步通信,調(diào)用方不用等待操作完成就可以返回,甚至不需要關(guān)心這個(gè)操作是否完成。 同步可以知道事情是否成功執(zhí)行。 異步通信對(duì)于運(yùn)行時(shí)間比較長(zhǎng)的任務(wù)來(lái)說(shuō)比較有用,否則就需要在客戶端和服務(wù)端之間開啟一個(gè)長(zhǎng)連接,這是非常不實(shí)際的。 當(dāng)需要低延遲的時(shí)候可以使用異步通信。 處理異常通信的技術(shù)相對(duì)來(lái)說(shuō)比較復(fù)雜。 同步通信 即請(qǐng)求/響應(yīng):發(fā)起一個(gè)請(qǐng)求,然后等待響應(yīng)。 異步通信 即基于事件:發(fā)起一個(gè)請(qǐng)求,注冊(cè)一個(gè)回調(diào),當(dāng)服務(wù)端操作結(jié)束后,會(huì)調(diào)用該回調(diào)。 對(duì)于使用基于事件的協(xié)作方式來(lái)說(shuō),客戶端不是發(fā)起請(qǐng)求,而是發(fā)布一個(gè)事件,然后期待其他的協(xié)作者接收到該消息,并知道該怎么做。 基于事件的系統(tǒng)天生就是異步的; 業(yè)務(wù)邏輯并非集成中某個(gè)核心服務(wù)中,而是平均分布在不同的協(xié)作者中。 基于事件的協(xié)作方式耦合性很低。 4.5編排和協(xié)作 對(duì)復(fù)雜業(yè)務(wù)邏輯進(jìn)行建模時(shí),我們需要處理跨服務(wù)業(yè)務(wù)流程的問(wèn)題,而使用微服務(wù)時(shí)這個(gè)問(wèn)題會(huì)來(lái)的更快,我們以MusicCrop中創(chuàng)建用戶為例,看看創(chuàng)建用戶業(yè)務(wù)時(shí)會(huì)發(fā)生什么。 MusicCrop的創(chuàng)建用戶業(yè)務(wù)包括三個(gè)子業(yè)務(wù): 在客戶的積分賬號(hào)中創(chuàng)建一條記錄; 通過(guò)郵政系統(tǒng)給用戶發(fā)送一個(gè)歡迎禮包; 通過(guò)郵件系統(tǒng)發(fā)送一條歡迎郵件; 當(dāng)考慮具體實(shí)現(xiàn)時(shí),有兩種架構(gòu)風(fēng)格可以采用: 一種是使用編排,我們依賴某個(gè)中心大腦來(lái)驅(qū)動(dòng)整個(gè)流程。 編排的話,在創(chuàng)建客戶時(shí),會(huì)通過(guò)請(qǐng)求/響應(yīng)的方式進(jìn)行通訊,我們可以對(duì)當(dāng)前進(jìn)行到具體哪一個(gè)進(jìn)行跟蹤。 編排的缺點(diǎn)是客戶服務(wù)作為中心控制點(diǎn)承擔(dān)了太多職責(zé),它會(huì)成為網(wǎng)狀結(jié)構(gòu)的中心樞紐及很多邏輯的起點(diǎn)。例如客戶服務(wù)中心可能會(huì)成為“上帝服務(wù)”,而其他三個(gè)子服務(wù)會(huì)成為“貧血服務(wù)”即只是簡(jiǎn)單的CRUD操作。 大多數(shù)的重量級(jí)的編排方案都非常不穩(wěn)定,而且修改的代價(jià)很大。 一種是使用協(xié)同,我們僅僅需要告訴系統(tǒng)中各個(gè)部分各自的職責(zé),而把具體怎么做的細(xì)節(jié)留給它們自己。 使用協(xié)同,可以僅僅從客戶中心服務(wù)使用異步的方式觸發(fā)一個(gè)事件,該事件名可以叫做“創(chuàng)建客戶”,例如可以使用訂閱或者消息系統(tǒng),客戶服務(wù)中心發(fā)送一個(gè)消息,然后其他三個(gè)子服務(wù)自己去執(zhí)行各自的服務(wù)。 使用協(xié)同可以消除耦合,同時(shí)可以對(duì)現(xiàn)有系統(tǒng)更加靈活的修改。 協(xié)同的缺點(diǎn)是看不到具體的創(chuàng)建客戶業(yè)務(wù)流程處理到哪一個(gè)步驟,比較難以跟蹤。 同時(shí)意味著我們需要做一個(gè)些額外的監(jiān)控工作,以保證其正確的進(jìn)行。 基于以上兩種方式的比較,我更傾向于使用協(xié)同的方式,在這種方式下每個(gè)服務(wù)都足夠聰明,并且能夠很好的完成自己的任務(wù)。 這里有好幾個(gè)因素需要考慮:同步調(diào)用比較簡(jiǎn)單,而且容易知道整個(gè)流程的工作是否正常,如果想用使用請(qǐng)求/響應(yīng)風(fēng)格的語(yǔ)義,可以使用異步請(qǐng)求加回調(diào)的方式;另一方面,使用異步調(diào)用的方式有利于協(xié)同方案的實(shí)施,從而大大減少服務(wù)間的耦合,這恰恰就是我們?yōu)榱四軌颡?dú)立發(fā)布服務(wù)而追求的特定。 針對(duì)請(qǐng)求/響應(yīng)可以考慮兩種技術(shù)RPC和REST。 4.6遠(yuǎn)程過(guò)程調(diào)用RPC 遠(yuǎn)程過(guò)程調(diào)動(dòng)允許你進(jìn)行一個(gè)本地調(diào)用,但是事實(shí)上結(jié)果是由某個(gè)遠(yuǎn)程服務(wù)器產(chǎn)生的。 RPC的實(shí)現(xiàn)會(huì)幫你生成服務(wù)端和客戶端的樁代碼,從而讓你快速開始編碼。基本上不用花時(shí)間,我們就可以再服務(wù)間進(jìn)行內(nèi)容交互了。 然而有一些RPC的實(shí)現(xiàn)確實(shí)存在一些問(wèn)題。這些問(wèn)題通常一開始不明顯,但慢慢地就會(huì)暴露出來(lái),并且?guī)?lái)的代價(jià)要遠(yuǎn)遠(yuǎn)大于一開始快速啟動(dòng)的好處。 4.6.1技術(shù)的耦合 有一些RPC機(jī)制,如Java RMI與特定的平臺(tái)緊密綁定,這對(duì)于服務(wù)端和客戶端的技術(shù)選型造成了一定限制。Thrift和protocol buffers對(duì)于不同語(yǔ)言的支持很好,從而在一定程度上減少了這個(gè)問(wèn)題的影響。 從某種程度上來(lái)說(shuō),這種技術(shù)上的耦合也會(huì)暴露內(nèi)部實(shí)現(xiàn)細(xì)節(jié)的一定方式。例如使用Java RMI不僅把客戶端綁定在JVM上,服務(wù)端也是如此。 4.6.2本地調(diào)用和遠(yuǎn)程調(diào)用并不相同 RPC的和興想法是隱藏遠(yuǎn)程調(diào)用的復(fù)雜性。但是很多RPC的實(shí)現(xiàn)隱藏的有些過(guò)頭了,進(jìn)而會(huì)造成一些問(wèn)題。使用本地調(diào)用不會(huì)引起性能問(wèn)題,但是RPC會(huì)花大量的時(shí)間對(duì)負(fù)荷進(jìn)行封裝和解封裝,更別提網(wǎng)絡(luò)通信需要的時(shí)間。 你需要考慮網(wǎng)絡(luò)本身的問(wèn)題。分布式計(jì)算中一個(gè)非常著名的錯(cuò)誤觀點(diǎn)就是“網(wǎng)絡(luò)是可靠的”,事實(shí)上網(wǎng)絡(luò)并不可靠。及時(shí)客戶端和服務(wù)端都正常運(yùn)行,整個(gè)調(diào)用也有可能出錯(cuò),這些錯(cuò)誤有可能會(huì)很快發(fā)生,有可能過(guò)一段時(shí)間才會(huì)顯現(xiàn)出來(lái),它們升值有可能損壞你的報(bào)文,因此網(wǎng)絡(luò)的出錯(cuò)模式也不止一種。 4.6.3.脆弱性 有一些很流程的RPC實(shí)現(xiàn)可能會(huì)造成一些令人討厭的脆弱性,Java的RMI就是一個(gè)很好的例子,考慮一個(gè)非常簡(jiǎn)單的接口,通過(guò)該接口可以向客戶服務(wù)發(fā)起一個(gè)遠(yuǎn)程調(diào)用,如果對(duì)該接口進(jìn)行了修改,由于是本地的樁代碼,你很容易把這個(gè)接口當(dāng)成了本地接口進(jìn)行了修改,從而造成錯(cuò)誤。并且如果想修改一個(gè)接口,需要重新生成服務(wù)端和客戶端兩邊的樁代碼,這種修改會(huì)很頻繁。 這就是任何一個(gè)使用二進(jìn)制樁代碼生成機(jī)制的RPC所要面臨的挑戰(zhàn):客戶端和服務(wù)端的部署無(wú)法分離。如果使用這種技術(shù)。離lock-setp發(fā)布就不遠(yuǎn)了。 實(shí)踐中,通訊雙方使用的數(shù)據(jù)類型會(huì)直接被序列化和反序列化,而如果數(shù)據(jù)類型中包含了大量的字段,這就會(huì)導(dǎo)致不再使用的字段無(wú)法被安全的刪除掉。 4.6.4RPC很糟糕嗎 盡管RPC存在這些缺點(diǎn),但是可以通過(guò)使用thrift或者protocol buffers等技術(shù)來(lái)避免對(duì)客戶端和服務(wù)端的lock-step發(fā)布來(lái)消除上面提到的一些問(wèn)題。 如果你決定使用RPC方式的話,需要注意一些問(wèn)題: 不要對(duì)遠(yuǎn)程調(diào)用過(guò)度抽象,以至于網(wǎng)路因素完全被隱藏起來(lái); 確保你可以單獨(dú)的升級(jí)服務(wù)端的接口而不用強(qiáng)迫客戶端升級(jí),所以在編寫客戶端代碼時(shí)要注意這個(gè)方面的均衡; 在客戶端中一定不要隱藏我們是在做網(wǎng)絡(luò)調(diào)用這個(gè)事實(shí), 在RPC的方式中經(jīng)常會(huì)在客戶端能使用庫(kù),但是這些庫(kù)如果在結(jié)構(gòu)上組織的不好,也有可能會(huì)帶來(lái)一些問(wèn)題。 RPC是請(qǐng)求/響應(yīng)協(xié)作方式的一種,相比使用數(shù)據(jù)庫(kù)做集成的方式,RPC顯然是一個(gè)巨大的進(jìn)步。 4.7REST REST是受Web啟發(fā)而產(chǎn)生的一種架構(gòu)風(fēng)格,REST風(fēng)格包含了需要原則和限制,但是這里我們僅僅專注于如果在微服務(wù)的世界使用REST更好的解決集成問(wèn)題。 REST是RPC的一種替代方案。 REST最重要的一點(diǎn)就是資源的概念。服務(wù)可以根據(jù)請(qǐng)求的內(nèi)容創(chuàng)建對(duì)象的不同表示形式。也就是說(shuō)一個(gè)資源的對(duì)外顯示方式和內(nèi)部存儲(chǔ)方式之間沒(méi)有什么耦合。 REST本身并沒(méi)有提到底層應(yīng)該使用什么協(xié)議,盡管事實(shí)上最常用的http。http的一些特定,比如動(dòng)詞put、get等,使得在http上實(shí)現(xiàn)REST要簡(jiǎn)單的多,而如果使用其他協(xié)議的話,就需要自己實(shí)現(xiàn)這些特定。 4.7.1REST和HTTP HTTP本身提供了很多功能,這些功能對(duì)于實(shí)現(xiàn)REST風(fēng)格非常有用,比如動(dòng)詞put、get等。GET方式使用冪等的方式獲得資源。POST創(chuàng)建一個(gè)新資源。 HTTP周邊也有一個(gè)大的生態(tài)系統(tǒng),其中包含很多支撐工具和技術(shù),例如Varnish這要的HTTP緩存代理、mod_proxy這樣的負(fù)載均衡器。這些工具可以很好幫忙我們處理HTTP流量,并使用聰明的方式對(duì)其進(jìn)行路由。而且這些操作劇本上都對(duì)終端用戶透明。HTTP還提供了一系列安全控制機(jī)制供我們直接使用。包括認(rèn)證證書。 需要注意的是HTTP也可以用來(lái)實(shí)現(xiàn)RPC,比如SOAP就是具有HTTP進(jìn)行路由的。 4.7.2超媒體作為程序狀態(tài)的引擎 REST引入的用來(lái)避免客戶端和服務(wù)端直接產(chǎn)生耦合的另一個(gè)原則是“超媒體作為程序狀態(tài)的引擎”。 4.7.3JSON、XML還是其他 由于服務(wù)端使用標(biāo)準(zhǔn)文本形式的響應(yīng),所以客戶端可以很靈活的對(duì)資源進(jìn)行使用,而基于HTTP和REST能夠提供多種不同的響應(yīng)形式。例如XML和JSON。 JSON無(wú)論從形式上還是使用方法上來(lái)說(shuō)都更加簡(jiǎn)單。相對(duì)于XML來(lái)說(shuō)JSON更加緊湊。 JSON也有一些缺點(diǎn),XML使用連接來(lái)進(jìn)行超媒體控制,JONS中并沒(méi)有類似的東西。 當(dāng)然并不是說(shuō)只有兩種格式,通過(guò)HTTP我們可以發(fā)送任何格式,甚至于二進(jìn)制的。 4.7.4留心過(guò)多的約定 REST越來(lái)越流行,但是有一些工具會(huì)為了短期利益而犧牲長(zhǎng)期利益。例如有些框架可以很容易的表示數(shù)據(jù)庫(kù)對(duì)象,并把它們反序列化成進(jìn)程內(nèi)的對(duì)象,然后直接暴露給外部。這種方式內(nèi)在的耦合性所帶來(lái)的痛苦會(huì)遠(yuǎn)遠(yuǎn)大于從一開始就消除該你啊你之間的耦合所需要的代價(jià)。那如何這個(gè)問(wèn)題那?一個(gè)有效的方式是先進(jìn)行外部接口的設(shè)計(jì),等到外部接口穩(wěn)定之后再實(shí)現(xiàn)微服務(wù)內(nèi)部的數(shù)據(jù)持久化,這樣可以保證接口是由消費(fèi)者的需求驅(qū)動(dòng)出來(lái)的,從而避免數(shù)據(jù)春方式對(duì)外部接口的影響。 4.7.5基于HTTP的REST的缺點(diǎn) 從易用性的角度來(lái)看,基于HTTP的REST無(wú)法幫助你生成客戶端的樁代碼,而RPC可以。 使用HTTP意味著可以使用很多的HTTP客戶端。 從個(gè)人的角度來(lái)看,使用客戶端的庫(kù)可以做的更好,但是使用庫(kù)會(huì)增加復(fù)雜度,因?yàn)槿藗儠?huì)不自覺(jué)的回到基于HTTP的RPC的思路上來(lái),然后構(gòu)建出一些共享庫(kù)。在客戶端和服務(wù)端之間共享代碼是非常危險(xiǎn)的。 還有一個(gè)問(wèn)題就是有些Web框架無(wú)法很好的支持所有的HTTP動(dòng)詞,可能很容易處理GET和POST,但是PUT和DELETE就比較麻煩了。推薦使用Jersey這樣比較好的REST框架就不存在這樣的問(wèn)題。 性能上也可能會(huì)遇到問(wèn)題,基于HTTP的REST支持不同的格式。比如JSON或者二進(jìn)制,所以負(fù)載相對(duì)SOAP來(lái)說(shuō)更加緊湊,當(dāng)然和像Thrift這樣的二進(jìn)制協(xié)議是沒(méi)辦法比的,在低延遲的場(chǎng)景下,每個(gè)HTTP請(qǐng)求的封裝開銷可能是個(gè)問(wèn)題。 雖然HTTP可以用于大流量的通訊場(chǎng)景,但是對(duì)于低延遲通訊來(lái)說(shuō)并不是最好的選擇,相比之下,有一些構(gòu)建于TCP或者其他網(wǎng)絡(luò)技術(shù)之上的協(xié)議更加高效。比如WebService。 對(duì)于服務(wù)和服務(wù)之間的通訊來(lái)說(shuō),如果低延遲或者較小的消息尺寸對(duì)你來(lái)說(shuō)很重要的話,那么一般來(lái)講HTTP不是一個(gè)好主意,你可以選擇一個(gè)不同的底層協(xié)議,類似UDP來(lái)滿足你的性能要求,很多RPC框架都是可以很好地運(yùn)行在除了TCP之外的其他網(wǎng)絡(luò)協(xié)議上。 有些RPC的實(shí)現(xiàn)支持高級(jí)的序列化和反序列化支持,然而對(duì)于REST來(lái)說(shuō),這部分工作就要自己實(shí)現(xiàn)了。這部分工作可能會(huì)成為服務(wù)端和客戶端之間的一個(gè)耦合點(diǎn),因?yàn)閷?shí)現(xiàn)一個(gè)具有容錯(cuò)性的讀取器不是一件容易的事情。 盡管有些缺點(diǎn),在選擇服務(wù)間的交互方式時(shí),基于HTTP的REST仍然是一個(gè)比較合理的默認(rèn)選擇。 4.8實(shí)現(xiàn)基于事件的異步協(xié)作 前面討論了基于請(qǐng)求/響應(yīng)相關(guān)的技術(shù),接下來(lái)介紹基于異步事件的通訊。 4.8.1技術(shù)選擇 主要有兩個(gè)部分需要考慮:微服務(wù)發(fā)布事件機(jī)制和消費(fèi)者接收事件機(jī)制。 傳統(tǒng)來(lái)說(shuō),像RabbitMQ這樣的消息代理能夠處理上述兩方面的問(wèn)題。生產(chǎn)者使用API向代理發(fā)布事件,代理可以向消費(fèi)者提供訂閱服務(wù),并且在事件發(fā)布的時(shí)候通知消費(fèi)者。 不過(guò)需要注意的是消息代理僅僅是中間件世界中的一小部分而已。隊(duì)列本身是很合理、很有用的東西。需要謹(jǐn)記一個(gè)原則:盡量讓中間件保持簡(jiǎn)單,而把業(yè)務(wù)邏輯放在自己的服務(wù)中。 另一種方法時(shí)使用HTTP來(lái)傳播事件。ATOM是一個(gè)符合REST規(guī)范的協(xié)議,可以通過(guò)他提供資源聚合的發(fā)布服務(wù),而且有很多現(xiàn)成的客戶端可以用來(lái)消費(fèi)該聚合。另一方面ATOM規(guī)范和與之相關(guān)的庫(kù)用起來(lái)非常便捷,而且HTTP能夠很好的處理伸縮性。但HTTP不擅長(zhǎng)處理低延遲的場(chǎng)景,而且使用ATOM的話,用戶還需要自己追蹤消息是否送達(dá)及管理輪詢等工作。 4.8.2異步架構(gòu)的復(fù)雜性 事件驅(qū)動(dòng)機(jī)制的系統(tǒng)看起來(lái)耦合非常低,而且伸縮性很好,但是這樣的編程風(fēng)格會(huì)帶來(lái)一定的復(fù)雜性,這種復(fù)雜性并不僅僅包括對(duì)消息的發(fā)布訂閱操作。例如一個(gè)非常耗時(shí)的異步請(qǐng)求/響應(yīng),需要考慮響應(yīng)返回時(shí)需要怎么處理,該響應(yīng)是否回到發(fā)送請(qǐng)求的那個(gè)節(jié)點(diǎn)?如果是的話,節(jié)點(diǎn)服務(wù)停止了怎么辦?如果不是的話,是否需要把信息實(shí)現(xiàn)存儲(chǔ)到某個(gè)比其他地方,以便于做相應(yīng)的處理?如果API設(shè)計(jì)的好的話娿,短生命周期的異步操作還是比較容易管理的,但盡管如此,對(duì)于習(xí)慣了進(jìn)程間同步使用的程序員來(lái)說(shuō),使用異步模式也需要思維上的轉(zhuǎn)換。 需要考慮: 限制重試次數(shù); 所有失敗的消息需要存儲(chǔ)在一個(gè)失敗隊(duì)列中。 需要界面展現(xiàn)失敗隊(duì)列中的消息; · 事件驅(qū)動(dòng)架構(gòu)和異步編程會(huì)帶來(lái)一定的復(fù)雜性,所以通常需要謹(jǐn)慎的選擇這種技術(shù)。如果使用該技術(shù),需要確保各個(gè)流程有很好的監(jiān)控機(jī)制,并考慮使用關(guān)聯(lián)ID,這種機(jī)制可以幫助你對(duì)跨進(jìn)程的請(qǐng)求進(jìn)行跟蹤。 4.9服務(wù)及狀態(tài)機(jī) 不管選用REST還是SOAP的RCP機(jī)制,服務(wù)即狀態(tài)機(jī)的概念都很強(qiáng)大,服務(wù)應(yīng)該根據(jù)限界上下文進(jìn)行劃分。我們的客戶微服務(wù)應(yīng)該擁有與這個(gè)上下文中行為相關(guān)的所有邏輯。 當(dāng)消費(fèi)者想要對(duì)客戶做修改時(shí),它會(huì)向客戶服務(wù)發(fā)送一個(gè)合適的請(qǐng)求。客戶服務(wù)根據(jù)自己的邏輯決定是否接受該請(qǐng)求。客戶服務(wù)控制了所有與客戶生命周期相關(guān)的事件。 我們要避免簡(jiǎn)單的對(duì)CRUD進(jìn)行封裝的貧血服務(wù),如果出現(xiàn)了在客戶服務(wù)之外與其進(jìn)行相關(guān)的修改的情況,那么你就失去了內(nèi)聚性。 把關(guān)鍵領(lǐng)域的生命周期顯示建模出來(lái)非常有用。我們不但可以再位移的一個(gè)地方處理狀態(tài)沖突,而且可以在這些狀態(tài)變化的基礎(chǔ)上封裝一些行為。 可以認(rèn)為基于HTTP的REST相比其他集成技術(shù)更合理,但是不管你選擇什么技術(shù),都要記住上面的原則。 4.10響應(yīng)式擴(kuò)展 響應(yīng)式擴(kuò)展提供了一種機(jī)制,在此之上,你可以把多個(gè)調(diào)用的結(jié)果組裝起來(lái)并在此基礎(chǔ)上執(zhí)行操作。調(diào)用本身可以是阻塞或者非阻塞的。響應(yīng)式擴(kuò)展改變了傳統(tǒng)的流程,以往我們會(huì)獲取一些數(shù)據(jù),然后基于此進(jìn)行操作,現(xiàn)在可以做的是簡(jiǎn)單的對(duì)操作的結(jié)果進(jìn)行觀察,結(jié)果會(huì)根據(jù)相關(guān)數(shù)據(jù)的改變自動(dòng)更新。 很多響應(yīng)式擴(kuò)展實(shí)現(xiàn)都在分布式系統(tǒng)中,因?yàn)檎{(diào)用的細(xì)節(jié)被屏蔽了,所以事情也更容易處理,我們可以簡(jiǎn)單地對(duì)下游服務(wù)調(diào)用的結(jié)果進(jìn)行觀察,而不需要關(guān)心它是阻塞還是非阻塞的,唯一需要做的就是等待結(jié)果并作出響應(yīng)。其優(yōu)點(diǎn)在于,我可以把多個(gè)不同的調(diào)用組合起來(lái),這樣就可以更容易的對(duì)下游服務(wù)的并發(fā)調(diào)用做處理。 4.11微服務(wù)世界中的DRY和代碼重用的危險(xiǎn) 微服務(wù)系統(tǒng)中應(yīng)該避免系統(tǒng)行為和知識(shí)的重復(fù)。如果有相同的代碼干同樣的事情,那么代碼就會(huì)變大的越來(lái)越大,從而降低可維護(hù)性。 使用DRY可以得到重復(fù)性比較好的代碼。如果隨意創(chuàng)建可用的代碼庫(kù),在微服務(wù)中進(jìn)行服用,對(duì)微服務(wù)系統(tǒng)來(lái)說(shuō)可能比較危險(xiǎn)。 我們需要避免消費(fèi)者和提供者之前的代碼耦合,否則對(duì)微服務(wù)任何小的改動(dòng)都會(huì)引起消費(fèi)者的改動(dòng)。而 代碼庫(kù)就有可能引入這種耦合。 跨服務(wù)公用代碼庫(kù)很有可能會(huì)引入耦合。但使用類似日志庫(kù)這樣的公共代碼就沒(méi)有什么問(wèn)題。 經(jīng)驗(yàn)是:在微服務(wù)內(nèi)部不用違反DRY,但在跨服務(wù)的情況下可以適當(dāng)范圍DRY。服務(wù)之間引入大量的耦合會(huì)比重復(fù)代碼帶來(lái)更糟糕的問(wèn)題。 4.12按引用訪問(wèn) 如何傳遞領(lǐng)域?qū)嶓w的相關(guān)信息是一個(gè)值得討論的問(wèn)題?可以遵守一個(gè)原則:即A服務(wù)應(yīng)該是關(guān)于A服務(wù)的唯一可靠來(lái)源。 使用資源的URI,例如客戶端訂單的通知郵件,在郵件中可以發(fā)送關(guān)于訂單的URI,而不是具體的訂單信息,防止在發(fā)送郵件后,訂單發(fā)生了改變而導(dǎo)致訂單不是最新的數(shù)據(jù)。 當(dāng)然在使用引用時(shí)也需要做一些取舍。如果總是從客戶服務(wù) 去查詢給定客戶的相關(guān)信息,那么客戶服務(wù)的負(fù)載會(huì)變大,如果在獲得資助的同事,可以得到資源的有效性時(shí)限信息的話,就可以進(jìn)行相應(yīng)的換粗,從而減少服務(wù)的負(fù)載,HTTP在緩存控制方面提供了很多現(xiàn)場(chǎng)的支持。 4.13版本管理 每次提及微服務(wù)的是偶,需要考慮如果進(jìn)行版本管理。 4.13.1盡可能推遲 減少破壞性修改影響的最好辦法就是盡量不要做這樣的修改。比如數(shù)據(jù)庫(kù)集成很容易引入破壞性的修改。使用REST就是很好的辦法,因?yàn)閷?duì)于內(nèi)部的實(shí)現(xiàn)的修改不太容易引起服務(wù)接口的變化。 另一種延遲破壞性修改的關(guān)鍵是鼓勵(lì)客戶端的正確行為,避免過(guò)早的將客戶端和服務(wù)端緊密綁定起來(lái)。 客戶端盡可能靈活的消費(fèi)服務(wù)響應(yīng)應(yīng)該符合Postel法則,該法則認(rèn)為,系統(tǒng)中每個(gè)模塊都應(yīng)該“寬進(jìn)嚴(yán)出”,即對(duì)自己發(fā)送的東西要嚴(yán)格,對(duì)接收的東西則要寬容。在請(qǐng)求/響應(yīng)的場(chǎng)景下,該原則可以幫助我們?cè)诜?wù)發(fā)送改變時(shí),減少消費(fèi)方的修改。 4.13.2及早發(fā)現(xiàn)破壞性的修改 及早發(fā)現(xiàn)對(duì)消費(fèi)者產(chǎn)生【破壞的修改非常重要,因?yàn)榧词故褂米詈玫募夹g(shù),也很難避免破壞性修改的出現(xiàn)。 最好的方式是使用消費(fèi)者驅(qū)動(dòng)的契約來(lái)及早定位這些問(wèn)題。 4.13.3使用語(yǔ)義化的版本管理 如果一個(gè)客戶端能夠僅僅通過(guò)查詢服務(wù)的版本號(hào),就知道他是否能夠與之進(jìn)行對(duì)接,那就是最好的。“語(yǔ)義化版本管理”就是一種能夠支持這樣方式的規(guī)則說(shuō)明。 "語(yǔ)義話版本管理"的每個(gè)版本號(hào)都遵守這樣的格式:major.minor.patch。其中major的改變意味著其中包含向后不兼容的修改;minor的改變意味著有新功能的增加,但應(yīng)該是向后兼容的;patch的改變代表對(duì)已有功能的缺陷修復(fù)。 4.13.4不同的接口共存 如果已經(jīng)做了所有可以做的事情來(lái)避免對(duì)接口的修改,那么下一步的任務(wù)就是限制其影響。我們不想強(qiáng)迫客戶端跟隨服務(wù)端一起升級(jí),因?yàn)橄到y(tǒng)微服務(wù)可以獨(dú)立于彼此進(jìn)行發(fā)布。我們使用過(guò)的一種成功的方式就是:在同一個(gè)服務(wù)商使用新接口和老接口同時(shí)存在。所以在發(fā)布一個(gè)破壞性修改是,可以部署一個(gè)同時(shí)包含新老接口的版本。 4.13.5同時(shí)使用多個(gè)版本的服務(wù) 另一種經(jīng)常被提起的版本管理方法時(shí)同時(shí)運(yùn)行不同版本的服務(wù),然后把老用于路由到老版本的服務(wù),而新服務(wù)可以看到新版本的服務(wù)。 缺點(diǎn)是如果要修復(fù)一個(gè)內(nèi)部bug,需要修復(fù)兩個(gè)版本,并做兩次部署。而且可能需要在代碼庫(kù)中拉取分支,這個(gè)也會(huì)引起很多問(wèn)題。其次吧用戶路由到正確的服務(wù)中也是一件比較復(fù)雜的事情。最后不同版本的服務(wù)的持久化問(wèn)題,不同版本的服務(wù)如果都存儲(chǔ)到同一個(gè)數(shù)據(jù)庫(kù)中,并且他們對(duì)不同的服務(wù)均課件,這可能引入更多的復(fù)雜性。 短期內(nèi)同時(shí)使用兩個(gè)不同版本的服務(wù)時(shí)合理的,尤其是當(dāng)你做藍(lán)綠部署或者金絲雀發(fā)布時(shí)。在這些情況下,不同版本的服務(wù)可能共同存在幾分鐘或者幾小時(shí),而且一般只會(huì)有兩個(gè)版本。 4.14用戶界面 4.15與第三方軟件集成 第一個(gè)你的組織對(duì)軟件的需求幾乎不可能完全有內(nèi)部滿足。 第二個(gè)事都自己組織開發(fā)的話效率非常低。 如果考慮一個(gè)軟件是否自己開發(fā):如果某個(gè)軟件非常棒,并且它是你的戰(zhàn)略性資產(chǎn)的話,那就自己構(gòu)建,如果不是這么特別的話,那就購(gòu)買。 4.15.1缺乏控制 類似使用CMS或者SAAS這樣的產(chǎn)品時(shí),如果與之進(jìn)行集成對(duì)其進(jìn)行擴(kuò)展,因?yàn)榇蟛糠值募夹g(shù)都不受你的控制。這些都需要依賴于廠家所做的決定。 4.15.2定制化 很多企業(yè)的工具都聲稱可以做深度的定制化。一定要小心。這些定制化會(huì)非常昂貴。 4.15.3意大利面式的集成 另一個(gè)挑戰(zhàn)是如何與工具進(jìn)行集成,服務(wù)間的集成是一件非常重要的事情。 4.15.4在自己可控的平臺(tái)進(jìn)行定制化 可以使用定制化軟件所提供的API進(jìn)行集成。 4.15.5絞殺者模式 絞殺者模式可以捕獲并攔截對(duì)老系統(tǒng)的調(diào)用。
轉(zhuǎn)載于:https://www.cnblogs.com/use-D/p/9912456.html
總結(jié)
- 上一篇: 微信小游戏视频激励广告onClose接口
- 下一篇: App启动流程