互聯(lián)網(wǎng)架構(gòu):屢試不爽的架構(gòu)三馬車(chē)_第1頁(yè)
互聯(lián)網(wǎng)架構(gòu):屢試不爽的架構(gòu)三馬車(chē)_第2頁(yè)
互聯(lián)網(wǎng)架構(gòu):屢試不爽的架構(gòu)三馬車(chē)_第3頁(yè)
互聯(lián)網(wǎng)架構(gòu):屢試不爽的架構(gòu)三馬車(chē)_第4頁(yè)
互聯(lián)網(wǎng)架構(gòu):屢試不爽的架構(gòu)三馬車(chē)_第5頁(yè)
已閱讀5頁(yè),還剩8頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

互聯(lián)網(wǎng)架構(gòu):屢試不爽的架構(gòu)三馬車(chē)這里所說(shuō)的三架馬車(chē)是指微服務(wù)、消息隊(duì)列和定時(shí)任務(wù)。如下圖所示,這里是一個(gè)三駕馬車(chē)共同驅(qū)動(dòng)的一個(gè)立體的互聯(lián)網(wǎng)項(xiàng)目的架構(gòu)。不管項(xiàng)目是大是小,這個(gè)架構(gòu)模板的形態(tài)一旦定型了之后就不太會(huì)變,區(qū)別只是我們有更多的服務(wù)有更復(fù)雜的調(diào)用,更復(fù)雜的消息流轉(zhuǎn),更多的Job,整個(gè)架構(gòu)整體是可擴(kuò)展的,而且不會(huì)變形,這個(gè)架構(gòu)可以在很長(zhǎng)的一段時(shí)間內(nèi)無(wú)需有大的調(diào)整。圖上畫(huà)了虛線(xiàn)框的都代表這個(gè)模塊或項(xiàng)目是不包含太多業(yè)務(wù)邏輯的,純粹是一層皮(會(huì)調(diào)用服務(wù)但是不會(huì)觸碰數(shù)據(jù)庫(kù))。黑色線(xiàn)的箭頭代表依賴(lài)關(guān)系,綠色和紅色箭頭分別是MQ的發(fā)送和訂閱消息流的方向。具體在后文都會(huì)進(jìn)一步詳細(xì)說(shuō)明。微服務(wù)微服務(wù)并不是一個(gè)很新的概念,在10年前的時(shí)候我就開(kāi)始實(shí)踐這個(gè)架構(gòu)風(fēng)格,在四個(gè)公司的項(xiàng)目中全面實(shí)現(xiàn)了微服務(wù),越來(lái)越堅(jiān)信這是非常適合互聯(lián)網(wǎng)項(xiàng)目的一個(gè)架構(gòu)風(fēng)格。不是說(shuō)我們的服務(wù)一定要跨物理機(jī)器進(jìn)行遠(yuǎn)程調(diào)用,而是我們通過(guò)進(jìn)行有意的設(shè)計(jì)讓我們的業(yè)務(wù)在一開(kāi)始的時(shí)候就按照領(lǐng)域進(jìn)行分割,這能讓我們對(duì)業(yè)務(wù)有更充分的理解,能讓我們?cè)谥蟮牡休p易在不同的業(yè)務(wù)模塊上進(jìn)行耕耘,能讓我們的項(xiàng)目開(kāi)發(fā)越來(lái)越輕松,輕松于幾個(gè)方面:1.

如果我們能進(jìn)行微服務(wù)化,那么我們一定事先經(jīng)過(guò)比較完善的產(chǎn)品需求討論和領(lǐng)域劃分,每一個(gè)服務(wù)精心設(shè)計(jì)自己領(lǐng)域內(nèi)的表結(jié)構(gòu),這是一個(gè)很重要的設(shè)計(jì)過(guò)程,也決定了整個(gè)技術(shù)架構(gòu)和產(chǎn)品架構(gòu)是匹配的,對(duì)于All-In-One的架構(gòu)往往會(huì)省略這一過(guò)程,需求到哪里代碼寫(xiě)到哪里。2.

我們對(duì)服務(wù)的劃分和職責(zé)的定位如果是清晰的,對(duì)于新的需求,我們就能知道需要在哪里改怎么樣的代碼,沒(méi)有復(fù)制粘貼的存在少了很多坑。3.

我們大多數(shù)的業(yè)務(wù)邏輯已經(jīng)開(kāi)發(fā)完畢,直接重用即可,我們的新業(yè)務(wù)只是現(xiàn)有邏輯的聚合。在PRD評(píng)審后,開(kāi)發(fā)得到的結(jié)論是只需要組合分別調(diào)用ABC三個(gè)服務(wù)的XYZ方法,然后在C服務(wù)中修改一下Z方法增加一個(gè)分支邏輯,就可以構(gòu)建起新的邏輯,這種爽快的感覺(jué)難以想象。4.

在性能存在明顯瓶頸的時(shí)候,我們可以針對(duì)性地對(duì)某些服務(wù)增加更多機(jī)器進(jìn)行擴(kuò)容,而且因?yàn)榉?wù)的劃分,我們更清楚系統(tǒng)的瓶頸所在,從10000行代碼定位到一行性能存在問(wèn)題的代碼是比較困難的,但是如果這10000行代碼已經(jīng)是由10個(gè)服務(wù)構(gòu)成的,那么先定位到某個(gè)服務(wù)存在性能問(wèn)題然后再針對(duì)這個(gè)服務(wù)進(jìn)行分析一下子降低了定位問(wèn)題的復(fù)雜度。5.

如果業(yè)務(wù)有比較大的變動(dòng)需要下線(xiàn),那么我們可以肯定的是底層的公共服務(wù)是不會(huì)淘汰的,下線(xiàn)對(duì)應(yīng)業(yè)務(wù)的聚合業(yè)務(wù)服務(wù)停掉流量入口,然后下線(xiàn)相關(guān)涉及到的基礎(chǔ)服務(wù)進(jìn)行部分接口即可。如果擁有完善的服務(wù)治理平臺(tái),整個(gè)操作甚至無(wú)需改動(dòng)代碼。這里也要求我們做到幾個(gè)方面的原則:1.

服務(wù)的粒度劃分需要把控好。我的習(xí)慣是先按照領(lǐng)域來(lái)分不會(huì)錯(cuò),隨著項(xiàng)目的進(jìn)展慢慢進(jìn)行更細(xì)粒度的拆分。比如對(duì)于互聯(lián)網(wǎng)金融P2P業(yè)務(wù),一開(kāi)始可以分為:a三方合作服務(wù)PartnerInvestService:對(duì)接合作的三方理財(cái)平臺(tái)的流量b普通投資服務(wù)NormalInvestService:最普通形態(tài)的資產(chǎn)的主流程c預(yù)約投資產(chǎn)品服務(wù)ReserveInvestService:需要預(yù)約投資的資產(chǎn)的主流程d周期性計(jì)劃產(chǎn)品服務(wù)AutoInvestService:會(huì)定期自動(dòng)復(fù)投的理財(cái)產(chǎn)品主流程e投資人交易服務(wù)TradeService:專(zhuān)門(mén)負(fù)責(zé)處理投資人的交易行為,比如投資f借款人交易服務(wù)LoanService:專(zhuān)門(mén)負(fù)責(zé)處理借款人的交易行為,比如還款g用戶(hù)服務(wù)UserService:處理用戶(hù)的注冊(cè)登錄等h資產(chǎn)服務(wù)ProjectService:處理資產(chǎn)和標(biāo)的相關(guān)i賬戶(hù)賬務(wù)服務(wù)AccountService:處理用戶(hù)的賬戶(hù)各個(gè)子賬戶(hù)和賬務(wù)記錄j營(yíng)銷(xiāo)活動(dòng)服務(wù)ActivityService:處理各種活動(dòng)、用戶(hù)的積分體系k會(huì)員體系服務(wù)VipService:處理用戶(hù)的會(huì)員成長(zhǎng)體系l銀行存管服務(wù)BankService:專(zhuān)門(mén)用于對(duì)接銀行存管系統(tǒng)m電子簽章服務(wù)DigSignService:專(zhuān)門(mén)用于對(duì)接三方數(shù)字簽章系統(tǒng)n消息推送服務(wù)MessageService:專(zhuān)門(mén)用于對(duì)接三方短信通道和推送SDK2.

服務(wù)一定是立體的,不是在一個(gè)層次上的,如上圖,我們的服務(wù)有三個(gè)層次:

聚合業(yè)務(wù)服務(wù):高層次的串起來(lái)整個(gè)流程的具有完整業(yè)務(wù)形態(tài)的業(yè)務(wù)服務(wù)。和基礎(chǔ)業(yè)務(wù)服務(wù)不同的是,這里是在完整描述一方面的業(yè)務(wù),這個(gè)業(yè)務(wù)往往是由各種基礎(chǔ)業(yè)務(wù)拼裝組合起來(lái)的。和不同外部合作方的不同合作形式,給用戶(hù)提供的產(chǎn)品的不同服務(wù)形態(tài),都決定了聚合業(yè)務(wù)服務(wù)會(huì)有業(yè)務(wù)流程上的差異化,如果把此類(lèi)服務(wù)下放到基礎(chǔ)業(yè)務(wù)服務(wù)中,那么基礎(chǔ)業(yè)務(wù)服務(wù)會(huì)有各種if-else邏輯(根據(jù)產(chǎn)品類(lèi)型、用戶(hù)類(lèi)型進(jìn)行各種if-else),隨著業(yè)務(wù)的合作不合作,需求變動(dòng),基礎(chǔ)業(yè)務(wù)服務(wù)會(huì)腐化得很厲害,為了避免這個(gè)情況,我們把變動(dòng)的多的聚合業(yè)務(wù)邏輯放到獨(dú)立的業(yè)務(wù)服務(wù)中。一般而言,聚合業(yè)務(wù)服務(wù)因?yàn)榇砹霜?dú)立的業(yè)務(wù)流程,它們之間是不會(huì)進(jìn)行相互調(diào)用的,但是它們一定會(huì)調(diào)用大量的各類(lèi)基礎(chǔ)業(yè)務(wù)服務(wù)。在第一點(diǎn)里說(shuō)的標(biāo)有藍(lán)色字體的a~d這些服務(wù)都是此類(lèi)服務(wù)。這個(gè)層次的服務(wù)的業(yè)務(wù)邏輯更多是在表達(dá)業(yè)務(wù)流程的復(fù)雜性和差異性,不會(huì)涉及到具體怎么處理賬戶(hù)信息、賬務(wù)信息、用戶(hù)信息,不會(huì)涉及到怎么處理具體的投資人和借款人的交易。比如對(duì)于預(yù)約這類(lèi)業(yè)務(wù)形態(tài),它關(guān)注的是先要預(yù)約資產(chǎn),然后再由系統(tǒng)進(jìn)行自動(dòng)投資,底層完全依賴(lài)于投資人交易服務(wù)來(lái)做整個(gè)交易的過(guò)程。基礎(chǔ)業(yè)務(wù)服務(wù):某一個(gè)領(lǐng)域業(yè)務(wù)相關(guān)的服務(wù)。此類(lèi)服務(wù)之間是允許相互調(diào)用的,比如投資人交易服務(wù)和借款人交易服務(wù)免不了需要和用戶(hù)服務(wù)、資產(chǎn)服務(wù)、賬戶(hù)賬務(wù)服務(wù)進(jìn)行通訊做相關(guān)的用戶(hù)信息查詢(xún)、標(biāo)的信息查詢(xún)、記賬等業(yè)務(wù)操作。之所以投資人交易服務(wù)和借款人交易服務(wù)定位為基礎(chǔ)業(yè)務(wù)服務(wù)是因?yàn)?,它們處理的是還是某一個(gè)具體方面的業(yè)務(wù),并不是全流程,在這個(gè)抽象層次上,業(yè)務(wù)不是那么容易變動(dòng)的,對(duì)于復(fù)雜的各種業(yè)務(wù)形態(tài)(比如預(yù)約交易、自動(dòng)復(fù)投交易、等額本息交易)會(huì)在這些服務(wù)之上形成聚合業(yè)務(wù)服務(wù)。在第一點(diǎn)里說(shuō)的標(biāo)有綠色字體的e~k這些服務(wù)都是此類(lèi)服務(wù)。在這個(gè)層次的服務(wù)雖然擁有大量的業(yè)務(wù)邏輯,但是其實(shí)已經(jīng)享受到了很大層度的公共基礎(chǔ)服務(wù)的重用了,而且和自己業(yè)務(wù)耦合較弱的額外邏輯往往沒(méi)有在本服務(wù)中堆積,由更多專(zhuān)職的基礎(chǔ)業(yè)務(wù)服務(wù)來(lái)承擔(dān)了這部分邏輯。公共基礎(chǔ)服務(wù):負(fù)責(zé)某一個(gè)方面的基礎(chǔ)業(yè)務(wù)(沒(méi)有什么領(lǐng)域業(yè)務(wù)邏輯在里面),可以是自治的處理某一個(gè)方面的基礎(chǔ)業(yè)務(wù),也可以和外部通訊實(shí)現(xiàn)某一個(gè)方面的功能,服務(wù)之間是不會(huì)相互調(diào)用的,但是會(huì)被聚合業(yè)務(wù)服務(wù)和基礎(chǔ)業(yè)務(wù)服務(wù)調(diào)用。在第一點(diǎn)里說(shuō)的標(biāo)有橙色字體的l~n這些服務(wù)都是此類(lèi)服務(wù)。如果以后和外部的合作有變動(dòng),因?yàn)槲覀円呀?jīng)定義了對(duì)外的服務(wù)契約,可以輕易替換這個(gè)服務(wù)來(lái)更換合作的第三方,系統(tǒng)其余的地方幾乎不需要修改。所有的三方對(duì)接都建議獨(dú)立出公共基礎(chǔ)服務(wù),如果同一個(gè)業(yè)務(wù)對(duì)接多個(gè)三方渠道,比如推送對(duì)接了極光和個(gè)推,甚至公共基礎(chǔ)服務(wù)還可以由一個(gè)抽象聚合的推送服務(wù),下面再路由到具體的極光推送和個(gè)推推送服務(wù)。希望在這里把這個(gè)事情說(shuō)清楚了,怎么來(lái)劃分服務(wù)怎么劃分三個(gè)層次的服務(wù)是一個(gè)很有意思很有必要的事情,在服務(wù)劃分之后最好有一個(gè)明確的文檔來(lái)描述每一個(gè)服務(wù)的職責(zé),這樣我們?cè)跓o(wú)需閱讀API的情況下可以大概定位到業(yè)務(wù)所在的服務(wù),整個(gè)復(fù)雜的系統(tǒng)就變得很直白了。搜索公眾號(hào)后端架構(gòu)師后臺(tái)回復(fù)“面試”,獲取一份驚喜禮包。3.每一個(gè)服務(wù)對(duì)接的底層數(shù)據(jù)表是獨(dú)立的沒(méi)有交叉關(guān)聯(lián)的,也就是數(shù)據(jù)結(jié)構(gòu)是不直接對(duì)外的,需要使用其他服務(wù)的數(shù)據(jù)一定通過(guò)訪(fǎng)問(wèn)接口進(jìn)行。好處也就是面向?qū)ο笤O(shè)計(jì)中封裝的好處:可以很方便地重構(gòu)底層的數(shù)據(jù)結(jié)構(gòu)甚至是數(shù)據(jù)源,只要接口不變,外部不會(huì)感知到。性能有問(wèn)題的情況下需要加緩存、分表、拆庫(kù)、歸檔是比較方便的事情,畢竟數(shù)據(jù)源沒(méi)有外部依賴(lài)。

說(shuō)白了就是我的數(shù)據(jù)我做主,我想怎么搞外面管不著,在重構(gòu)或是做一些高層次技術(shù)架構(gòu)(比如異地多活)的時(shí)候,沒(méi)有底層數(shù)據(jù)被依賴(lài),這太重要了。當(dāng)然,壞處或是麻煩的地方就是跨服務(wù)的調(diào)用使得數(shù)據(jù)操作無(wú)法在一個(gè)數(shù)據(jù)庫(kù)事務(wù)中完成,這并不是什么大問(wèn)題,一是因?yàn)槲覀冞@種拆分方式并不會(huì)讓粒度太細(xì),大部分的業(yè)務(wù)邏輯是在一個(gè)業(yè)務(wù)服務(wù)里完成的,二是后面會(huì)提到跨服務(wù)的調(diào)用不管是通過(guò)MQ進(jìn)行的還是直接調(diào)用進(jìn)行的,都會(huì)有補(bǔ)償來(lái)實(shí)現(xiàn)最終一致性。4.考慮到跨機(jī)器跨進(jìn)程調(diào)用服務(wù)穩(wěn)定性方面的顯著差異。在方法內(nèi)部進(jìn)行方法調(diào)用,我們需要考慮調(diào)用出現(xiàn)異常的情況,但是幾乎不需要考慮超時(shí)的情況,幾乎不需要考慮請(qǐng)求丟失的情況,幾乎不需要考慮重復(fù)調(diào)用的情況,對(duì)于遠(yuǎn)程服務(wù)調(diào)用,這些點(diǎn)都需要去重點(diǎn)考慮,否則系統(tǒng)整體就是基本可用,測(cè)試環(huán)境不出問(wèn)題,但是到了線(xiàn)上問(wèn)題百出的狀態(tài)。這就要求對(duì)于每一個(gè)服務(wù)的提供和調(diào)用多問(wèn)幾個(gè)上面的問(wèn)題,細(xì)細(xì)考慮到因?yàn)榫W(wǎng)絡(luò)問(wèn)題方法沒(méi)有執(zhí)行多次執(zhí)行或部分執(zhí)行的情況:我們?cè)趯?duì)外提供服務(wù)的時(shí)候,不但要告知用戶(hù)服務(wù)提供的業(yè)務(wù)能力,還要告知用戶(hù)服務(wù)的特性,比如是否是冪等的(對(duì)于訂單類(lèi)型的操作服務(wù),相同的訂單相同的操作強(qiáng)烈建議是冪等的,這樣調(diào)用方可以放心進(jìn)行重試或補(bǔ)償);是否需要外部進(jìn)行補(bǔ)償(在這里你可能說(shuō)為什么需要外部進(jìn)行補(bǔ)償,服務(wù)就不能自己補(bǔ)償嗎,對(duì)于內(nèi)部的子邏輯服務(wù)當(dāng)然可以自己補(bǔ)償,但是有的時(shí)候因?yàn)榫W(wǎng)絡(luò)原因請(qǐng)求就沒(méi)有到服務(wù)端,服務(wù)端一無(wú)所知這個(gè)調(diào)用當(dāng)然無(wú)從去補(bǔ)償);是否有頻控的限制;是否有權(quán)限的限制;降級(jí)后的處理方式等等。反過(guò)來(lái),我們調(diào)用其它服務(wù)也需要多問(wèn)幾句目標(biāo)服務(wù)的特性,針對(duì)性進(jìn)行設(shè)計(jì)相應(yīng)的補(bǔ)償邏輯、一致性處理邏輯和降級(jí)邏輯。我們必須考慮到有些時(shí)候并不是服務(wù)端的問(wèn)題,而是請(qǐng)求根本沒(méi)有到達(dá)服務(wù)端。服務(wù)本身往往也會(huì)有復(fù)雜的邏輯,作為客戶(hù)端的身份調(diào)用大量外部的服務(wù),所以服務(wù)端和客戶(hù)端的角色不是固定不變的,當(dāng)我們的服務(wù)內(nèi)部有許多客戶(hù)端來(lái)調(diào)用服務(wù)端的時(shí)候,對(duì)于每一個(gè)子邏輯我們都需要仔細(xì)考慮每一個(gè)環(huán)節(jié)。否正會(huì)出現(xiàn)的情況就是,這個(gè)服務(wù)是部分邏輯冪等的或是部分邏輯是具備最終一致性的。如果你說(shuō),這么多服務(wù),我在實(shí)現(xiàn)的時(shí)候很難考慮到這些點(diǎn),我完全不去考慮分布式事務(wù)、冪等性、補(bǔ)償(毫不夸張地說(shuō),有的時(shí)候我們花了20%的時(shí)間實(shí)現(xiàn)了業(yè)務(wù)邏輯,然后花80%的時(shí)間在實(shí)現(xiàn)這些可靠性方面的外圍邏輯),行不行?也不是不可以,那么業(yè)務(wù)在線(xiàn)上跑的時(shí)候一定會(huì)是千瘡百孔的,如果整個(gè)業(yè)務(wù)的處理對(duì)可靠性方面的要求不高或是業(yè)務(wù)不面向用戶(hù)不會(huì)受到投訴的話(huà),這部分業(yè)務(wù)的是可以暫時(shí)不考慮這些點(diǎn),但是諸如訂單業(yè)務(wù)這種核心的不允許有不一致性的業(yè)務(wù)還是需要全面考慮這些點(diǎn)的。5.

考慮到跨機(jī)器跨進(jìn)程調(diào)用服務(wù)數(shù)據(jù)傳輸方面的顯著差異。對(duì)于本地的方法調(diào)用,如果參數(shù)和返回值傳的是對(duì)象,那么對(duì)于大部分的語(yǔ)言來(lái)說(shuō),傳的是指針(或指針的拷貝),指針指向的是堆中分配的對(duì)象,對(duì)象在數(shù)據(jù)傳輸上的成本幾乎忽略不計(jì),也沒(méi)有序列化和反序列化的開(kāi)銷(xiāo)。對(duì)于跨進(jìn)程的服務(wù)調(diào)用,這個(gè)成本往往不能忽略不計(jì)。如果我們需要返回很多數(shù)據(jù),往往接口的定義需要進(jìn)行特殊的改造:通過(guò)使用分頁(yè)的形式,一次返回固定的少量數(shù)據(jù),客戶(hù)端按需拉取更多數(shù)據(jù)??梢栽趨?shù)中傳類(lèi)似于EnumSet的數(shù)據(jù)結(jié)構(gòu),讓客戶(hù)端告知服務(wù)端我需要什么層次的數(shù)據(jù),比如GetUserInfo接口可以提供給客戶(hù)端BasicInfo、VIPInfo、InvestData、RechargeData、WithdrawData,客戶(hù)端可以按需從服務(wù)端拿BasicInfo|VipInfo。6.

這里還引申出方法粒度的問(wèn)題,比如我們可以定義GetUserInfo通過(guò)傳入不用的參數(shù)來(lái)返回不同的數(shù)據(jù)組合,也可以分別定義GetUserBasicInfo、GetUserVIPInfo、GetUserInvestData等等細(xì)粒度的接口,接口的粒度定義取決于使用者會(huì)怎么來(lái)使用數(shù)據(jù),更趨向于一次使用單種類(lèi)型數(shù)據(jù)還是復(fù)合類(lèi)型的數(shù)據(jù)等等。7.

然后我們需要考慮接口升級(jí)的問(wèn)題,接口的改動(dòng)最好是兼容之前的接口,如果接口需要淘汰下線(xiàn),需要先確保調(diào)用方改造到了新接口,確保調(diào)用方流量為0觀察一段時(shí)間后方能從代碼下線(xiàn)老接口。一旦服務(wù)公開(kāi)出去,要進(jìn)行接口定義調(diào)整甚至下線(xiàn)往往就沒(méi)有這么容易了,不是自己說(shuō)了算了。所以對(duì)外API的設(shè)計(jì)需要慎重點(diǎn)。8.

最后不得不說(shuō),在整個(gè)公司都搞起了微服務(wù)后,跨部門(mén)的一些服務(wù)調(diào)用在商定API的時(shí)候難免會(huì)有一些扯皮的現(xiàn)象發(fā)生,到底是我傳給你呢還是你自己來(lái)拉,這個(gè)數(shù)據(jù)對(duì)我沒(méi)用為什么要在我這里留一下呢?拋開(kāi)非技術(shù)層面的事情不說(shuō),這些扯皮也是有一些技術(shù)手段來(lái)化解的:明確服務(wù)職責(zé),也就明確了服務(wù)應(yīng)該感知到什么不應(yīng)該感知到什么。跨部門(mén)的服務(wù)交互的接口定義可以定的很輕,采用只有一個(gè)訂單號(hào)的接口或MQ通知+數(shù)據(jù)回拉的策略(誰(shuí)數(shù)據(jù)多誰(shuí)提供數(shù)據(jù)接口,不用把數(shù)據(jù)一次性推給下游)。數(shù)據(jù)提供方可以構(gòu)建一套通用數(shù)據(jù)接口,這樣可以滿(mǎn)足多個(gè)部門(mén)的需求,無(wú)需做定制化的處理。甚至在接口上可以提供落地和不落地兩種性質(zhì)的透?jìng)?。你可能看到這里覺(jué)得很頭暈,為什么微服務(wù)需要額外考慮這么多東西,實(shí)現(xiàn)的復(fù)雜度一下子上升了。我想說(shuō)的是我們需要換一個(gè)角度來(lái)考慮這個(gè)事情:1.

我們不需要在一開(kāi)始的時(shí)候?qū)λ羞壿嫸歼M(jìn)行嚴(yán)密的考慮,先覆蓋核心流程核心邏輯。因?yàn)榭绶?wù)成為了服務(wù)的提供方和使用方,相當(dāng)于除了我自己,還有很多其它人會(huì)來(lái)關(guān)系我的服務(wù)能力,大家會(huì)提出各種問(wèn)題,這對(duì)設(shè)計(jì)一個(gè)可靠的方法是有好處的。2.

即使在不跨服務(wù)調(diào)用的時(shí)候我們把所有邏輯堆積在一起,也不意味著這些邏輯一定是事務(wù)性的,實(shí)現(xiàn)嚴(yán)密的,跨服務(wù)調(diào)用往往是一定程度放大了問(wèn)題產(chǎn)生的可能性。3.

我們還有服務(wù)框架呢,服務(wù)框架往往會(huì)在監(jiān)控跟蹤層次和運(yùn)維系統(tǒng)結(jié)合在一起提供很多一體化的功能,這將封閉在內(nèi)部的方法邏輯打散暴露出來(lái),對(duì)于有一個(gè)完善的監(jiān)控平臺(tái)的微服務(wù)系統(tǒng),在排查問(wèn)題的時(shí)候你往往會(huì)感嘆這是一個(gè)遠(yuǎn)程服務(wù)調(diào)用就好了。4.

最大的紅利還是之前說(shuō)的,當(dāng)我們以清晰的業(yè)務(wù)邏輯形成了一個(gè)立體化的服務(wù)體系之后,任何需求可以解剖為很少量的代碼修改和一些組合的服務(wù)調(diào)用,而且你知道我這么做是不會(huì)有任何問(wèn)題的,因?yàn)榈讓拥姆?wù)ABCDEFG都是經(jīng)過(guò)歷史考驗(yàn)的,這種爽快感體驗(yàn)過(guò)一次就會(huì)大呼過(guò)癮。但是,如果服務(wù)粒度劃分的不合理,層次劃分的不合理,底層數(shù)據(jù)源有交叉,沒(méi)考慮到網(wǎng)絡(luò)調(diào)用失敗,沒(méi)考慮到數(shù)據(jù)量,接口定義不合理,版本升級(jí)過(guò)于魯莽,整個(gè)系統(tǒng)會(huì)出各種各樣的擴(kuò)展問(wèn)題性能問(wèn)題和Bug,這是很頭痛的,這也就需要我們有一個(gè)完善的服務(wù)框架來(lái)幫助我們定位各種不合理,在之后說(shuō)到中間件的文章中會(huì)再具體著重介紹服務(wù)治理這塊。

消息隊(duì)列消息隊(duì)列MQ的使用有下面幾個(gè)好處,或者說(shuō)我們往往處于這些目的來(lái)考慮引入MQ:1.

異步處理:類(lèi)似于訂單這樣的流程一般可以定義出一個(gè)核心流程,這個(gè)流程用于處理核心訂單的狀態(tài)機(jī),需要盡快同步落庫(kù)完成,然后圍繞訂單會(huì)衍生出一系列和用戶(hù)相關(guān)的庫(kù)存相關(guān)的后續(xù)的業(yè)務(wù)處理,這些處理完全不需要卡在用戶(hù)點(diǎn)擊提交訂單的那剎那進(jìn)行處理。下單只是一個(gè)確認(rèn)合法受理訂單的過(guò)程,后續(xù)的很多事情都可以慢慢在幾十個(gè)模塊中進(jìn)行流轉(zhuǎn),這個(gè)流轉(zhuǎn)過(guò)程哪怕是消耗5分鐘,用戶(hù)也無(wú)需感受到。2.

流量洪峰:互聯(lián)網(wǎng)項(xiàng)目的一個(gè)特點(diǎn)是有的時(shí)候會(huì)做一些toC的促銷(xiāo),免不了有一些流量洪峰,如果我們引入了消息隊(duì)列在模塊之間作為緩沖,那么backend的服務(wù)可以以自己既有的舒服的頻次來(lái)被動(dòng)消耗數(shù)據(jù),不會(huì)被強(qiáng)壓的流量擊垮。當(dāng)然,做好監(jiān)控是必不可少的,下面再細(xì)說(shuō)一下監(jiān)控。3.

模塊解耦:隨著項(xiàng)目復(fù)雜度的上升,我們會(huì)有各種于項(xiàng)目?jī)?nèi)部和外部的事件(用戶(hù)注冊(cè)登陸、投資、提現(xiàn)事件等),這些重要事件可能不斷有各種各樣的模塊(營(yíng)銷(xiāo)模塊、活動(dòng)模塊)需要關(guān)心,核心業(yè)務(wù)系統(tǒng)去調(diào)用這些外部體系的模塊,讓整個(gè)系統(tǒng)在內(nèi)部糾纏在一起顯然是不合適的,這個(gè)時(shí)候通過(guò)MQ進(jìn)行解耦,讓各種各樣的事件在系統(tǒng)中進(jìn)行松耦合流轉(zhuǎn),模塊之間各司其職也相互沒(méi)有感知,這是比較適合的做法。4.

消息群發(fā):有一些消息是會(huì)有多個(gè)接收者的,接收者的數(shù)量還是動(dòng)態(tài)的(類(lèi)似指責(zé)鏈的性質(zhì)也是可能的),在這個(gè)時(shí)候如果上下游進(jìn)行一對(duì)多的耦合就會(huì)更麻煩,對(duì)于這種情況就更適用使用MQ進(jìn)行解耦了。上游只管發(fā)消息說(shuō)現(xiàn)在發(fā)生了什么事情,下游不管有多少人關(guān)心這個(gè)消息,上游都是沒(méi)有感知的。這些需求互聯(lián)網(wǎng)項(xiàng)目中基本都存在,所以消息隊(duì)列的使用是非常重要的一個(gè)架構(gòu)手段。在使用上有幾個(gè)注意點(diǎn):1.

我更傾向于獨(dú)立一個(gè)專(zhuān)門(mén)的listener項(xiàng)目(而不是合并在server中)來(lái)專(zhuān)門(mén)做消息的監(jiān)聽(tīng),然后這個(gè)模塊其實(shí)沒(méi)有過(guò)多的邏輯,只是在收到了具體的消息之后調(diào)用對(duì)應(yīng)的service中的API進(jìn)行消息處理。listener是可以啟動(dòng)多份做一個(gè)負(fù)載均衡的(取決于具體使用的MQ產(chǎn)品),但是因?yàn)檫@里幾乎沒(méi)有什么壓力,不是100%必須。注意,不是所有的service都是需要有一個(gè)配到的listener項(xiàng)目的,大多數(shù)公共基礎(chǔ)服務(wù)因?yàn)楸旧砗塥?dú)立不需要感知到外部的其它業(yè)務(wù)事件,所以往往是沒(méi)有l(wèi)istener的,基礎(chǔ)業(yè)務(wù)服務(wù)也有一些是類(lèi)似的原因不需要有l(wèi)istener。2.

對(duì)于重要的MQ消息,應(yīng)當(dāng)配以相應(yīng)的補(bǔ)償線(xiàn)作為備份,在MQ集群一切正常作為補(bǔ)漏,在MQ集群癱瘓的時(shí)候作為后背。我在日千萬(wàn)訂單的項(xiàng)目中使用過(guò)RabbitMQ,雖然QPS在幾百上千,遠(yuǎn)遠(yuǎn)低于RabbitMQ壓測(cè)下來(lái)能抗住的數(shù)萬(wàn)QPS,但是整體上有那么十萬(wàn)分之一的丟消息概率(我也用過(guò)阿里的RocketMQ,但是因?yàn)閱瘟枯^小目前沒(méi)有觀察到有類(lèi)似的問(wèn)題),這些丟掉的消息馬上會(huì)由補(bǔ)償線(xiàn)進(jìn)行處理了。在極端的情況下,RabbitMQ發(fā)生了整個(gè)集群宕機(jī),A服務(wù)發(fā)出的消息無(wú)法抵達(dá)B服務(wù)了,這個(gè)時(shí)候補(bǔ)償Job開(kāi)始工作,定期從A服務(wù)批量拉取消息提供給B服務(wù),雖然消息處理是一批一批的,但是至少確保了消息可以正常處理。做好這套后備是非常重要的,因?yàn)槲覀儫o(wú)法確保中間件的可用性在100%。3.

補(bǔ)償?shù)膶?shí)現(xiàn)是不帶任何業(yè)務(wù)邏輯的,我們?cè)偈崂硪幌卵a(bǔ)償這個(gè)事情。如果A服務(wù)是消息的提供者,B-listener是消息監(jiān)聽(tīng)器,聽(tīng)到消息后會(huì)調(diào)用B-server中具體的方法handleXXMessage(XXMessagemessage)來(lái)執(zhí)行業(yè)務(wù)邏輯,在MQ停止工作的時(shí)候,有一個(gè)Job(可配置補(bǔ)償時(shí)間以及每次拉取的量)來(lái)定期調(diào)用A服務(wù)提供的專(zhuān)有方法getXXMessages(LocalDateTimefrom,LocalDateTimeto,intbatchSize)來(lái)拉取消息,然后還是(可以并發(fā))調(diào)用B-server的那個(gè)handleXXMessage來(lái)處理消息。這個(gè)補(bǔ)償?shù)腏ob可以重用的可配置的,無(wú)需每次為每一個(gè)消息都手寫(xiě)一套,唯一需要多做的事情是A服務(wù)需要提供一個(gè)拉取消息的接口。那你可能會(huì)說(shuō),我A服務(wù)這里還需要維護(hù)一套基于數(shù)據(jù)庫(kù)的消息隊(duì)列嗎,這個(gè)不是自己搞一套基于被動(dòng)拉的消息隊(duì)列了嗎?其實(shí)這里的消息往往只是一個(gè)轉(zhuǎn)化工作,A一定在數(shù)據(jù)庫(kù)中有落地過(guò)去一段時(shí)間發(fā)生過(guò)變動(dòng)的數(shù)據(jù),只要把這些數(shù)據(jù)轉(zhuǎn)化為Message對(duì)象提供出去即可。B-server的handleXXMessage由于是冪等的,所以無(wú)所謂消息是否重復(fù)處理,這里只是在應(yīng)急情況下進(jìn)行無(wú)腦的過(guò)去一段時(shí)間的數(shù)據(jù)的依次處理。4.

所有消息的處理端最好對(duì)相同的消息處理實(shí)現(xiàn)冪等,即使有一些MQ產(chǎn)品支持消息處理且只處理一次,靠自己做好冪等能讓事情變得更簡(jiǎn)單。5.

有一些場(chǎng)景下有延遲消息或延遲消息隊(duì)列的需求,諸如RabbitMQ、RocketMQ都有不同的實(shí)現(xiàn)方式。6.

MQ消息一般而言有兩種,一種是(最好)只能被一個(gè)消費(fèi)者進(jìn)行消費(fèi)并且只消費(fèi)一次的,另一種是所有訂閱者都可以來(lái)處理,不限制人數(shù)。不用的MQ中間件對(duì)于這兩種形式都有不同的實(shí)現(xiàn),有的時(shí)候使用消息類(lèi)型來(lái)做,有的使用不同的交換機(jī)來(lái)做,有的是使用group的劃分來(lái)做(不同的group可以重復(fù)消息相同的消息)。一般來(lái)說(shuō)都是支持這兩種實(shí)現(xiàn)的。在使用具體產(chǎn)品的時(shí)候務(wù)必研究相關(guān)的文檔,做好實(shí)驗(yàn)確保這兩種消息是以正確的方式在處理,以免發(fā)生妖怪問(wèn)題。7.

需要做好消息監(jiān)控,最最重要的是監(jiān)控消息是否有堆積,有的話(huà)需要及時(shí)增強(qiáng)下游處理能力(加機(jī)器,加線(xiàn)程),當(dāng)然做的更好點(diǎn)可以以熱點(diǎn)拓?fù)鋱D繪制所有消息的流向流速一眼就可以看到目前哪些消息有壓力。你可能會(huì)想既然消息都在MQ體系中不會(huì)丟失,消息有堆積處理慢一點(diǎn)其實(shí)也沒(méi)什么問(wèn)題。是的,消息可以有適當(dāng)?shù)亩逊e,但是不能大量堆積,如果MQ系統(tǒng)出現(xiàn)存儲(chǔ)問(wèn)題,大量堆積的消息有丟失也是比較麻煩的,而且有一些業(yè)務(wù)系統(tǒng)對(duì)于消息的處理是看時(shí)間的,過(guò)晚到達(dá)的消息是會(huì)認(rèn)為業(yè)務(wù)違例進(jìn)行忽略的。8.

圖上畫(huà)了兩個(gè)MQ集群,一套對(duì)內(nèi)一套對(duì)外。原因是對(duì)內(nèi)的MQ集群我們?cè)跈?quán)限上控制可以相對(duì)弱點(diǎn),對(duì)外的集群必須明確每一個(gè)Topic,而且Topic需要由固定的人來(lái)維護(hù)不能在集群上隨意增刪Topic造成混亂。對(duì)內(nèi)對(duì)外的消息實(shí)現(xiàn)硬隔離對(duì)于性能也有好處,建議在生產(chǎn)環(huán)境把對(duì)內(nèi)對(duì)外的MQ集群進(jìn)行隔離劃分。定時(shí)任務(wù)定時(shí)任務(wù)的需求有那么幾類(lèi):1.

如之前所說(shuō),跨服務(wù)調(diào)用,MQ通知難免會(huì)有不可達(dá)的問(wèn)題,我們需要有一定的機(jī)制進(jìn)行補(bǔ)償。2.

有一些業(yè)務(wù)是基于任務(wù)表進(jìn)行驅(qū)動(dòng)的,有關(guān)任務(wù)表的設(shè)計(jì)下面會(huì)詳細(xì)說(shuō)明。3.

有一些業(yè)務(wù)是定時(shí)定期來(lái)進(jìn)行處理的,根本不需要實(shí)時(shí)進(jìn)行處理(比如通知用戶(hù)紅包即將過(guò)期,和銀行進(jìn)行日終對(duì)賬,給用戶(hù)出賬單等)。和2的區(qū)別在于,這里的任務(wù)的執(zhí)行時(shí)間和頻次是五花八門(mén)的,2的話(huà)一般而言是固定頻次的。詳細(xì)說(shuō)明一下任務(wù)驅(qū)動(dòng)是怎么一回事。其實(shí)在數(shù)據(jù)庫(kù)中做一些任務(wù)表,以這些表驅(qū)動(dòng)作為整個(gè)數(shù)據(jù)處理的核心體系,這套被動(dòng)的運(yùn)作方式是最最可靠的,比MQ驅(qū)動(dòng)或服務(wù)驅(qū)動(dòng)兩種形態(tài)可靠多,天生必然是可負(fù)載均衡的+冪等處理+補(bǔ)償?shù)降椎?,任?wù)表可以設(shè)計(jì)下面的字段:自增ID任務(wù)類(lèi)型:表明具體的任務(wù)類(lèi)型,當(dāng)然也可以不同的任務(wù)類(lèi)型直接做多個(gè)任務(wù)表。外部訂單號(hào):和外部業(yè)務(wù)邏輯的唯一單號(hào)關(guān)聯(lián)起來(lái)。執(zhí)行狀態(tài):未處理(等待處理),處理中(防止被其它Job搶占),成功(最終成功了),失?。〞簳r(shí)失敗,會(huì)繼續(xù)進(jìn)行重試),人工介入(永遠(yuǎn)不會(huì)再變了,一定需要人工處理,需要報(bào)警通知)重試次數(shù):處理過(guò)太多次還是失敗的可以歸類(lèi)為死信,由專(zhuān)門(mén)的死信隊(duì)列任務(wù)單獨(dú)再進(jìn)行若干次的重試不行的話(huà)就報(bào)警人工干預(yù)處理歷史:每一次的處理結(jié)果,Json的List保存在這里供參考上次處理時(shí)間:最近一次執(zhí)行時(shí)間上次處理結(jié)果:最近一次執(zhí)行結(jié)果創(chuàng)建時(shí)間:數(shù)據(jù)庫(kù)維護(hù)最后修改時(shí)間:數(shù)據(jù)庫(kù)維護(hù)除了這些字段之外,還可能會(huì)加一些業(yè)務(wù)自己的字段,比如訂單狀態(tài),用戶(hù)ID等等信息作為冗余。任務(wù)表可以進(jìn)行歸檔減少數(shù)據(jù)量,任務(wù)表扮演了消息隊(duì)列的性質(zhì),我們需要有監(jiān)控可以對(duì)數(shù)據(jù)積壓,出入隊(duì)不平衡處理不過(guò)來(lái),死信數(shù)據(jù)發(fā)生等等情況進(jìn)行報(bào)警。如果我們的流程處理是任務(wù)ABCD順序來(lái)處理的話(huà),每一個(gè)任務(wù)因?yàn)橛凶约旱臋z查間隔,這套體系可能會(huì)浪費(fèi)一點(diǎn)時(shí)間,沒(méi)有通過(guò)MQ實(shí)時(shí)串聯(lián)這么高效,但是我們要考慮到的是,任務(wù)的處理往往是批量數(shù)據(jù)獲取+并行執(zhí)行的,和MQ基于單條數(shù)據(jù)的處理是不一樣的,總體上來(lái)說(shuō)吞吐上不會(huì)有太多的差異,差的只是單條數(shù)據(jù)的執(zhí)行時(shí)間,考慮到任務(wù)表驅(qū)動(dòng)執(zhí)行的被動(dòng)穩(wěn)定性,對(duì)于有的業(yè)務(wù)來(lái)說(shuō),這不失為一種選擇。這里再說(shuō)明一下Job的幾個(gè)設(shè)計(jì)原則:1.

Job可以由各種調(diào)度框架來(lái)驅(qū)動(dòng),比如ElasticJob、Quartz等等,需要獨(dú)立項(xiàng)目處理,不能和服務(wù)混在一起,部署啟動(dòng)多份往往會(huì)有問(wèn)題。當(dāng)然,自己實(shí)現(xiàn)一個(gè)任務(wù)調(diào)度框架也不是很麻煩的事情,在執(zhí)行的時(shí)候來(lái)決定Job在哪臺(tái)機(jī)器來(lái)跑,讓整個(gè)集群的資源使用更合理。說(shuō)白了就是兩種形態(tài),一種是Job部署在那里由框架來(lái)觸發(fā),還有就是只是代碼在那里,由框架來(lái)起進(jìn)程。搜索公眾號(hào)后端架構(gòu)師后臺(tái)回復(fù)“架構(gòu)整潔”,獲取一份驚喜禮包。2.

Job項(xiàng)目只是一層皮,最多有一些配置的整合,不應(yīng)該有實(shí)際的業(yè)務(wù)邏輯,不會(huì)觸碰數(shù)據(jù)庫(kù),大部分情況就是在調(diào)用具體服務(wù)的API接口。Job項(xiàng)目就負(fù)責(zé)配置和頻次的控制。3.

補(bǔ)償類(lèi)的Job注意補(bǔ)償次數(shù),避免整個(gè)任務(wù)被死信數(shù)據(jù)卡住的問(wèn)題。三馬車(chē)都說(shuō)完了,那么,最后我們來(lái)梳理一下這么一套架構(gòu)下整個(gè)項(xiàng)目的模塊劃分:Site:frontconsoleapp-gatewayFa?adeService:partnerinvestservice-apipartnerinvestservice-serverpartnerinvestservice-listenernormalinvestservice-apinormalinvestservice-serverno

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論