一、MQ是干嘛的
消息總線(Message Queue)沙郭,后文稱MQ榴芳,是一種跨進程的通信機制嗡靡,用于上下游傳遞消息。
在互聯(lián)網架構中窟感,MQ是一種非常常見的上下游“邏輯解耦+物理解耦”的消息通信服務讨彼。
使用了MQ之后,消息發(fā)送上游只需要依賴MQ柿祈,邏輯上和物理上都不用依賴其他服務哈误。
二、什么時候不使用消息總線
既然MQ是互聯(lián)網分層架構中的解耦利器躏嚎,那所有通訊都使用MQ豈不是很好黑滴?
這是一個嚴重的誤區(qū)
,調用與被調用的關系紧索,是無法被MQ取代的。
MQ的不足是:
1)系統(tǒng)更復雜菜谣,多了一個MQ組件
2)消息傳遞路徑更長珠漂,延時會增加
3)消息可靠性和重復性互為矛盾,消息不丟不重難以同時保證
4)上游無法知道下游的執(zhí)行結果尾膊,這一點是很致命的
舉個栗子:用戶登錄場景媳危,登錄頁面調用passport服務,passport服務的執(zhí)行結果直接影響登錄結果冈敛,此處的“登錄頁面”與“passport服務”就必須使用調用關系待笑,而不能使用MQ通信。
無論如何抓谴,記住這個結論:調用方實時依賴執(zhí)行結果的業(yè)務場景暮蹂,請使用調用寞缝,而不是MQ。
三仰泻、什么時候使用MQ
【典型場景一:數據驅動的任務依賴】
什么是任務依賴荆陆,舉個栗子,互聯(lián)網公司經常在凌晨進行一些數據統(tǒng)計任務集侯,這些任務之間有一定的依賴關系被啼,比如:
1)task3需要使用task2的輸出作為輸入
2)task2需要使用task1的輸出作為輸入
這樣的話,tast1, task2, task3之間就有任務依賴關系棠枉,必須task1先執(zhí)行浓体,再task2執(zhí)行,載task3執(zhí)行辈讶。
對于這類需求命浴,常見的實現方式是,使用cron人工排執(zhí)行時間表:
1)task1荞估,0:00執(zhí)行咳促,經驗執(zhí)行時間為50分鐘
2)task2,1:00執(zhí)行(為task1預留10分鐘buffer)勘伺,經驗執(zhí)行時間也是50分鐘
3)task3跪腹,2:00執(zhí)行(為task2預留10分鐘buffer)
這種方法的壞處是:
1)如果有一個任務執(zhí)行時間超過了預留buffer的時間,將會得到錯誤的結果飞醉,因為后置任務不清楚前置任務是否執(zhí)行成功冲茸,此時要手動重跑任務,還有可能要調整排班表
2)總任務的執(zhí)行時間很長缅帘,總是要預留很多buffer轴术,如果前置任務提前完成,后置任務不會提前開始
3)如果一個任務被多個任務依賴钦无,這個任務將會稱為關鍵路徑逗栽,排班表很難體現依賴關系,容易出錯
4)如果有一個任務的執(zhí)行時間要調整失暂,將會有多個任務的執(zhí)行時間要調整
無論如何彼宠,采用“cron排班表”的方法,各任務耦合弟塞,誰用過誰痛誰知道(采用此法的請評論留言)
優(yōu)化方案是凭峡,采用MQ解耦:
1)task1準時開始,結束后發(fā)一個“task1 done”的消息
2)task2訂閱“task1 done”的消息决记,收到消息后第一時間啟動執(zhí)行摧冀,結束后發(fā)一個“task2 done”的消息
3)task3同理
采用MQ的優(yōu)點是:
1)不需要預留buffer,上游任務執(zhí)行完,下游任務總會在第一時間被執(zhí)行
2)依賴多個任務索昂,被多個任務依賴都很好處理建车,只需要訂閱相關消息即可
3)有任務執(zhí)行時間變化,下游任務都不需要調整執(zhí)行時間
需要特別說明的是楼镐,MQ只用來傳遞上游任務執(zhí)行完成的消息癞志,并不用于傳遞真正的輸入輸出數據。
【典型場景二:上游不關心執(zhí)行結果】
上游需要關注執(zhí)行結果時要用“調用”框产,上游不關注執(zhí)行結果時凄杯,就可以使用MQ了。
舉個栗子秉宿,58同城的很多下游需要關注“用戶發(fā)布帖子”這個事件戒突,比如招聘用戶發(fā)布帖子后,招聘業(yè)務要獎勵58豆描睦,房產用戶發(fā)布帖子后膊存,房產業(yè)務要送2個置頂,二手用戶發(fā)布帖子后忱叭,二手業(yè)務要修改用戶統(tǒng)計數據隔崎。
對于這類需求,常見的實現方式是韵丑,使用調用關系:
帖子發(fā)布服務執(zhí)行完成之后爵卒,調用下游招聘業(yè)務、房產業(yè)務撵彻、二手業(yè)務钓株,來完成消息的通知,但事實上陌僵,這個通知是否正常正確的執(zhí)行轴合,帖子發(fā)布服務根本不關注。
這種方法的壞處是:
1)帖子發(fā)布流程的執(zhí)行時間增加了
2)下游服務當機碗短,可能導致帖子發(fā)布服務受影響受葛,上下游邏輯+物理依賴嚴重
3)每當增加一個需要知道“帖子發(fā)布成功”信息的下游,修改代碼的是帖子發(fā)布服務偎谁,這一點是最惡心的总滩,屬于架構設計中典型的依賴倒轉,誰用過誰痛誰知道(采用此法的請評論留言)
優(yōu)化方案是搭盾,采用MQ解耦:
1)帖子發(fā)布成功后,向MQ發(fā)一個消息
2)哪個下游關注“帖子發(fā)布成功”的消息婉支,主動去MQ訂閱
采用MQ的優(yōu)點是:
1)上游執(zhí)行時間短
2)上下游邏輯+物理解耦鸯隅,除了與MQ有物理連接,模塊之間都不相互依賴
3)新增一個下游消息關注方,上游不需要修改任何代碼
典型場景三:上游關注執(zhí)行結果蝌以,但執(zhí)行時間很長
有時候上游需要關注執(zhí)行結果炕舵,但執(zhí)行結果時間很長(典型的是調用離線處理,或者跨公網調用)跟畅,也經常使用回調網關+MQ來解耦咽筋。
舉個栗子,微信支付徊件,跨公網調用微信的接口奸攻,執(zhí)行時間會比較長,但調用方又非常關注執(zhí)行結果虱痕,此時一般怎么玩呢睹耐?
一般采用“回調網關+MQ”方案來解耦:
1)調用方直接跨公網調用微信接口
2)微信返回調用成功,此時并不代表返回成功
3)微信執(zhí)行完成后部翘,回調統(tǒng)一網關
4)網關將返回結果通知MQ
5)請求方收到結果通知
這里需要注意的是硝训,不應該由回調網關來調用上游來通知結果,如果是這樣的話新思,每次新增調用方窖梁,回調網關都需要修改代碼,仍然會反向依賴夹囚,使用回調網關+MQ的方案纵刘,新增任何對微信支付的調用,都不需要修改代碼啦崔兴。
四彰导、總結
MQ是一個互聯(lián)網架構中常見的解耦利器。
什么時候不使用MQ敲茄?
上游實時關注執(zhí)行結果
什么時候使用MQ位谋?
1)數據驅動的任務依賴
2)上游不關心多下游執(zhí)行結果
3)異步返回執(zhí)行時間長