ActiveMQ進階特性:虛擬Destinations實現消費者分組與簡單路由

來源:互聯網
上載者:User

ActiveMQ支援的虛擬Destinations分為有兩種,分別是

Ø  虛擬主題(Virtual Topics)

Ø  組合 Destinations(CompositeDestinations)

這兩種虛擬Destinations可以看做對簡單的topic和queue用法的補充,基於它們可以實現一些簡單有用的EIP功能,虛擬主題類似於1對多的分支功能+消費端的cluster+failover,組合Destinations類似於簡單的destinations直接的路由功能。

 

1.   虛擬主題(Virtual Topics)

ActiveMQ中,topic只有在持久訂閱(durablesubscription)下是持久化的。存在持久訂閱時,每個持久訂閱者,都相當於一個持久化的queue的用戶端,它會收取所有訊息。這種情況下存在兩個問題:

1.        同一應用內consumer端負載平衡的問題:同一個應用上的一個持久訂閱不能使用多個consumer來共同承擔訊息處理功能。因為每個都會擷取所有訊息。queue模式可以解決這個問題,broker端又不能將訊息發送到多個應用端。所以,既要發布訂閱,又要讓消費者分組,這個功能jms規範本身是沒有的。

2.        同一應用內consumer端failover的問題:由於只能使用單個的持久訂閱者,如果這個訂閱者出錯,則應用就無法處理訊息了,系統的健壯性不高。

為瞭解決這兩個問題,ActiveMQ中實現了虛擬Topic的功能。使用起來非常簡單。

對於訊息發行者來說,就是一個正常的Topic,名稱以VirtualTopic.開頭。例如VirtualTopic.TEST。

對於訊息接收端來說,是個隊列,不同應用裡使用不同的首碼作為隊列的名稱,即可表明自己的身份即可實現消費端應用分組。例如Consumer.A.VirtualTopic.TEST,說明它是名稱為A的消費端,同理Consumer.B.VirtualTopic.TEST說明是一個名稱為B的用戶端。可以在同一個應用裡使用多個consumer消費此queue,則可以實現上面兩個功能。又因為不同應用使用的queue名稱不同(首碼不同),所以不同的應用中都可以接收到全部的訊息。每個用戶端相當於一個持久訂閱者,而且這個用戶端可以使用多個消費者共同來承擔消費任務。

 

Virtual Topics使用樣本如下

package kk;import java.util.concurrent.atomic.AtomicInteger;import javax.jms.Message;import javax.jms.MessageConsumer;import javax.jms.MessageListener;import javax.jms.MessageProducer;import javax.jms.Queue;import javax.jms.Session;import javax.jms.TextMessage;import org.apache.activemq.ActiveMQConnection;import org.apache.activemq.ActiveMQConnectionFactory;import org.apache.activemq.command.ActiveMQQueue;import org.apache.activemq.command.ActiveMQTopic;public class TestVirtualTopic {public static void main(String[] args) {try {ActiveMQConnectionFactory factoryA = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");Queue queue = new ActiveMQQueue(getVirtualTopicConsumerNameA());ActiveMQConnection conn = (ActiveMQConnection) factoryA.createConnection();conn.start();Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);MessageConsumer consumer1 = session.createConsumer( queue );MessageConsumer consumer2 = session.createConsumer( queue );MessageConsumer consumer3 = session.createConsumer( new ActiveMQQueue(getVirtualTopicConsumerNameB()) );final AtomicInteger aint1 = new AtomicInteger(0);MessageListener listenerA = new MessageListener() {public void onMessage(Message message) {try {System.out.println(aint1.incrementAndGet()+ " => receive from "+ getVirtualTopicConsumerNameA() +": " + message);} catch (Exception e) {e.printStackTrace();}}};consumer1.setMessageListener(listenerA);consumer2.setMessageListener(listenerA);final AtomicInteger aint2 = new AtomicInteger(0);MessageListener listenerB = new MessageListener() {public void onMessage(Message message) {try {System.out.println(aint2.incrementAndGet()+ " => receive from "+ getVirtualTopicConsumerNameB() +": " + message);} catch (Exception e) {e.printStackTrace();}}};consumer3.setMessageListener(listenerB);MessageProducer producer = session.createProducer(new ActiveMQTopic(getVirtualTopicName()));int index = 0;while (index++ < 100) {TextMessage message = session.createTextMessage(index+ " message.");producer.send(message);}} catch (Exception e) {e.printStackTrace();}}  protected static String getVirtualTopicName() {        return "VirtualTopic.TEST";    }    protected static String getVirtualTopicConsumerNameA() {        return "Consumer.A.VirtualTopic.TEST";    }        protected static String getVirtualTopicConsumerNameB() {        return "Consumer.B.VirtualTopic.TEST";    }}

 

使用同樣queue名稱的消費者會平分所有訊息。

從queue接收到的訊息,message.getJMSDestination().toString()為topic://VirtualTopic.TEST,即原始的destination。訊息的persistent屬性為true,即每個相當於一個持久訂閱。

Virtual Topic這個功能特性在broker上有個總開關,useVirtualTopics屬性,預設為true,設定為false即可關閉此功能。

當此功能開啟,並且使用了持久化的儲存時,broker啟動的時候會從持久化儲存裡拿到所有的destinations的名稱,如果名稱模式與Virtual Topics匹配,則把它們添加到系統的Virtual Topics列表中去。當然,沒有顯式定義的Virtual Topics,也可以直接使用的,系統會自動建立對應的實際topic。

當有consumer訪問此VirtualTopics時,系統會自動建立持久化的queue,並在每次Topic收到訊息時,分發到具體的queue。

消費端使用的queue名稱首碼的Consumer是可以修改的。樣本如下:

<beans  xmlns="http://www.springframework.org/schema/beans"  xmlns:amq="http://activemq.apache.org/schema/core"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd  http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd"> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />   <broker xmlns="http://activemq.apache.org/schema/core">    <destinationInterceptors>      <virtualDestinationInterceptor>        <virtualDestinations>          <virtualTopic name=">"prefix="VirtualTopicConsumers.*."selectorAware="false"/>        </virtualDestinations>      </virtualDestinationInterceptor>    </destinationInterceptors>   </broker></beans>

首碼修改成了VirtualTopicConsumers。

其實也可以使用postfix屬性設定尾碼(貌似一般沒有必要)。

selectorAware屬性則表明如果consumer端有selector,則只有匹配selector的訊息才會指派到對應的queue中去。

 

2.   組合Destinations (Composite Destinations)

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.