1. 程式人生 > >MQ訊息中介軟體

MQ訊息中介軟體

MQ是什麼?

MQ是Message Queue訊息佇列的縮寫。訊息佇列是一種應用程式對應用程式的通訊方法、應用程式通過寫和檢索入列隊的針對應用程式的資料(訊息)來進行通訊,而不需要專用連線來連結它們。訊息傳遞指的是程式之間通過在訊息中傳送資料進行通訊,而不是通過直接呼叫彼此來通訊,直接呼叫通常是用於諸如遠端過程呼叫的技術。排隊指的是應用程式通過佇列來通訊,佇列的使用除去了接收和傳送應用程式同時執行的要求。

訊息中介軟體的概況?

訊息佇列技術是分散式應用間交換資訊的一種技術,訊息佇列可駐留在記憶體或者磁碟上,佇列儲存訊息直到它們被應用程式讀走,通過訊息佇列,應用程式可獨立的執行---它們不需要知道彼此的位置。或者繼續執行前不需要等待接收程式接收此訊息。

 

訊息匯流排(Message Queue),後文稱MQ,是一種跨程序的通訊機制,用於上下游傳遞訊息。

 

在網際網路架構中,MQ是一種非常常見的上下游“邏輯解耦+物理解耦”的訊息通訊服務。

使用了MQ之後,訊息傳送上游只需要依賴MQ,邏輯上和物理上都不用依賴其他服務。

 

MQ相關的概念:

(1)訊息Message

訊息是MQ中最小的概念,本質上是一段資料,它能被一個或者多個應用程式所理解。是應用程式之間傳遞的資訊載體、

(2)佇列Queue

a、本地佇列

本地佇列按照功能能劃分為初始化佇列,傳輸佇列、目標佇列、死信佇列

    初始化佇列:用作訊息觸發功能。

    傳輸佇列:只是暫存待傳的訊息,條件許可的情況下,通過管道將訊息傳送到其他的佇列管理器。

   目標佇列:是訊息的目的地,可以長期存放訊息。

    死信佇列:當訊息不能送到目標佇列,也不再路由出去。則自動放入死信佇列儲存。

b、別名佇列和遠端佇列

只是一個佇列的定義,用來指定遠端佇列管理器的佇列、使用了遠端佇列,程式就不需要知道目標佇列的位置、

c、模型佇列

模型佇列定義了一套本地佇列的屬性結合。一旦開啟模型佇列,佇列管理器會按照這些屬性動態的創建出一個本地佇列。

(3)佇列管理器(Queue Manager)

佇列管理器時一個負責嚮應用程式提供訊息服務的機構,如果把佇列管理器比作資料庫,那麼佇列就是其中的一張表、

(4)通道(Channel)

通道是兩個管理器之間的一種單向點對點的通訊連線,若需要雙向交流,可以建立一對通道。

(5)監聽器(listener)

MQ產品特性

可靠性傳輸:這個特點是訊息中介軟體的立足之本,對應用來說,只要成功把資料提交個訊息中介軟體,那麼關於資料可靠傳輸的問題就由訊息中介軟體來負責。

不重複傳輸 :不重複傳輸也就是斷點續傳的功能,特別適合在網路不穩定的環境,節約網路資源。

非同步傳輸:接受資訊雙方不必同時線上,具有離線能力和安全性。

訊息驅動:接到訊息後主動通知訊息接收方

支援事務:應用程式可以把一些資料更新組合成一個工作單元,這些更新通常是邏輯相關的,為了保障資料完整性,所有的更新必須同時成功或者同時失敗。

什麼時候不使用訊息匯流排

既然MQ是網際網路分層架構中的解耦利器,那所有通訊都使用MQ豈不是很好?這是一個嚴重的誤區,呼叫與被呼叫的關係,是無法被MQ取代的。

 

MQ的不足是:

1)系統更復雜,多了一個MQ元件

2)訊息傳遞路徑更長,延時會增加

3)訊息可靠性和重複性互為矛盾,訊息不丟不重難以同時保證

4)上游無法知道下游的執行結果,這一點是很致命的

 

舉個栗子:使用者登入場景,登入頁面呼叫passport服務,passport服務的執行結果直接影響登入結果,此處的“登入頁面”與“passport服務”就必須使用呼叫關係,而不能使用MQ通訊。

 

無論如何,記住這個結論:呼叫方實時依賴執行結果的業務場景,請使用呼叫,而不是MQ。

 

什麼時候使用MQ

【典型場景一:資料驅動的任務依賴】

 什麼是任務依賴,舉個栗子,網際網路公司經常在凌晨進行一些資料統計任務,這些任務之間有一定的依賴關係,比如:

1)task3需要使用task2的輸出作為輸入

2)task2需要使用task1的輸出作為輸入

這樣的話,tast1, task2, task3之間就有任務依賴關係,必須task1先執行,再task2執行,載task3執行。

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

1)task1,0:00執行,經驗執行時間為50分鐘

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

3)task3,2:00執行(為task2預留10分鐘buffer)

 

這種方法的壞處是:

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

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

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

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

 

無論如何,採用“cron排班表”的方法,各任務耦合,誰用過誰痛誰知道(採用此法的請評論留言)

 

 

優化方案是,採用MQ解耦:

1)task1準時開始,結束後發一個“task1 done”的訊息

2)task2訂閱“task1 done”的訊息,收到訊息後第一時間啟動執行,結束後發一個“task2 done”的訊息

3)task3同理

 

採用MQ的優點是:

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

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

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

 

需要特別說明的是,MQ只用來傳遞上游任務執行完成的訊息,並不用於傳遞真正的輸入輸出資料。

 

【典型場景二:上游不關心執行結果】

上游需要關注執行結果時要用“呼叫”,上游不關注執行結果時,就可以使用MQ了。

 

舉個栗子,58同城的很多下游需要關注“使用者釋出帖子”這個事件,比如招聘使用者釋出帖子後,招聘業務要獎勵58豆,房產使用者釋出帖子後,房產業務要送2個置頂,二手使用者釋出帖子後,二手業務要修改使用者統計資料。

 

對於這類需求,常見的實現方式是,使用呼叫關係:

帖子釋出服務執行完成之後,呼叫下游招聘業務、房產業務、二手業務,來完成訊息的通知,但事實上,這個通知是否正常正確的執行,帖子釋出服務根本不關注。

 

這種方法的壞處是:

1)帖子釋出流程的執行時間增加了

2)下游服務當機,可能導致帖子釋出服務受影響,上下游邏輯+物理依賴嚴重

3)每當增加一個需要知道“帖子釋出成功”資訊的下游,修改程式碼的是帖子釋出服務,這一點是最噁心的,屬於架構設計中典型的依賴倒轉,誰用過誰痛誰知道(採用此法的請評論留言)

 

優化方案是,採用MQ解耦:

1)帖子釋出成功後,向MQ發一個訊息

2)哪個下游關注“帖子釋出成功”的訊息,主動去MQ訂閱

 

採用MQ的優點是:

1)上游執行時間短

2)上下游邏輯+物理解耦,除了與MQ有物理連線,模組之間都不相互依賴

3)新增一個下游訊息關注方,上游不需要修改任何程式碼

 

典型場景三:上游關注執行結果,但執行時間很長

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

 

舉個栗子,微信支付,跨公網呼叫微信的介面,執行時間會比較長,但呼叫方又非常關注執行結果,此時一般怎麼玩呢?

一般採用“回撥閘道器+MQ”方案來解耦:

1)呼叫方直接跨公網呼叫微信介面

2)微信返回呼叫成功,此時並不代表返回成功

3)微信執行完成後,回撥統一閘道器

4)閘道器將返回結果通知MQ

5)請求方收到結果通知

 

這裡需要注意的是,不應該由回撥閘道器來呼叫上游來通知結果,如果是這樣的話,每次新增呼叫方,回撥閘道器都需要修改程式碼,仍然會反向依賴,使用回撥閘道器+MQ的方案,新增任何對微信支付的呼叫,都不需要修改程式碼啦。

 

總結

MQ是一個網際網路架構中常見的解耦利器。

 

什麼時候不使用MQ?

上游實時關注執行結果

 

什麼時候使用MQ?

1)資料驅動的任務依賴

2)上游不關心多下游執行結果

3)非同步返回執行時間長

 

整理自:

https://blog.csdn.net/u011393781/article/details/52680686

https://blog.csdn.net/xybelieve1990/article/details/70313216/