ActiveMQ從入門到精通(二)

加瓦一枚發表於2018-12-28

接上一篇《ActiveMQ從入門到精通(一)》,本篇主要討論的話題是:訊息的順序消費、JMS Selectors、訊息的同步/非同步接受方式、Message、P2P/PubSub、持久化訂閱、持久化訊息到MySQL以及與Spring整合等知識。

訊息的順序消費

在上一篇文章中,我們已經明確知道了ActiveMQ並不能保證消費的順序性,即便我們使用了訊息優先順序。而在實際開發中,有些場景又是需要對訊息進行順序消費的,比如:使用者從下單、到支付、再到發貨等。如果使用ActiveMQ該如何保證消費的順序性呢?

訊息消費順序性

首先來說,在實際中,我們並不需要的是對全部訊息的全域性有序消費,我們僅僅需要的是區域性業務有序性消費。比如說,我們僅僅需要的是一個使用者的下訂單、支付、發貨這個過程的3條訊息有序消費。

比如,我們可以根據使用者ID簡單做一個HASH,將訊息定位到不同的佇列上,也就意味著同一個使用者的訊息將發往同一個佇列。這樣做的好處在於,多個佇列之間可以並行處理。

然後,在佇列上可以對一段時間上的訊息按照使用者分組進行排序,這只是一個少量訊息的區域性排序而已,比如Queue-A上有一個使用者的3條訊息(訂單訊息msg1、支付訊息msg2、發貨訊息msg3),那麼,msg1將交給訂單業務系統,處理完成後,msg2交給支付系統,處理完成後,msg3交給發貨系統。雖然這個處理過程是同步的(一條訊息處理完,在接著處理),但是它的併發性,系統的處理能力並沒有下降!為什麼這麼說呢?

假設,msg1/msg2/msg3處理各需要0.1S,如果訂單業務系統、支付系統、發貨系統並沒有分開,而是一個“大系統”,那麼顯然訂單業務在0.1S完成後,需要等待後面的支付、發貨邏輯處理完才能繼續工作,意味著訂單業務幹了0.1S的活,等了0.2S,導致在0.3秒內訂單業務只處理了1條訊息。而現在這3個系統是分開的,那麼在0.3S內,訂單業務系統可以處理3條訊息,而且沒有業務系統閒著!

實際上,RocketMQ在消費順序性這塊要比ActiveMQ要強大些,後期在RocketMQ專題中再為大家介紹。


JMS Selectors

JMS Selectors,即訊息選擇器。在《ActiveMQ從入門到精通(一)》中,介紹過訊息的組成部分,其中談到訊息物件有訊息屬性,用於訊息選擇器。我們來看一個程式碼片段,你就會明白:

生產者片段

 

消費者片段

需要注意一下幾點:

第一,生產者端需要設定訊息屬性,一定要注意的是setXxxProperty(filed,value)

第二,給出條件,其實本質上就是SQL92語法

第三,建立消費者的時候,指定條件即可

 


訊息的同步 AND 非同步 接受

訊息的接受,我們已經知道,可以通過消費者的receive()/receive(long time)/receiveNoWait(),這種方式是client端主動接受訊息,可以理解為訊息的同步接受。要知道這種同步的訊息接受方式,是讓我們很難受的,我們不得不寫一個死迴圈來不斷接受訊息。那麼有沒有一種比較優雅的方式,比如我們設定一個類似訊息監聽的機制,一旦佇列上有訊息了,那麼回撥我們的message handler進行處理呢?

Message Listener

訊息的非同步接受是指當訊息到達時,ActiveMQ主動通知客戶端。可以通過註冊一個實現了MessageListener介面的物件到MessageConsumer。MessageListener只有一個必須要實現的方法,即onMessage。在發往Destination的訊息時,會呼叫該方法。

這種非同步接受“貌似”是ActiveMQ主動的推送訊息給消費者,其本質還是消費者輪詢訊息伺服器導致的,只不過這個過程被封裝了!


Message

JMS程式的核心在於,生產和消費的訊息能夠被其他程式所使用到。JMS Message是一個既簡單又不乏靈活的基本格式,由訊息頭、屬性、訊息體3部分組成。

Message

注意,在消費者端,我們接受到訊息後,一般需要通過instanceof來判斷型別後在進行處理!

在ActiveMQ中,還存在一類臨時訊息,就是通過建立臨時佇列/臨時主題,如果Connection一旦關閉,那麼臨時目標就關閉,訊息內容也就消失。瞭解下即可,實際中並不適用。


P2P or Pub/Sub

上2張圖,你就會明白這2種模式的區別了。

P2P

生產者端傳送一條訊息,消費者端只會有一個消費者消費這個訊息。好像打電話,一對一通訊!

Pub/Sub

一對多通訊,傳送一條訊息,所有訂閱了該目標的消費者都會收到訊息。

P2P、Pub/Sub在程式碼上的區別點僅僅在於,目標型別的建立是createQueue or createTopic,其他一切照舊!

對於訂閱模式,對訂閱者提出了特殊的要求,要想收到訊息,必須先訂閱,而且訂閱程式必須一直處於執行狀態!實際上,有時候消費者重啟了下,那麼這個消費者將丟失掉一些訊息,那麼能否避免這樣的情況呢?ActiveMQ已經替我們想好了,就是持久化訂閱!

 


持久化訂閱

所謂持久化訂閱,打個比方,就是說跟MQ打聲招呼,即便我不在,那麼給我傳送的訊息暫存在MQ,等我來了,再給我發過來。說白了,持久化訂閱,需要給MQ備個案(你是誰,想在哪個Topic上搞特殊化)!看一個程式碼片段:

持久化訂閱機制

每一個持久化訂閱者都應該有一個唯一的ID作為標示以及要在哪個Topic上進行持久化訂閱,一旦這些資訊告知MQ之後,那麼以後不論持久化訂閱者在不線上,那麼他的訊息會暫存在MQ,以後都會發給他!


持久化訊息到MySQL

在前文中已經提及預設情況下,ActiveMQ是開啟持久化訊息機制的,並且是持久化到kahadb的,但是"很可惜"kahadb對我們不是很友好的視覺化,其實ActiveMQ提供了配置的方式讓我們來選擇持久化訊息到哪裡,這裡我以到MySQL為例來說明。(實際上ActiveMQ已經在conf配置檔案中提供了相應的例子,我這裡就簡單說明下)

在activemq.xml的<broker>節點中增加MySQL資訊

注意到這個bean的id,這個是要被引用的。

註釋kahadb,啟用持久化到MySQL配置

實際中,我們會持久化到哪裡呢?一般情況下,比如到kahadb,比如到leveldb,因為這些資料庫的效能要較MySQL更高些,我們並不關心訊息的“視覺化”,更加關心的是訊息在持久化的同時更加高效!

 


與Spring整合

這裡我將為大家演示Spring和ActiveMQ整合的核心要素。採用Spring,不要Web容器,不涉及Spring-MVC,而且在這裡我將採用JUnit + Spring-Test來進行測試!在文章末尾我將提供原始碼下載。OK,先來看一眼工程截圖:

工程結構

第一步:POM.XML配置

maven dependency tree

第二步:MQ資訊配置檔案、Spring配置檔案

activemq.properties

 

spring-context.xml

下面我們重點關注spring-activemq.xml:

ConnectionFactory

注意從ActiveMQConectionFactory到PooledConnectionFactory,到Spring提供的SingleConnectionFactory,就是一個適配的過程。

 

 

 

 

生產者、消費者配置

注意Spring的套路經常是這樣的,提供XxxTemplate,比如HibernateTemplate,對於JMS,提供了JmsTemplate。

生產者應該持有JmsTemplate進行傳送訊息。

消費者,提供監聽器、監聽的目的地、連線工廠即可。

上面的配置,只是一個非常簡單的示例,比如是傳送到佇列,還是傳送到主題,事務的配置,簽收機制的配置,ttl/priority等配置在後文通過看一下原始碼,你就會知道該如何配置了。

第三步:消費者實現監聽器

spring提供的介面

第四步:生產者

通過注入拿到JmsTemplate

第五步:利用Junit4 + SpringTest方式進行測試

我們以前在測試Spring這一塊,大都是通過手動編碼的方式(載入XML,setter/getter bean)進行,這裡我將為大家介紹一種全新的方式測試Spring程式!

測試基類

為什麼要提供一個測試基類呢?因為我們可能有很多個測試類,如果有了這個基類,其他測試類繼承它,就可以自動獲得測試基類的屬性了。

@RunWith  指明採用SpringJunit4進行測試

@ContextConfiguration 告訴配置檔案在哪裡

 

生產者測試類

發現沒有,這樣寫Junit單元測試,和以前感覺不一樣!

其實,SpringTest + Junit4還提供了很多功能強大的地方,比如可以設定資料庫事務。如果我們在測試的過程結束後,希望回滾資料庫的話,很簡單,只需要在相應方法上打上註解即可。

執行結果

Test Result

JmsTemplate

看一下屬性:

JmsTemplate

很多屬性,是不是很熟悉呢?

JmsTemplate的父類中有一個重要屬性:

pubSubDomain

預設情況下,是P2P模式,如果將這個屬性配置成true,那麼將是主題模式。

 

OK,到這裡這篇部落格的內容就介紹完畢了,下一篇是關於ActiveMQ叢集方面的知識,See you again.

本篇部落格工程程式碼下載地址: 

http://pan.baidu.com/s/1i4HEZsx

密碼:h2hh



作者:張豐哲
連結:https://www.jianshu.com/p/f7a7105b3c27
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。

相關文章