JMS学习九(ActiveMQ集群)

上一篇文章中我们说到了失效转移(failover),网络连接器(networkconnection),下面我们就来实践一下即搭建Broker集群,Broker集群的搭建就使用到了failover和networkconnection,如果对failover和networkconnection不了解的可以看看上一篇文章,这里就不重复。

如果应用的访问量不大或者说使用ActiveMQ进行消息发送量不大的则我们可以使用单个消息服务来实现但是如果应用中使用ActiveMQ发送消息的量很大或者说对稳定性、吞吐量要求都很高的话则不能使用单个消息服务了,就要使用集群来实现了。下面看看各种集群方案的改进。

1、第一简单而不太好的设计


方案设计说明:

Broker1 消息服务,接收发送过来的消息。

Broker2和Broker1之间有网络连接器连接,需要的情况下Broker2会从Broker1读取消息。

Broker3和Broker1之间有网络连接器连接,需要的情况下Broker3会从Broker1读取消息。

Broker2和Broker3之间有网络连接器并且是双向的,在需要的情况下可以相互读取消息。

这种方案在不使用failover的情况下,消息路由路径

(1)、P、B1、B2、C

(2)、P、B1、B3、B2、C

这种架构看上去没问题,但这种方式有两个缺点:

(1)、接受消息生产者的消息服务器只有一个,即消息的物理保存点只有一个,如果Broker1出现问题则整个消息发送就玩完了!

(2)、从消息路由的角度来说也不是一个好的设计(访问网络多了不太好慢,路由路劲要控制在一定范围即木桶定律)

这种设计方案的网络连接器配置文件:

端口:

 61616 (Broker1)

 61617(Broker2)

 61618(Broker3)

activemq.xml配置文件配置

Broker1的xml配置:

<transportConnectors>
	 <transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
<networkConnectors>      
     <networkConnector uri="static://(tcp://127.0.0.1:61617,tcp://127.0.0.1:61618)"/>    
</networkConnectors>
Broker2和Broker3可以从Broker1读取消息
Broker2的xml配置:

<transportConnectors>
	 <transportConnector name="openwire" uri="tcp://0.0.0.0:61617?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
<networkConnectors>      
     <networkConnector uri="static://(tcp://127.0.0.1:61618)"/>    
</networkConnectors>
Broker3可以从Broker2读取消息

Broker3的xml配置:

<transportConnectors>
	 <transportConnector name="openwire" uri="tcp://0.0.0.0:61618?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
<networkConnectors>      
     <networkConnector uri="static://(tcp://127.0.0.1:61617)"/>    
</networkConnectors>
Broker2可以从Broker3读取消息。

Broker2和Broker3是相互读取的双向配置可以使用下面这种配置:

在Broker2中这样配置:

<transportConnectors>
	 <transportConnector name="openwire" uri="tcp://0.0.0.0:61617?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
<networkConnectors>      
     <networkConnector uri="static://(tcp://127.0.0.1:61618)" duplex="true"/>    
</networkConnectors>

或在Broker3中这样配置:

<transportConnectors>
	 <transportConnector name="openwire" uri="tcp://0.0.0.0:61618?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
<networkConnectors>      
     <networkConnector uri="static://(tcp://127.0.0.1:61617)" duplex="true"/>    
</networkConnectors>

其中的duplex="true"就是双向的,所以在Broker2或Broker3中配置一个就ok了!!!

Producer连接工厂:

connectionFactory = new ActiveMQConnectionFactory("admin", "admin","tcp://127.0.0.1:61616");

Consumer连接工厂:

connectionFactory = new ActiveMQConnectionFactory("admin", "admin","tcp://127.0.0.1:61618");

ok 这种设计方式的配置就这些了……


2、比较合理的设计方式

上面的设计方式有两个缺点下面这种设计方式可以说解决了那两个缺点,下面来看看

(1)、数据进行Master-Slave备份,消息消费进行负载均衡,具体如下图(图中的箭头可以理解为消息数据的流向):


Hub1和Hub2进行Master-Slave消息备份

Hub1、Hub2和Broker1、Broker2、Broker3甚至扩展后添加的Broker4、Broker5使用网络连接器连接从而从Hub1/Hub2中获取消息。


这种方案Hub1和Hub2弄成了互备,然后每个Hub都和其他外围的Broker相连,消费者连到Broker1/Broker2/Broker3生产者连到Hub1/Hub2,消息的最长路径不会超过2个Broker,如果以后要扩展比如增加Broker4、Broker5则直接修改Hub1和Hub2增加新的Broker的连接就可以了,不影响消费消息的路由长度,这样所有访问路径的长度都一样,系统就相对稳定一点!


这种方案配置文件:

1)、端口:

activemq:61616(Broker-Hub1)

activemq:61617(Broker-Hub2)

activemq:61618(Broker1)

activemq:61619(Broker2)

activemq:61620(Broker3)

2)、activemq.xml配置文件:

因为3个或更多个Consumer的Broker只是改改配置文件中的端口其他的都是一样的所以这里只列出一个即Broker1。

<transportConnectors>
	 <transportConnector name="openwire" uri="tcp://0.0.0.0:61618?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
<persistenceAdapter>
            <kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>

Broker-Hub1的activemq.xml配置文件

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}">
<transportConnectors>
            <transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
<networkConnectors>      
      <networkConnector uri="static://(tcp://127.0.0.1:61618,tcp://127.0.0.1:61619,tcp://127.0.0.1:61620)"/>    
</networkConnectors>
<persistenceFactory>
				 <journalPersistenceAdapterFactory journalLogFiles="2" journalLogFileSize="16" useJournal="true" useQuickJournal="true" dataSource="#mysql-ds" dataDirectory="${activemq.data}/data"/>
</persistenceFactory>
</broker>
 <bean id="mysql-ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>  
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/test?relaxAutoCommit=true"/>  
        <property name="username" value="root"/>  
        <property name="password" value="admin"/>  
        <property name="poolPreparedStatements" value="true"/>  
 </bean>  

Broker-Hub2的activemq.xml配置文件

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost2" dataDirectory="${activemq.data}">
<transportConnectors>
            <transportConnector name="openwire" uri="tcp://0.0.0.0:61617?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
<networkConnectors>      
      <networkConnector uri="static://(tcp://127.0.0.1:61618,tcp://127.0.0.1:61619,tcp://127.0.0.1:61620)"/>    
</networkConnectors>
<persistenceFactory>
				 <journalPersistenceAdapterFactory journalLogFiles="2" journalLogFileSize="16" useJournal="true" useQuickJournal="true" dataSource="#mysql-ds" dataDirectory="${activemq.data}/data"/>
</persistenceFactory>
</broker>
 <bean id="mysql-ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>  
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/test?relaxAutoCommit=true"/>  
        <property name="username" value="root"/>  
        <property name="password" value="admin"/>  
        <property name="poolPreparedStatements" value="true"/>  
 </bean> 

ok这样所有Broker的配置都配置完了,下面来看看生产者和消费者的ConnectionFactory的连接:


3)、生产者:

connectionFactory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://127.0.0.1:61616,tcp://127.0.0.1:61617)?randomize=false&priorityBackup=true");

4)、消费者:

connectionFactory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://127.0.0.1:61618,tcp://127.0.0.1:61619,tcp://127.0.0.1:61620)?randomize=false&priorityBackup=true");


ok这样上面的这种方案就ok了!

这里说明一下这个方案的图形和个人理解:

1)、这里的Hub1和Hub2是做了Master-Slave主从消息备份,而Hub1/Hub2和Broker1、2、3、4、5之间是使用networkConnection进行单向连接的也就是说Broker从Hub读取消息。

2)、Broker1、Broker2、Broker3之间是没有任何的联系的他们是一个个单独的!

3)、消息生产者,使用了failover(tcp:Hub1,tcp:Hub2)这种方式也就是Master-Slave方式的备份

4)、消息消费者,也是使用了failover这种方式,但在消费者这里使用这种方式可以减小各个Broker的负载,比如Broker1、Broker2、Broker3各个负载一部分而且在某个Broker停止服务后还可以进行转移。

5)、这里强调一点ActiveMQ消息的消费是推拉模式即消费者(Consumer)向消息服务(Broker)注册,当有消息来的时候消息服务器就会把这个消息推送给注册了的消费者。


第二种方案(Hub1、Hub2之间不进行Master-Slave备份而是使用Broker负载),图中的箭头可以理解为消息数据的流向


或者用下面的这张图能更好说明



因为Hub1和Hub2之间使用了Broker负载消息互相读取,所以对于外面来说都一样就相当与一个Broker。

这种方案和之前的Master-Slave方法不同之处就是Hub1和Hub2没有进行数据备份而只是起到了负载的功能,自己的消息还是保存在自己的目录下。
但是Hub1和Hub2可以互相读取对方的数据。
下面来看看这种方案的activemq.xml文件配置以及生产者和消费者的配置:
1)、Broke1的配置:

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost3" dataDirectory="${activemq.data}">
<transportConnectors>
            <transportConnector name="openwire" uri="tcp://0.0.0.0:61618?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
<persistenceAdapter>
            <kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
</broker>

2)、Hub-broker1的activemq.xml配置:

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost1" dataDirectory="${activemq.data}">
<transportConnectors>
            <transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
<persistenceAdapter>
            <kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
<networkConnectors> 		
          <networkConnector uri="static://(tcp://127.0.0.1:61617,tcp://127.0.0.1:61618,tcp://127.0.0.1:61619,tcp://127.0.0.1:61620)"/>    
</networkConnectors>
</broker>
 


3)、Hub-broker2的activemq.xml配置

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost2" dataDirectory="${activemq.data}">
<transportConnectors>
            <transportConnector name="openwire" uri="tcp://0.0.0.0:61617?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
<persistenceAdapter>
            <kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
<networkConnectors> 		
          <networkConnector uri="static://(tcp://127.0.0.1:61616,tcp://127.0.0.1:61618,tcp://127.0.0.1:61619,tcp://127.0.0.1:61620)"/>    
</networkConnectors>
</broker>

4)、生产者:

connectionFactory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://127.0.0.1:61616,tcp://127.0.0.1:61617)?randomize=false&priorityBackup=true");

5)、消费者:

connectionFactory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://127.0.0.1:61618,tcp://127.0.0.1:61619,tcp://127.0.0.1:61620)?randomize=false&priorityBackup=true");
当然生产者和消费者配置的ip优先级可以按照自己的需求修改,以实现负载均衡。

这种方式相比上一种方式,数据没有进行主从备份,有可能会导致消息消费的滞后,但是这种方式在消息量大的时候可以实现负载均衡这种能提供更高的性能。

两种方式各有利弊,但网上也看到有人把两种方式整合了的,需要的时候可以看看……

注意:我这篇文章中箭头的指向可以理解为消息数据的流向,所有demo都是测试过的没有问题!

有人可能会问为什么不把Broker1、Broker2、Broker3 进行双向连接,第一他们不是数据的保存点如果Hub1、2出了问题他们都没数据第二那样连了之后路由太长导致消息的获取会很慢!

ok文章到此结束


我的疑惑:

1、在网上看到有的图形中Hub1和Hub2之间进行了Master-Slave数据备份而且还有消息数据的互相读取,这种方式个人已测试过,消息服务根本就起不来即如果做了主从备份则不可能使用网络连接器(networkConnectors)进行连接读取数据。

2、有看到Hub1/Hub2和Broker1、Broker2、Broker3之间是双向连接(网络连接器networkConnectors)个人感觉没必要使用双向连接吧,毕竟不会从Broker读取数据到Hub。


这里写的都是个人的学习达到的程度,如有错误还请指教谢谢!


推荐文章:

http://www.open-open.com/lib/view/open1400126457817.html

http://manzhizhen.iteye.com/blog/2116920

http://www.cnblogs.com/leihenqianshang/articles/5623858.html

http://blog.csdn.net/vtopqx/article/details/51649654



评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值