1. 程式人生 > >訊息佇列(入門篇)

訊息佇列(入門篇)

什麼是訊息佇列?

小時候,我的爸爸希望我多讀書,並常常尋找好書給我看,最開始他每次看見我寫完作業之後就給我拿來書,並親自監督我讀完之後他才忙自己的事情。久而久之,我養成了讀書的習慣。所以方式就改成了,爸爸想要我讀的書,都放在書架上,由於我已經養成了好習慣,一有空就從書架上拿書下來讀。再後來我的小夥伴們聽說我家很多書,也常常來我家玩,然後它們也可以直接從書架上拿書下來看。
看完這個故事之後再看看官方一點的訊息佇列定義。

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

為了幫助理解
訊息佇列,顧名思義,首先是個佇列。佇列的操作有入隊和出隊,也就是你有一個程式在產生內容然後入隊(生產者),另一個程式讀取內容,內容出隊(消費者)。
Producer:訊息生產者,負責產生和傳送訊息到 Broker;
Broker:訊息處理中心。負責訊息儲存、確認、重試等,一般其中會包含多個 queue;
Consumer:訊息消費者,負責從 Broker 中獲取訊息,並進行相應處理;

生產者消費者設計模式?

使用場景?

比如你寫日誌,因為可能一個客戶端有多個操作去寫,又有很多個客戶端,顯然併發不能無窮大,於是你就需要把寫日誌的請求放入到訊息佇列裡,在消費者那邊依次把佇列中產生的日誌寫到資料庫裡。

再比如假設使用者在你的軟體中註冊,服務端收到使用者的註冊請求後,它會做這些操作:校驗使用者名稱等資訊,如果沒問題會在資料庫中新增一個使用者記錄如果是用郵箱註冊會給你傳送一封註冊成功的郵件,手機註冊則會發送一條簡訊分析使用者的個人資訊,以便將來向他推薦一些志同道合的人,或向那些人推薦他傳送給使用者一個包含操作指南的系統通知等等……但是對於使用者來說,註冊功能實際只需要第一步,只要服務端將他的賬戶資訊存到資料庫中他便可以登入上去做他想做的事情了。至於其他的事情,非要在這一次請求中全部完成麼?值得使用者浪費時間等你處理這些對他來說無關緊要的事情麼?所以實際當第一步做完後,服務端就可以把其他的操作放入對應的訊息佇列中然後馬上返回使用者結果,由訊息佇列非同步的進行這些操作。

訊息佇列的特性

非同步性
將耗時的同步操作,通過以傳送訊息的方式,進行了非同步化處理。減少了同步等待的時間。
鬆耦合
訊息佇列減少了服務之間的耦合性,不同的服務可以通過訊息佇列進行通訊,而不用關心彼此的實現細節,只要定義好訊息的格式就行。
分散式
通過對消費者的橫向擴充套件,降低了訊息佇列阻塞的風險,以及單個消費者產生單點故障的可能性(當然訊息佇列本身也可以做成分散式叢集)。
可靠性
訊息佇列一般會把接收到的訊息儲存到本地硬碟上(當訊息被處理完之後,儲存資訊根據不同的訊息佇列實現,有可能將其刪除),這樣即使應用掛掉或者訊息佇列本身掛掉,訊息也能夠重新載入。

使用訊息佇列帶來的好處?

1.解耦
每個成員不必受其他成員影響,可以更獨立自主,只通過一個簡單的容器來聯絡。再往後我長大了,不僅可以從家裡的書架取書來看,還可以從圖書館的書架等等。只要有書架這個“容器”我就可以取書下來看。而不必關心到底是誰把書放上了書架。
2.提速
爸爸不再監督我看書,而為自己節省了大量時間。
3.廣播
將書擺上書架,可以讓不同的人讀,這樣讀書人的“成本”就很低,只需要找到書架就OK了。
4.削峰
讀書的頻率可以控制在自己手中,我學習忙的時候可以少讀一些,等空下來了,我可以加緊讀書。在我讀完這部分書之前,並不影響爸爸將更多好書放上書架。

使用訊息佇列帶來的壞處?

1.引入複雜度:在最開始的例子中,“書架”無疑是多出來的一個東西,在我們的系統中自然就需要地方來存放它,以及對它作相應的處理。

2.暫時的不一致性:依然拿最開始的例子來說,由於爸爸在對我進行閱讀習慣的培養之後,我會自覺的去看完爸爸放上來的書,並且他也是信任我的。但是他並不知道我具體是什麼時候看完的,他只知道我一定會看完,他甚至會疏忽我學業的繁忙而錯誤的認為我已經看完了那些書,然而實際上我稍後才一段時間才看完。可以肯定的是,這本書我一定會看完的,但在期間一段時間內,我跟爸爸對於我讀書程序狀態的認知是不一致的。

在作訊息佇列的時候需要考慮的事項包括?

1.永續性,訊息可能被儲存在記憶體中,寫入到磁碟,或甚至提交到DBMS,如果可靠性要求表明了更加資源密集型的解決方案。
2.安全策略,哪些應用程式可以訪問這些訊息?
3.訊息清理策略,佇列或訊息應當有存活時間
4.訊息過濾,一些系統支援過濾資料,因此,訂閱者只能看到匹配預定義興趣標準的訊息
5.交付策略,我們是不是應該保證訊息傳遞至少一次,或不超過一次?
6.路由策略,在一個有許多佇列伺服器的系統中,哪些伺服器應該收到一條訊息或一佇列的訊息?
7.批量策略,是否立即將訊息傳送?還是說系統應該稍等,並嘗試一次傳遞多條訊息?
8.排隊標準,什麼時候應當考慮訊息“入隊”?什麼時候佇列有了?或者,何時它被轉發到至少一個遠端佇列?或所有佇列?
9.已收通知,釋出者可能需要知道,何時部分或全部訂閱者收到了訊息。
這些因素都是要考慮的,會顯著影響到傳輸語義,系統的可靠性,系統效率。

標準和協議?

從歷史來看,訊息佇列使用了專有的,封閉的協議,以約束不同的作業系統或程式語言在異構環境中互動的能力。
最近,已經出現了三個標準,使得訊息佇列開放而廣泛:高階訊息佇列協議、MQTT、面向流文字的訊息傳遞協議

last but not least

所以在軟體的正常功能開發中,並不需要去刻意的尋找訊息佇列的使用場景,而是當出現效能瓶頸時,去檢視業務邏輯是否存在可以非同步處理的耗時操作,如果存在的話便可以引入訊息佇列來解決。否則盲目的使用訊息佇列可能會增加維護和開發的成本卻無法得到可觀的效能提升,那就得不償失了。