01.MQ簡介

MQ是幹嘛的

當你剛剛爲公司的一個Web應用實現了一個很棒的註冊模塊。它看起來簡潔、高效。在你沾沾自喜的時候,你的leader對你說,現在咱們需要在註冊成功後對用戶發送一條短信。過了一段時間後,你的leader又對你說,現在咱們需要在註冊成功後對用戶發送一條郵件,點擊郵件中的激活鏈接後纔算是真正的註冊成功。又過了一段時間,你的leader又對你說,現在咱們需要在註冊成功後對用戶發送一條成功贈送金幣的迎新消息。又過了一段時間後…

世界唯一不變的就是不斷變化。對於剛纔的應用場景,如果所有的新增業務邏輯都寫在註冊模塊中,不但會有大量的耦合,也會增加後期維護的成本。

江湖傳聞應對這種場景對於MQ來說小菜一碟,那我們來看下MQ是怎麼做到的。


MQ英文全稱Message Queue,中文翻譯爲消息總線或消息隊列,它是一種跨進程的通信機制,用於上下游傳遞消息。

在互聯網架構中,MQ是一種非常常見的上下游邏輯解耦+物理解耦的消息通信服務。使用了MQ之後,消息發送上游只需要依賴MQ,邏輯上和物理上都不用依賴其他服務。

對於剛開始我們提到的問題,如果使用MQ的話,我們只需要在註冊完成後向MQ中發送一條消息;對於後面的迭代模塊只需要訂閱該消息即可。無論後期新增多少模塊都不會對原始的註冊模塊造成影響。

其實,我們可以把MQ想象成一個郵局,當你把你想要投遞的郵件放進郵箱時,MQ最終會把郵件投遞給你的收件人,當然了,你的收件人可以是一個人或者是一羣人,這個MQ都是支持的。

既然MQ這麼厲害,爲什麼不所有的通訊都使用MQ呢?

因爲沒有一種技術普適於所有差異化的業務場景。就好比,相對論把牛頓的經典力學擴展到更普適的宇宙範圍,上升到亞光速和光速層面,打破了經典力學的侷限性,但是,它也肯定有侷限性,不然也不會顯得與量子力學格格不入!那麼,MQ的侷限性都有哪些呢?

MQ的侷限性

  • 多了個組件,會使系統更復雜
  • 消息傳遞路徑更長,延時會增加
  • 消息可靠性和重複性護衛矛盾,消息不丟不重難以同時保證
  • 比較致命的是,上游無法知道下游的執行結果

舉個簡單的例子,用戶的登錄,登錄頁面調用用戶中心的登錄服務,而登錄服務的執行結果將直接影響登錄的結果。此處的登錄頁面登錄服務就必須使用調用關係,而不能使用MQ通信。假如使用了MQ,想想都很酸爽。。

正因爲MQ侷限性的存在,那麼,我們什麼情況下不使用MQ呢?

因爲其侷限性,所以,當調用方實時依賴執行結果的業務場景,請使用調用,而不是MQ

我們在瞭解了什麼情況下不宜使用MQ的情況下,我們更應該熟悉MQ常用的幾種典型場景。

MQ典型應用場景

數據驅動的任務依賴

所謂的數據驅動的任務依賴,顧名思義,就是指某一個任務的輸入數據依賴於另一個任務的輸出數據。

比如,很多公司會在凌晨進行一些數據統計業務,而有時候多個統計業務就會有數據依賴的情況。

對於這類需求,常見的實現方式是使用,cron表達式進行人工排執行時間表。

  • task1, 0:00執行,經驗執行時間50分鐘
  • task2,1:00執行(爲task1預留10分鐘buffer),經驗執行時間也是50分鐘
  • task3,2:00執行(爲task2預留10分鐘buffer)

但是,這種方法有着顯著的弊端:

  • 如果有一個任務執行時間超過了預留buffer的時間,將會得到錯誤的結果,因爲後置任務不清楚前置任務是否執行成功,此時要手動重跑任務,還有可能要調整排班表

  • 總任務的執行時間很長,總是要預留很多buffer,如果前置任務提前完成,後置任務不會提前開始

  • 如果一個任務被多個任務依賴,這個任務將會稱爲關鍵路徑,排班表很難體現依賴關係,容易出錯

  • 如果有一個任務的執行時間要調整,將會有多個任務的執行時間要調整

而且,這種方式也是具有很高的耦合性。因此,我們給出的優化方案就是使用MQ。

  • task1準時開始,結束後發一個“task1 done”的消息

  • task2訂閱“task1 done”的消息,收到消息後第一時間啓動執行,結束後發一個“task2 done”的消息

  • task3同理

ps:此處發送的消息可以理解爲,確認任務完成的一個標識消息,而不是任務執行完成後的輸出數據

綜上所述,在數據驅動的任務依賴的場景下,採用MQ具備了以下優點:

  • 不需要預留buffer,上游任務執行完,下游任務總會在第一時間被執行

  • 依賴多個任務,被多個任務依賴都很好處理,只需要訂閱相關消息即可

  • 有任務執行時間變化,下游任務都不需要調整執行時間

上游不關心執行結果

在上面已經說過,如果上游需要關注執行結果,則需要使用調用,如果上游不需要關注執行結果,則可以使用MQ。

此處,我們再次回顧下開篇所說的註冊模塊,註冊成功後,短信模塊需要發送一條短信通知,郵件模塊需要發送一條郵件通知,金幣模塊需要發送一條贈送金幣通知。這裏,我們不關心執行結果,只要執行了就是OK的。

如果採用直接調用

  • 最明顯的就是,執行時間增加

  • 其次,下游某一個服務宕機,可能導致註冊服務的異常,上下游邏輯+物理依賴嚴重

  • 最後,如果再新增一個下游,上游必須得修改代碼,屬於架構設計中典型的依賴倒轉

優化後,採用MQ解耦,在註冊成功後,向MQ發送一個消息;哪個下游關注註冊成功這個事件,就主動去MQ訂閱

採用MQ後,上游執行時間只關注本身業務;除了與MQ有物理連接,上下游模塊都不相互依賴;新增一個下游消息關注方,上游不需要修改任何代碼。

上游關心執行結果,但執行時間很長

有時候上游需要關注執行結果,但執行時間很長。典型的是調用離線處理,或者跨公網調用,經常使用回調網關+MQ來解耦

比如,微信支付,跨公網調用微信的接口。

執行的流程:

  • 調用方直接跨公網調用微信接口

  • 微信返回調用成功,此時並不代表返回成功

  • 微信執行完成後,回調統一網關

  • 網關將返回結果通知MQ

  • 請求方收到結果通知

這裏可能會有個疑問,爲什麼不由回調網關來調用上游來通知結果呢?
因爲,如果這樣的話,每次新增調用方,回調網關都需要修改代碼,仍然會反向依賴,使用回調網關+MQ的方案,新增任何對微信支付的調用,都不需要修改代碼啦。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章