一个机器上启动多个Broker

可以理解成一个伪分布式的ActiveMQ集群。

ActiveMQ消费消息同步问题_java

Linux上:

cd activemq-5.9.0

cp -r conf conf2

针对我安装在windows上的MQ来操作一下。

0.复制文件夹

ActiveMQ消费消息同步问题_操作系统_02

1.conf2修改里面的一些配置

修改conf2中activemq.xml核心配置文件中broker里面的:broker的名字、存储的位置的名字、客户端连接MQ各种协议端口号:

(1)<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost2" dataDirectory="${activemq.data}">
(2)<persistenceAdapter>
             <kahaDB directory="${activemq.data}/kahadb2"/>
 </persistenceAdapter>

ActiveMQ消费消息同步问题_网络_03

<transportConnectors>
  <transportConnector name="openwire" uri="tcp://0.0.0.0:61776?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
  <transportConnector name="amqp" uri="amqp://0.0.0.0:5772?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
  <transportConnector name="stomp" uri="stomp://0.0.0.0:61713?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
  <transportConnector name="mqtt" uri="mqtt://0.0.0.0:1783?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
  <transportConnector name="ws" uri="ws://0.0.0.0:61714?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
 </transportConnectors>

修改访问web界面端口号(conf/jetty.xml):

<bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start">
              <!-- the default port number for the web console -->
         <property name="port" value="8181"/>
 </bean>

2.修改bin2/activemq的文件

ActiveMQ消费消息同步问题_接收端_04

ActiveMQ消费消息同步问题_java_05

前面介绍过的启动MQ的broker(服务),启动的文件是:

ActiveMQ消费消息同步问题_ActiveMQ消费消息同步问题_06

cd activemq-5.9.0/bin/

cp activemq activemq2

ActiveMQ消费消息同步问题_接收端_07

修改这个文件的内容:

(1)

# Location of the pidfile
 if [ -z "$ACTIVEMQ_PIDFILE" ]; then
   ACTIVEMQ_PIDFILE="$ACTIVEMQ_DATA/activemq2-`hostname`.pid"
 fi(2)
if [ -z "$ACTIVEMQ_CONF" ] ; then
    # For backwards compat with old variables we let ACTIVEMQ_CONFIG_DIR set ACTIVEMQ_CONF
     if [ -z "$ACTIVEMQ_CONFIG_DIR" ] ; then
         ACTIVEMQ_CONF="$ACTIVEMQ_BASE/conf2"
     else
         ACTIVEMQ_CONF="$ACTIVEMQ_CONFIG_DIR"
     fi
 fi

3.修改:\bin2\win64\activemq.bat

ActiveMQ消费消息同步问题_网络_08

4.修改:\bin2\win64\wrapper.conf

ActiveMQ消费消息同步问题_java_09

ActiveMQ消费消息同步问题_网络_10

ActiveMQ消费消息同步问题_ActiveMQ消费消息同步问题_11

如果启动不起来,就需要对activemq2文件授权:chmod 751 activemq2,这样就实现了一台机器上启动多个broker。

启动Windows上的两个Broker。就是启动两个bin下的64位下的activemq.bat文件。

访问两个broker的web管理界面:

http://localhost:8161/admin/

http://localhost:8181/admin/

在Myeclipse中使用的时候可以分别连接两个broker,测试发送接收一个消息:

ActiveMQ消费消息同步问题_java_12

ActiveMQ消费消息同步问题_网络_13

ActiveMQ的网络的连接

ActiveMQ的broker之间的网络连接:

ActiveMQ消费消息同步问题_网络_14

    比如现在有两个broker:A、B。broker-A端有自己的生产者和消费者,broker-B端也有自己的生产者和消费者。两个broker之间的通信可以是单向的,也可以是双向的。默认使用的是单向的。

(1)单向通信:比如从A到B。给broker-A发送消息,消息会流到broker-B,在broker-B端可以被消费,但是给broker-B发消息,消息不会流到broker-A,broker-A端的消费者不能消费消息。

(2)双向通信:无论给哪一段发消息,两个broker都能消费消息。

ActiveMQ消费消息同步问题_操作系统_15

broker之间的网络连接有两种方式:一种是静态发现(静态连接方式),一种是动态发现(动态连接方式)。

(1)静态连接方式

ActiveMQ消费消息同步问题_java_16

ActiveMQ消费消息同步问题_ActiveMQ消费消息同步问题_17

现在来操作一下。修改一个broker中的activemq.xml文件,添加静态网络配置(关于消息的存储还原回原来的KahaDB方式):

ActiveMQ消费消息同步问题_网络_18

默认单向就是从61676-->61776的broker。

ActiveMQ消费消息同步问题_操作系统_19

ActiveMQ消费消息同步问题_操作系统_20

针对windows上的操作一下,操作的是tcp端口为61616的那个broker:

<networkConnectors>
        <networkConnector name="local network" uri="static://(tcp://localhost:61616,tcp://localhost:61776)" ></networkConnector>    
</networkConnectors>//默认的单向就是从61616到61776

        重新启动两个broker,测试PTP传递域的代码,运行发送端和接收端。因为默认使用的是单向的连接,现在要测试静态单向连接的broker伪分布式,所以需要修改连接端和消费端连接的端口,分别连接不同的broker:

ActiveMQ消费消息同步问题_接收端_21

 

    根据在核心配置文件中配置的静态连接单向方向是61676-->61776,所以就是发给61676的broker,然后消息会传递到61776的broker中。所以可以从61776的broker中进行消费。

    运行发送端接收端的代码,查看MQ的web管理界面。因为此时是两个broker,所以需要分别连接两个不同的URL分别查看消息的变化。如果把接收端的端口改为61676,就是生产端和消费端是同一个broker,查看web界面消息的变化都是来自同一个broker,另一个61776的broker是没有变化的。消息就只会在一个broker中进行进出。

针对windows上的MQ:

ActiveMQ消费消息同步问题_接收端_22

ActiveMQ消费消息同步问题_网络_23

applicationContext.xml中配置的连接不动:

ActiveMQ消费消息同步问题_java_24

就是消息是发送给61616的,但是消息会传送到61776上,启动两个broker,启动两个web管理界面:

ActiveMQ消费消息同步问题_ActiveMQ消费消息同步问题_25

ActiveMQ消费消息同步问题_网络_26

配置了静态的单向连接,发给61616的消息会传送到61776,所以从61776可以接收到消息。

如果发到61616上,也可以从61616上接收到:

ActiveMQ消费消息同步问题_java_27

因为两个broker配置了连接,所以两个web界面上都可以看到上面的消息。

所以配置了静态单向连接A->B,发给A消息,从B端也可以接收到消息,当然也可以从A端的消费者中消费消息。但是注意的是:PTP消息是存放在队列中的,消费一次后就清除了,一个消息只能被一个消费者消费。但是Pub/Sub消息,消息是不会清除的,因为他要发布给很多的订阅者,一个消息可以有很多的消费者。

如果applicationContext.xml中配置的连接仍然是61616(没有任何影响)。发送给61776,然后从61616接收就接收不到消息。这是因为:在这个broker集群中配置的是61616-->61776的单向连接,消息不会从61776流向61616的。所以如果消息发送给61776,消费者从61776可以接收到消息,但是从61616接收不到消息,因为消息不能逆向回流。

核心配置文件中网络连接networkConnection的可以使用的属性:

ActiveMQ消费消息同步问题_java_28

        第七个属性是有关负载均衡的时候。比如BrokerB有两个消费者,还有一个远程的BrokerA消费者,属性值是true的时候,BrokerB就会把他的两个消费者当作1个,也就是说BrokerB分消息的时候只会分成两份。如果参数值是false,那么就会把BrokerB的消息分成三份分发。 

      第八、九个参数的作用是实现消息过滤。我们上面配置的网络连接,发送端BrokerA发送消息的时候会全部的转到接收端BrokerB上,但是有的时候这样是不对的,有的时候是想过滤的,就是说把部分消息转为接收端BrokerB中的。所以如果我们配置的是静态网络连接,想达到消息在Broker之间的过滤就用第九个参数,如果我们配置的是动态网络连接,想达到消息在Broker之间的过滤就用第八个参数。   

 

ActiveMQ消费消息同步问题_ActiveMQ消费消息同步问题_29

        第十一个参数是设置不同broker的双向网络连接的。比如在核心配置文件中进行下面的使用:

ActiveMQ消费消息同步问题_操作系统_30

这样配置之后就建立了BrokerA与BrokerB之间的双向连接。A发消息B可以接到,B发消息A可以接到。测试双向连接,需要来回的更改发送端接收端的端口,这样通过web就可以看到结果。

        第十二个参数就是我们常说的ActiveMQ的缓存的时候可以缓存的未消费的消息的数量,是为了提高性能的,在这里设置可以缓存的未消费的消息的个数。

        比如现在BrokerA和BrokerB配置的静态双向连接,如果说此时BrokerA和BrokerB两端都各自还有消费者,那么到底谁消费的消息会多一点呢?这就涉及到消息消费者的负载均衡,后面讲。

broker双向连接的消息回流

ActiveMQ消费消息同步问题_ActiveMQ消费消息同步问题_31

        出现上述的消息丢失的情况,即使使用双向网络连接也是解决不了的,所以可以使用ActiveMQ5.6增加的replayWhenNoConsumers属性设置。所以修改两个broker的核心配置文件activemq.xml:

ActiveMQ消费消息同步问题_接收端_32

        重新启动两个broker,然后测试运行发送端和接收端的代码,演示运行的过程中某个broker下线了,另一个broker端的消费者可以全部消费未消费的消息,包括回流的消息。所以消息可以回流在ActiveMQ的集群中是非常有用的。

针对windows上的ActiveMQ来操作一下上面介绍的消息回流。还是操作61616的activemq.xml文件,在broker标签里面的:

<destinationPolicy>
             <policyMap>
               <policyEntries>标签里面添加一个policyEntry配置消息回流:
 <policyEntry queue=">" enableAudit="false">    
       <networkBridgeFilterFactory>        
              <conditionalNetworkBridgeFilterFactory replayWhenNoConsumers="true"/>    
        </networkBridgeFilterFactory>
   </policyEntry>修改networkConnectors标签里面的networkConnector标签,添加duplex="true"双向连接(61616和61776的双向连接):
<networkConnectors>
    <networkConnector name="local network"  duplex="true"  uri="static://(tcp://localhost:61616,tcp://localhost:61776)" ></networkConnector>  
 </networkConnectors>applicationContext.xml中配置的连接的还是61616,为了测试修改一个PTP类型的发送端和接收端的代码。
上面的修改对conf和conf2中的核心配置文件都做同样的修改。
发送端:
package test1;
 import javax.jms.Connection;
 import javax.jms.ConnectionFactory;
 import javax.jms.Destination;
 import javax.jms.JMSException;
 import javax.jms.MessageProducer;
 import javax.jms.Queue;
 import javax.jms.Session;
 import javax.jms.TextMessage;
 import org.apache.activemq.ActiveMQConnectionFactory;
 //PTP模式的发送端
 public class QueueSender {
     public static void main(String[] args) throws Exception {
         ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");//发送到61616上
         Connection con = connectionFactory.createConnection();
         con.start();
         
         Session session = con.createSession(true, Session.AUTO_ACKNOWLEDGE);
         Destination destination = session.createQueue("my-queue");
         MessageProducer producer = session.createProducer(destination);
         for(int i=0;i<10;i++){
             TextMessage message = session.createTextMessage("message--"+i);
             message.setStringProperty("stringProperty"+i, "property1"+i);
             producer.send(message);
         }
         session.commit();
         session.close();
         con.close();
     }
 }

接收端:

package test1;
 import java.util.Enumeration;
 import javax.jms.Connection;
 import javax.jms.ConnectionFactory;
 import javax.jms.Destination;
 import javax.jms.MessageConsumer;
 import javax.jms.MessageProducer;
 import javax.jms.Session;
 import javax.jms.TextMessage;
 import org.apache.activemq.ActiveMQConnectionFactory;
 //PTP模式的接收端
 public class QueueReceiver {
     public static void main(String[] args) throws Exception {
         ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61776");//从61776接收
         Connection con = connectionFactory.createConnection();
         con.start();
         
         Enumeration jmsxPropertyNames = con.getMetaData().getJMSXPropertyNames();
         while(jmsxPropertyNames.hasMoreElements()){
             String element = (String)jmsxPropertyNames.nextElement();
             System.out.println("jms name="+element);
         }
         Session session = con.createSession(true, Session.AUTO_ACKNOWLEDGE);
         Destination destination = session.createQueue("my-queue");
         MessageConsumer consumer = session.createConsumer(destination);
         int i =0;
         while(i<10){
             Thread.sleep(2000);//让接收端接收的慢一点
             TextMessage message = (TextMessage)consumer.receive();
             session.commit();
             System.out.println("接收到的消息:"+message.getText()+"--接收到的属性:"+message.getStringProperty("stringProperty"+i));
             i++;
         }
         session.close();
         con.close();
     }
 }

启动bin和bin2下的64位的activemq.bat文件。启动发送端,查看web界面:

ActiveMQ消费消息同步问题_java_33

ActiveMQ消费消息同步问题_网络_34

然后启动接收端,让他接收两个消息之后下线,观察web界面:

ActiveMQ消费消息同步问题_操作系统_35

ActiveMQ消费消息同步问题_操作系统_36

ActiveMQ消费消息同步问题_网络_37

此时61776一端下线了,因为在双向连接中配置了消息回流机制,所以61776端没有消费的消息又回流会61616端了,所以让61616端接收也可以接收到了:

ActiveMQ消费消息同步问题_接收端_38

ActiveMQ消费消息同步问题_java_39

观察web界面:

ActiveMQ消费消息同步问题_接收端_40

ActiveMQ消费消息同步问题_ActiveMQ消费消息同步问题_41

把61616端的broker称为A,把61776端的broker称为B。理解一下上面的显示:

(1)首先消息发送给A10个,然后B端消费了2个,所以B端还剩8个消息。

(2)配置了消息回流,从A端消费消息,这样B端的消息就回流回了A端,此时A端进来了8个,消费了2个,所以A端还剩6个没有消费。

同理此时B端连接上进行消费的话,消息又会回流进行消费的。

容错的链接Failover协议----broker的负载均衡

ActiveMQ消费消息同步问题_java_42

上面介绍的是连接MQ的时候使用的协议是failover协议,并且randomize的值必须是true:

ActiveMQ消费消息同步问题_ActiveMQ消费消息同步问题_43

解释一下为什么使用failover协议,为什么randomize的值必须是true?

(1)使用failover协议,可以配置连接多个broker的url。这里连接的时候连的还是1个broker。使用broker的时候首先会连接第一个url(broker),但是第一个broker挂了怎么办?会影响MQ的使用,所以使用failover协议,第一个broker挂了可以直接使用第二个broker,但是前提是randomize的值必须是true。

(2)randomize的值必须是true,因为虽然使用了failover协议,但是如果第一个broker挂了,就不会使用第二个broker,因为randomize的值是false,但是如果改为true,就会自动使用第二个broker了。当randomize的值是true的时候,如果两个broker都存在,消息就会随机的发送到两个broker上。

ActiveMQ消费消息同步问题_java_44

从今往后,我们java代码连接ActiveMQ就推荐使用这种协议。

ActiveMQ消费消息同步问题_java_45

连接MQ的时候用randomize实现了broker的负载均衡,以后介绍消费者的负载均衡。

(2)动态连接方式

ActiveMQ消费消息同步问题_网络_46

ActiveMQ消费消息同步问题_java_47

ActiveMQ消费消息同步问题_接收端_48

ActiveMQ消费消息同步问题_网络_49

ActiveMQ消费消息同步问题_网络_50

ActiveMQ消费消息同步问题_java_51

ActiveMQ消费消息同步问题_网络_52