1. 程式人生 > >訊息佇列(一)

訊息佇列(一)

一、小故事

有一天,產品跑來說:“我們要做一個使用者註冊功能,需要在使用者註冊成功後給使用者發一封成功郵件。”

小明(攻城獅):“好,需求很明確了。” 不就提供一個註冊介面,儲存使用者資訊,同時發起郵件呼叫,待郵件傳送成功後,返回使用者操作成功。沒一會功夫,程式碼就寫完了。驗證功能沒問題後,就釋出上線了。

線上正常運行了一段時間,產品匆匆地跑來說:“你做的功能不行啊,運營反饋註冊操作響應太慢,已經有好多使用者流失了。”

小明聽得一身冷汗,趕緊回去改。他發現,原先的以單執行緒同步阻塞的方式進行郵件傳送,確實存在問題。這次,他利用了 JAVA 多執行緒的特性,另起執行緒進行郵件傳送,主執行緒直接返回儲存結果。測試通過後,趕緊釋出上線。小明心想,這下總沒問題了吧。

沒過多久,產品又跑來了,他說:“現在,註冊操作響應是快多了。但是又有新的問題了,有使用者反應,郵件收不到。能否在傳送郵件時,儲存一下發送的結果,對於傳送失敗的,進行補發。”

小明一聽,哎,又得熬夜加班了。產品看他一臉苦逼的樣子,忙說:“郵件服務這塊,別的團隊都已經做好了,你不用再自己搞了,直接用他們的服務。”

小明趕緊去和郵件團隊溝通,誰知他們的服務根本就不對外開放。這下小明可開始犯愁了,明知道有這麼一個服務,可是偏偏又調用不了。

郵件團隊的人說,“看你愁的,我給你提供了一個類似郵局信箱的東西,你往這信箱裡寫上你要傳送的訊息,以及我們約定的地址。之後你就不用再操心了,我們自然能從約定的地址中取得訊息,進行郵件的相應操作。”

後來,小明才知道,這就是外界廣為流傳的訊息佇列。

你不用知道具體的服務在哪,如何呼叫。你要做的只是將該傳送的訊息,向你們約定好的地址進行傳送,你的任務就完成了。

對應的服務自然能監聽到你傳送的訊息,進行後續的操作。這就是訊息佇列最大的特點,將同步操作轉為非同步處理,將多服務共同操作轉為職責單一的單服務操作,做到了服務間的解耦。

哈哈,這下能高枕無憂了。太年輕,哪有萬無一失的技術啊~

不久的一天,你會發現所有業務都替換了郵件傳送的方式,統一使用了訊息佇列來進行傳送。

這下僅僅一個郵件服務模組,難以承受業務方源源不斷的訊息,大量的訊息堆積在了佇列中。這就需要更多的消費者(郵件服務)來共同處理佇列中的訊息,即所謂的分散式訊息處理。

二、什麼是訊息佇列

一、訂閱雜誌

我們很多人都訂過雜誌,其過程很簡單。只要告訴郵局我們所要訂的雜誌名、投遞的地址,付了錢就OK。出版社定期會將出版的雜誌交給郵局,郵局會根據訂閱的列表,將雜誌送達消費者手中。這樣我們就可以看到每一期精彩的雜誌了。

仔細思考一下訂雜誌的過程,我們會發現這樣幾個特點:1、消費者訂雜誌不需要直接找出版社;2、出版社只需要把雜誌交給郵局;3、郵局將雜誌送達消費者。郵局在整個過程中扮演了非常重要的中轉作用,在出版社和消費者相互不需要知道對方的情況下,郵局完成了雜誌的投遞。
二、釋出-訂閱訊息模式

剛剛講了訂閱雜誌,下面我們引用剛才小故事的情景,講講傳統呼叫模式演化到釋出-訂閱訊息模式。
有些網站在註冊使用者成功後發一封啟用郵件,使用者收到郵件後點擊啟用連結後才能使用該網站。一般的做法是在註冊使用者業務邏輯中呼叫傳送郵件的邏輯。這 樣使用者業務就依賴於郵件業務。如果以後改為簡訊啟用,註冊使用者業務邏輯就必須修改為呼叫傳送簡訊的邏輯。如果要註冊後給使用者加點積分,再加一段邏輯。經過 多次修改,我們發現很簡單的註冊使用者業務已經越來越複雜,越來越難以維護。相信很多開發者都會有類似痛苦的經歷。

即使使用者業務實現中對其他業務是介面依賴,也避免不了業務變化帶來的依賴影響。怎麼辦?解耦!將註冊使用者業務邏輯中註冊成功後的處理剝離出來。
再回頭看看"訂閱雜誌",如果沒有郵局,出版社就必須自己將雜誌送達所有消費者。這種情形就和現在的註冊使用者業務一樣。我們發現問題了,在使用者業務和其他業務之間缺少了郵局所扮角色。
我們把郵局抽象成一個管理訊息的地方,叫"訊息管理器"。註冊使用者成功後傳送一個訊息給訊息管理器,由訊息管理器轉發該訊息給需要處理的業務。現在,使用者業務只依賴於訊息管理器了,它再也不會為了註冊使用者成功後的其他處理而煩惱。

註冊使用者的改造就是借鑑了"訂閱雜誌"這樣原始的模式。我們再進一步抽象,使用者業務就是訊息的"生產者",它將訊息釋出到訊息管理器。郵件業務就是 訊息的"消費者",它將收到的訊息進行處理。郵局可以訂閱很多種雜誌,雜誌都是通過某種編號來區分;訊息管理器也可以管理多種訊息,每種訊息都會有一個 "主題"來區分,消費者都是通過主題來訂閱的。

釋出-訂閱訊息模式已經呈現在我們面前,利用它可以產生更靈活、更鬆散耦合的系統。

好了,相信讀到這裡,大家對訊息佇列的概念已經有了一個大概的認識。來看點專業的。

訊息佇列(英語:Message queue)
是一種程序間通訊或同一程序的不同執行緒間的通訊方式,軟體的貯列用來處理一系列的輸入,通常是來自使用者。
訊息佇列提供了非同步的通訊協議,每一個貯列中的紀錄包含詳細說明的資料,
包含發生的時間,輸入裝置的種類,以及特定的輸入引數,也就是說:訊息的傳送者和接收者不需要同時與訊息佇列互交。
訊息會儲存在佇列中,直到接收者取回它。 
                                ——維基百科

解釋還是太官方了,我們來看一個最簡單的架構模型:

 

  • Producer:訊息生產者,負責產生和傳送訊息到 Broker;

  • Broker:訊息處理中心。負責訊息儲存、確認、重試等,一般其中會包含多個 queue;

  • Consumer:訊息消費者,負責從 Broker 中獲取訊息,並進行相應處理;

 

參考:

https://www.sohu.com/a/141980935_700886

https://blog.csdn.net/hongsejiaozhu/article/details/72867889