【ActiveMQ】JMS中間件ActiveMQ詳解

1.JMS介紹
Java Message Service(JMS)是SUN提出的旨在統一各種MOM(Message-Oriented Middleware )系統接口的規範,它包含點對點(Point to Point,PTP)和發佈/訂閱(Publish/Subscribe,pub/sub)兩種消息模型,提供可靠消息傳輸、事務和消息過濾等機制。
簡單的說,JMS制定了一個發消息的規範,是一個與具體平臺無關的API,絕大多數MOM(面向消息中間件)提供商都對JMS提供支持。
ActiveMQ是Apache出品的開源項目,它是JMS規範的一個實現。

2.JMS作用
在不同應用之間進行通信或者從一個系統傳輸數據到另外一個系統。兩個應用程序之間,或分佈式系統中發送消息,進行異步通信。
這類問題有很多解決方案 ,比如SOA、Socket通信、RMI等,但我們需要根據項目的限制以及功能和性能的需要作出選擇。
JMS的應用場景:規模和複雜度較高的分佈式系統
(1)同步通信:客戶發出調用後,必須等待服務對象完成處理並返回結果後才能繼續執行
(2)客戶和服務對象的生命週期緊密耦合:客戶進程和服務對象進程都必須正常運行,如果由於服務對象崩潰或者網絡故障導致客戶的請求不可達,客戶會接收到異常
(3)點對點通信:客戶的一次調用只發送給某個單獨的目標對象
這裏寫圖片描述

3.JMS模型
Java消息服務應用程序結構支持兩種模型:
(1)點對點模型(基於隊列)
每個消息只能有一個消費者,消息的生產者和消費者之間沒有時間上的相關性,可以由多個發送者,但只能被一個消費者消費。
一個消息只能被一個接受者接受一次
生產者把消息發送到隊列中(Queue),這個隊列可以理解爲電視機頻道(channel)
在這個消息中間件上有多個這樣的channel
接受者無需訂閱,當接受者未接受到消息時就會處於阻塞狀態

(2)發佈者/訂閱者模型(基於主題的)
每個消息可以有多個消費者,生產者和消費者之間有時間上的相關性,訂閱一個主題的消費者只能消費自它訂閱之後發佈的消息。
允許多個接受者,類似於廣播的方式
生產者將消息發送到主題上(Topic)
接受者必須先訂閱
注:持久化訂閱者:特殊的消費者,告訴主題,我一直訂閱着,即使網絡斷開,消息服務器也記住所有持久化訂閱者,如果有新消息,也會知道必定有人回來消費。
這裏寫圖片描述

4.JMS的基本構件
連接工廠:連接工廠是客戶用來創建連接的對象,例如ActiveMQ提供的ActiveMQConnectionFactory
連接: JMS Connection封裝了JMS 客戶端到JMS Provider 的連接與JMS提供者之間的一個虛擬的連接
會話: JMS Session是生產和消費消息的一個單線程上下文,會話用於創建消息的生產者(producer),消費者(consumer),消息(message)等。會話是一個事務性的上下文,消息的生產和消費不能包含在同一個事務中。
生產者:MessageProducer 由Session 對象創建的用來發送消息的對象
消費者:MessageConsumer 由Session 對象創建的用來接收消息的對象
消息:Message jms消息包括消息頭和消息體以及其它的擴展屬性。JMS定義的消息類型TextMessage、MapMessage、BytesMessage、StreamMessage和ObjectMessage。
目的地:Destination 消息的目的地,是用來指定生產的消息的目標和它消費的消息的來源的對象
消息隊列:Queue 點對點的消息隊列
消息主題:Tipic 發佈訂閱的消息隊列

5.JMS消息發送時序圖
這裏寫圖片描述

6.JMS消息發送開發流程
(1)生產者(producer)開發流程(ProducerTool.java)
1.1 創建Connection: 根據url,user和password創建一個jms Connection。
1.2 創建Session:在connection的基礎上創建一個session,同時設置是否支持事務和ACKNOWLEDGE標識。
1.3 創建Destination對象:需指定其對應的主題(subject)名稱,producer和consumer將根據subject來發送/接收對應的消息。
1.4 創建MessageProducer:根據Destination創建MessageProducer對象,同時設置其持久模式。
1.5 發送消息到隊列(Queue):封裝TextMessage消息,使用MessageProducer的send方法將消息發送出去。

(2)消費者(consumer)開發流程(ConsumerTool.java)
2.1 實現MessageListener接口:消費者類必須實現MessageListener接口,然後在onMessage()方法中監聽消息的到達並處理。
2.2 創建Connection:根據url,user和password創建一個jms Connection,如果是durable模式,還需要給connection設置一個clientId。
2.3 創建Session和Destination
2.4創建replyProducer【可選】:可以用來將消息處理結果發送給producer。
2.5 創建MessageConsumer: 根據Destination創建MessageConsumer對象。
2.6 消費message:在onMessage()方法中接收producer發送過來的消息進行處理,並可以通過replyProducer反饋信息給producer。

7.JMS消息的事務
(1)創建事務createSession(paramA,paramB)
paramA是設置事務的,paramB設置acknowledgment mode(應答模式)
paramA設置爲false時:paramB的值可爲Session.AUTO_ACKNOWLEDGE,Session.CLIENT_ACKNOWLEDGE,
DUPS_OK_ACKNOWLEDGE其中一個。

(2)事務的應答確認
A)paramA設置爲true時:
paramB的值忽略, acknowledgment mode被jms服務器設置 SESSION_TRANSACTED 。當一個事務被提交的時候,消息確認就會自動發生。
B) paramA設置爲false時:
Session.AUTO_ACKNOWLEDGE爲自動確認,當客戶成功的從receive方法返回的時候,或者從
MessageListener.onMessage方法成功返回的時候,會話自動確認客戶收到的消息。
Session.CLIENT_ACKNOWLEDGE 爲客戶端確認,客戶端接收到消息後,必須調用javax.jms.Message的
acknowledge方法,jms服務器纔會刪除消息。(默認是批量確認)
DUPS_OK_ACKNOWLEDGE 允許副本的確認模式,一旦接收方應用程序的方法調用從處理消息處返回,會
話對象就會確認消息的接收,而且允許重複確認。如果是重複的消息,那麼JMS provider必須把消息頭的JMSRedelivered字段設置爲true。

8.消費者的消費方式
1)同步消費:通過調用消費者的receive方法從目的地中顯式提取消息。receive方法可以一直阻塞到消息到達。
2)異步消費:客戶可以爲消費者註冊一個消息監聽器,以定義在消息到達時所採取的動作。實現MessageListener接口,在MessageListener()方法中實現消息的處理邏輯。

9.JMS的通信機制
這裏寫圖片描述

activeMQ支持多種通訊協議TCP/UDP等,我們選取最常用的TCP來分析activeMQ的通訊機制。首先我們來明確一個概念:
1)客戶(Client):消息的生產者、消費者對activeMQ來說都叫作客戶。
2)消息中轉器(Message broker):它是activeMQ的核心,它接收信息並進行相關處理後分發給消息消費者。

爲了能清楚的描述出activeMQ的核心通訊機制,我們選擇3個部分來進行說明,它們分別是建立鏈接、關閉鏈接、心跳。

一、Client跟activeMQ的TCP通訊的初始化過程分析如下:
1. activeMQ初始化時,通過TcpTransportServer類根據配置打開TCP偵聽端口,客戶通過該端口發起建立鏈接的動作。
2. 把accept的Socket放入阻塞隊列中。
3. 另外一個線程Socket handler阻塞着等待隊列中是否有新的Socket,如果有則取出來。
4. 生成一個TransportConnection的實例。TransportConnection類的主要作用是處理鏈路的狀態信息,並實現CommandVisitor接口來完成各類消息的處理。
5. TransportConnection會使用一個由多個TransportFilter實例組成的消息處理鏈條,負責對接收到的各類消息進行處理併發送相應的應答。這個鏈條的典型組成順序:MutexTransport->WireFormatNegotiator->InactivityMonitor->TcpTransport。在這條鏈條中最後的一環就是TcpTransport類,它是實際和Client獲取和發送數據的地方,該類的重要。
6. 建鏈完成,可以進行通訊操作。方法有run()和oneway(),一個負責讀取,一個負責發送。

二、關閉鏈接
1. activeMQ發現TCP鏈接的關閉,最關鍵的代碼在TcpBufferedInputStream類中的 int n = in.read(buffer, position, buffer.length - position);

三、心跳
爲了更好的維護TCP鏈路的使用,activeMQ採用了心跳機制作爲判斷雙方鏈路的健康情況。activeMQ使用的是雙向心跳,也就是activeMQ的Broker和Client雙方都進行相互心跳,但不管是Broker或Client心跳的具體處理情況是完全一樣的,都在InactivityMonitor類中實現,下面具體介紹。
1. 心跳會產生兩個線程“InactivityMonitor ReadCheck”和“InactivityMonitor WriteCheck”,它們都是Timer類型,都會隔一段固定時間被調用一次。ReadCheck線程主要調用的方法是readCheck(),當在等待時間內,有消息接收到,則該方法會返回true。WriteCheck線程主要調用的方法是writeCheck(),這有個小技巧,大家可以參考一下,那就是當WriteCheck線程休眠時,有任何數據發送成功,則該線程被喚醒後,不用通過TCP向對方真的發送心跳消息,這樣可以從一定程度上減少網絡傳輸的數據量。

10.ActiveMQ模型分析
首先介紹該模型中每個領域類的作用,然後再介紹它們之間的關係。
Broker:activeMQ的一個整體代表
RegionBroker:負責分發broker的操作到相應的消息區域
Region:activeMQ目前有四種主要消息區域:隊列域(queueRegion)、主題域(topicRegion)、臨時隊列域(tempQueueRegion)、臨時主題域(tempTopicRegion)
TransportConnection:代表一個通訊連接
Destination:消息的目的地,主要包括兩種Queue、Topic兩種
Subscription:消息的消費者、訂閱者
MessageStore:消息持久化存儲,像比較複雜的Kaha存儲機制就放在這
PendingMessageCursor:等待發給消費者的消息分發指針
ConnectionContext:用來維護髮送請求所需的連接上下文

1)ActiveMQ模型分析—靜態模型
這裏寫圖片描述
下面我們把這些領域類的關係進行一個描述:
1、一個RegionBroker擁有4種消息域的對象。
2、RegionBroker擁有所有目的地對象(destination)
3、每個消息域(Region)也擁有它們對應的0或N個目的地對象(destination)
4、同時每個Region也擁有它們對應的0或N個消息消費者、訂閱者(subscription)
5、每個目的地都有一個相應的持久化存儲方式(messageStore),以及一個等待發送的消息分發指針(pendingMessageCursor)
6、消息消費者和目的地可以彼此擁有0或N個
7、每個消費者都有一個對應的ConnectionContext,ConnectionContext裏包括一個TransportConnection對象,通過TransportConnection把真實的消息發給消費者。
8、TransportConnection也可以做爲通訊連接,偵聽消息生產者發出的信息,所以每個TransportConnection會指向Broker對象。

2)ActiveMQ模型分析—–動態模型
這裏寫圖片描述
消費生產者進程向activeMQ所在進程發送消息和消費者消費消息的過程如上圖所示,消息傳遞的路徑經過了核心領域模型,具體步驟如下:
1、生產者通過向activeMQ爲它建立好的TransportConnection發送消息給activeMQ
2、TransportConnection對象找到RegionBroker
3、RegionBroker根據消息的類型找到對應的消息區域(Region)
4、該Region在它自己裏面找到相應的消息目的地。
5、6:該目的地首先根據需要進行持久化操作,並使用待發送消息指針對象
7、當有合適的消息消費者、訂閱者來到時,目的地會找到這些消費者
8、9:通過該消費者對應的TransportConnection,發給相應的消費者進程

11.ActiveMQ消息分發指針
消息分發遊標是用來保存JMS消息的引用,消息遊標的處理過程如下:
1.當producer發送的持久化消息到達broker之後,broker首先會把它保存在持久存儲中
2.如果發現當前有活躍的consumer,而且這個consumer消費消息的速度能跟上producer生產消息的速度,那麼ActiveMQ會直接把消息傳遞給broker內部跟這個consumer關聯的queue。
3.如果當前沒有活躍的consumer或者consumer消費消息的速度跟不上producer生產消息的速度,那麼ActiveMQ會使用Pending Message Cursors保存對消息的引用。
4.Pending Message Cursors把消息引用傳遞給broker內部跟這個consumer關聯的dispatch queue。以下是兩種Pending Message Cursors:
• VM Cursor 在內存中保存消息的引用
• File Cursor 首先在內存中保存消息的引用,如果內存使用量達到上限,那麼會把消息引用保存到臨時文件中。
我們可以在activemq.xml 中配置消息分發指針的存儲策略。

12.ActiveMQ的監控
1.activeMQ自動的管理站點
http://localhost:8161/admin
2.Advisory Messages
ActiveMQ 支持Advisory Messages,它允許我們通過標準的JMS 消息來監控系統.通過它我們可以得到關
於JMS provider、producers、consumers和destinations的信息。
3.QueueBrowser
使用QueueBrowser的消息預覽,編程提供監控接口。

13.ActiveMQ配置連接URI
1.配置JMS連接最大閒置時間(消息服務器無消息)
jmsBrokerURL = tcp://218.241.100.165:61616?wireFormat.maxInactivityDuration=90000
該wireFormat.maxInactivityDuration = 90000的默認值是30000ms
wireFormat.maxInactivityDuration=0 這樣的參數, wireFormat.maxInactivityDuration是心跳參數。
避免ActiveMQ在一段時間沒有消息發送時拋出 “Channel was inactive for too long”異常。
2.maxReconnectDelay 最大重連間隔
failover:(tcp://127.0.0.1:61616?wireFormat.maxInactivityDuration=10000);maxReconnectDelay=10000
failover:(tcp://localhost:61616,tcp://remotehost:61616)?initialReconnectDelay=100
failover 失效備援
maxReconnectDelay=10000 最大重連間隔
3.設置異步發送消息
tcp://localhost:61616?jms.useAsyncSend=true
tcp://localhost:61616?jms.prefetchPolicy.all=100&jms.redeliveryPolicy.maximumRedeliveries=5
4.客戶端消息緩存的數量
tcp://localhost:61616?jms.prefetchPolicy.all=50 ##設置客戶端最多緩存50條消息
5.客戶端的預支取策略。
tcp://localhost:61616?jms.prefetchPolicy.queuePrefetch=1

14.ActiveMQ穩定性和容錯性考慮
1.保障Jms連接
使用失效備援機制,和間隔自動重試機制,程序控制等方面來控制。
failover:(tcp://localhost:61616)?initialReconnectDelay=100&;maxReconnectAttempts=5
failover transport是一種重新連接機制,用於建立可靠的傳輸。此處配置的是一旦ActiveMQ broker中斷,Listener端將每隔100ms自動嘗試連接,直至成功連接或重試5次連接失敗爲止。
failover還支持多個borker同時提供服務,實現負載均衡的同時可增加系統容錯性,格式:failover:(uri1,…,uriN)?transportOptions
failover://(tcp://masterhost:61616,tcp://slavehost:61616)?randomize=false
failover:(uri1,…,uriN)?transportOptions
failover:uri1,…,uriN
failover:(tcp://localhost:61616)
2.JMSRedelivered
如果這個值爲true,表示消息是被重新發送了。因爲有時消費者沒有確認他已經收到消息或者JMS提供者不確定消費者是否已經收到。
3.JMSExpiration
允許消息過期, setTimeToLive()設置消息的有效期。

15.ActiveMQ的failOver重連機制
“failover:(tcp://IPAddress1:61616,tcp://IPAddress1:61616)?initialReconnectDelay=100&maxReconnectAttempts=5”;
後面的參數initialReconnectDelay=100&maxReconnectAttempts=5“對每一個連接URI是通用的。
如果沒有指定URI的獲取方式,activeMQ會自動選擇其中的一個URI來嘗試建立連接(randomize 指定隨機),獲取連接後,ActiveMQ會維護連接的暫停和恢復。

以上面的URL爲例,說明failOver的重連機制:
a. IPAddress1, IPAddress2上的broker1,broker2都正常運行,創建的Connection會使用IPAddress1的broker1來發送消息,這時不激活消費者。
b.關閉broker1,Connection會自動切換到broker2的URI上來發送消息。
c. 激活消費者,消費者會先嚐試broker1,由於broker1不可用,使用broker2來收消息,
這時只能收到broker2上的消息。
d.再重新啓動broker1,生產者,和消費者都仍然使用broker2來發送和接受消息。
e. 關閉broker2,生產者和消費者都會自動切換到broker1上,消費者就收到之前broker發送的消息了。
這裏寫圖片描述

16.ActiveMQ安全管理
1.編程式實現
通過ActiveMQ提供的實現添加消息用戶的權限(由SimpleAuthenticationPlugin類實現)。
2.配置實現
配置mq訪問者信息, activemq安裝目錄下/conf/credentials.properties權限管理 , 在${ACTIVEMQ_HOME}/conf/activemq.xml 中配置

<plugins>
    <simpleAuthenticationPlugin>
    </simpleAuthenticationPlugin>
    <authorizationPlugin>
    </authorizationPlugin>
</plugins>

17.調整TCP傳輸設置
TCP傳輸是activeMQ最常用的傳輸方式。其中socketBufferSize和tcpNoDelay對傳輸性能有較大的影響。
socketBufferSize 通過tcp傳輸發送和接受數據的緩衝區大小,默認( 65536 bytes)
tcpNoDelay - 默認爲false。通常一個TCP socket緩衝區創建小的數據在發送之前。啓用此選項 - 消息將被儘快發送。
url = “failover://(tcp://localhost:61616?tcpNoDelay=true)”;

18.ActiveMQ集羣部署
1.多個消息提供者
使用Network of brokers,以便在broker之間存儲轉發消息。
2.多個消息消費者
ActiveMQ支持訂閱同一個queue的consumers上的集羣。如果一個consumer失效,那麼所有未被確認(unacknowledged)的消息都會被髮送到這個queue上其它的consumers。如果某個consumer的處理速度比其它consumers更快,那麼這個consumer就會消費更多的消息。
這裏寫圖片描述

Master/salve Server
1.主輔服務器的作用
主輔服務器:提供消息服務。
輔服務器:提供消息的備份,服務的備份。
2.Pure Master Slave的工作方式
A)服務端:
Slave broker消費master broker上所有的消息狀態,例如消息、確認和事務狀態等。
Slave broker不提供消息服務。
Master broker只有在消息成功被複制到slave broker之後纔會響應客戶。
master broker失效的時候,slave broker可以啓動network connectors和transport connectors,提供消息服務,也可以跟着停止。
B)客戶端:
使用failover的機制 uri = “failover://(tcp://masterhost:61616,tcp://slavehost:61616)?randomize=false ”;
3.配置
Master broker不需要特殊的配置。
Slave broker需要進行以下配置:

<broker masterConnectorURI="tcp://masterhost:62001" shutdownOnMasterFailure="false"> 

4.限制
只能有一個slave broker連接到master broker。
master broker失效而導致slave broker成爲master之後,之前的master broker只有在當前的master broker(原slave broker)停止後才能重新生效。

19.Spring和ActiveMQ的結合
使用spring對jms的支持,配置jms的各個組件
1 配置jms連接工廠

<amq:connectionFactory id="jmsConnectionFactory" brokerURL="vm://localhost" />

2 配置消息隊列

<amq:queue name="destination" physicalName=“queuename" />

3 配置消息監聽器

<bean id="messageListener"
    class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
    <constructor-arg>
        <bean class=“類路徑"></bean>
    </constructor-arg>
    <!--  配置監聽到jms方法後調用的執行方法-->
    <property name="defaultListenerMethod" value="printMyOut" />
    <!-- custom MessageConverter define -->
    <property name="messageConverter" ref="invokeMessageConverter" /
</bean>

4 配置消息監聽容器

<bean id="listenerContainer"
        class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="jmsConnectionFactory" />
        <property name="destination" ref="destination" />
        <property name="messageListener" ref="messageListener" />
</bean>

5 配置jms消息轉換器

<bean id="invokeMessageConverter" class="com.components.jms.InvokeMessageConverter" />

6.配置Spring的jms處理模版類(jmsTemplte)

<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory">
        <ref local="jmsFactory" />
    </property>
    <property name="defaultDestinationName" value="subject" />
    <!--
    區別它採用的模式爲false是p2p爲true是訂閱
    <property name="pubSubDomain" value="true"/>
    -->
    <!-- custom MessageConverter -->
    <property name="messageConverter" ref="invokeMessageConverter" />
</bean>

7.消息生產者和消息消費者
該部分可以根據業務需要,用戶自己編程實現。

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