RPC 用著好好的?為什么還需要使用 MQ?
本文轉(zhuǎn)載自微信公眾號「Java極客技術(shù)」,作者鴨血粉絲。轉(zhuǎn)載本文請聯(lián)系Java極客技術(shù)公眾號。
阿粉之前看了一場架構(gòu)師之路沈劍老師的一場直播,最近又重溫了一下,根據(jù)自己的認(rèn)知總結(jié)了一下,分享給大家。
MQ 想必大家或多或少都用過,接入 MQ 之后的整體架構(gòu)如下:
可以看到使用 MQ 之后,上下游通信就變成圖上的這種方式。
這種跨進程的通信方式,我們還有一種常用的解決方案,使用 Dubbo 等這類 RPC 服務(wù)。
理論上使用 RPC 的跨進程通信的場景,使用 MQ 也能解決,當(dāng)然反過來也能說通。
那為什么不都用 RPC,或者 MQ 來解決那?
這其實都是業(yè)務(wù)場景決定的,拋開業(yè)務(wù)場景來談架構(gòu)都是耍流氓!沒有全能的架構(gòu),只要適合的架構(gòu)。
下面我們來看看哪些場景適合 RPC,而哪些場景適合 MQ。
RPC 場景
使用 RPC 的場景一般都是上游服務(wù)需要實時依賴下游服務(wù)的返回。
我們以一個登錄服務(wù)為例,架構(gòu)圖如下:
用戶發(fā)起的登錄請求首先由對外的 WEB 服務(wù)接受,然后 WEB 服務(wù)服務(wù)調(diào)用用戶服務(wù)查詢用戶信息,然后比對用戶密碼。
也就是說我們的 WEB 應(yīng)用需要實時依賴用戶服務(wù)返回的用戶信息,如果沒有返回,這次登錄將會失敗。
假如這個場景我們用 MQ 代替, WEB 應(yīng)用發(fā)送 MQ 消息之后,然后流程就結(jié)束了,此時 WEB 應(yīng)用無法拿到用戶信息。
所以說對于這種需要強依賴下游返回的場景,使用 MQ 將會帶來以下不足:
- 上游無法直接得到下游結(jié)果
- 增加一個 MQ 組件,系統(tǒng)更復(fù)雜
MQ 場景
上游不關(guān)心下游結(jié)果的場景舉個例子,在我們第三方支付系統(tǒng)中,每支付成功一筆,都需要計算手續(xù)費。
這個場景我們顯然可以使用 RPC 完成調(diào)用,但是實際上,支付系統(tǒng)是不關(guān)心的計費系統(tǒng)的結(jié)果,兩個系統(tǒng)不存在直接強依賴的關(guān)系。
大家可以想象一下,用戶實際上已經(jīng)收到銀行卡扣款短信了,但是支付系統(tǒng)因為計費系統(tǒng)失敗,導(dǎo)致對外返回是失敗的結(jié)果。這對于用戶來講,不能接受啊。我都付錢了,你卻告訴我支付異常。
所以對于這種場景,直接使用 RPC 調(diào)用由以下幾點不足:
- 系統(tǒng)整體調(diào)用延時增加
- 下游服務(wù)異常,影響上游服務(wù)。兩者物理以及邏輯依賴嚴(yán)重
- 若后面再增加一個下游系統(tǒng),需要知道支付成功的結(jié)果,上游系統(tǒng)需要改動代碼。這種情況對于上游情況來講,就會很煩。明明與上游系統(tǒng)沒有什么關(guān)系,卻需要修改代碼。
那一定要用 MQ 解決嗎?
其實不一定,對于我們上面舉的場景,我們其實可以使用異步 RPC 或者線程池異步調(diào)用 RPC 就可以解決。
畢竟增加一個 MQ, 系統(tǒng)就變得更加復(fù)雜,我們還要單獨運維 MQ,這對于小團隊來講,工作量還是很大的。
但是這種方式,還是解決不了,增加一個下游系統(tǒng),上游系統(tǒng)還要改動的代碼囧境。
增加 MQ 解耦
這個場景使用 MQ 解耦,帶來幾點優(yōu)點:
- 任務(wù)一:上游系統(tǒng)執(zhí)行時間變短
- 任務(wù)二:上下游邏輯解耦,物理解耦
- 任務(wù)三:最重要一點,增加一個下游服務(wù),其只要訂閱即可,上游服務(wù)無需要改動代碼
數(shù)據(jù)驅(qū)動的定時任務(wù)場景舉個例子,支付公司每日都需要對賬,主要目的是核實自己系統(tǒng)的應(yīng)收的錢與支付渠道端是否一致,主要流程分為以下幾步:
定時任務(wù)下載渠道對賬文件,下載方式可能為 Http 接口下載,也有可能 SFTP 下載
定時任務(wù)解析對賬文件,然后將對賬數(shù)據(jù)入庫
定時任務(wù)將自己本端支付數(shù)據(jù)與對賬數(shù)據(jù)核對
上面的定時任務(wù)使用 Spring-Schedule 調(diào)度,假設(shè)各個定時任務(wù)下載時間如下所示:
上圖中三個任務(wù),任務(wù)二需要依賴任務(wù)一完成,而任務(wù)三又需要依賴任務(wù)二完成。
我們之前使用這種模式,通常會碰到幾個問題:
- 通常 06:00 就能下載到對賬文件,但是有時候渠道端對賬文件延遲,就會導(dǎo)致任務(wù)一執(zhí)行失敗,這樣就會后續(xù)兩個定時任務(wù)也會執(zhí)行失敗
- 假設(shè)任務(wù)二數(shù)據(jù)過多,執(zhí)行時間過長,任務(wù)三執(zhí)行時還沒結(jié)束,這就導(dǎo)致任務(wù)三無法拿到全量數(shù)據(jù),導(dǎo)致對賬異常
- 整體任務(wù)執(zhí)行時間過長
- 任務(wù)一若調(diào)整時間,可能導(dǎo)致任務(wù)二,任務(wù)三都需要調(diào)整時間
使用 MQ解耦
使用 MQ 解耦之后架構(gòu)圖如下:
這種方式,只要任務(wù)一的定時任務(wù)準(zhǔn)時啟動,任務(wù)一完成之后發(fā)送 MQ 消息,任務(wù)二收到之后就會啟動任務(wù),結(jié)束之后再發(fā)送消息給 MQ。任務(wù)三流程同任務(wù)二
使用這種方式存在優(yōu)點為:
- 下游任務(wù)只要收到消息就能立刻執(zhí)行,不需要額外等待,整體任務(wù)執(zhí)行時間變短
- 上游任務(wù)時間變動,無需修改下游任務(wù)時間。我們這個例子,只需要任務(wù)一的實際即可
總結(jié)
對于上游需要關(guān)注下游返回結(jié)果的場景,不適合使用 MQ。
適合使用 MQ 的場景有:
上游不關(guān)心下游結(jié)果的場景
數(shù)據(jù)驅(qū)動的定時任務(wù)依賴