ActiveMQ的集群与高可用

转载: https://blog.csdn.net/zuolj/article/details/53116439



单纯根据《ActiveMQ In Action(Manning-2011)》一书介绍的总结,部分介绍可能已经和官网不一。

一、ActiveMQ的高可用性

ActiveMQ使用master-slave模式实现高可用性,提供两种实现主从模式的配置:shared nothing、shared storage(a relational database and a shared file system)

1.shared nothing master-slave

A shared nothing master-slave ActiveMQ broker deployment

每一个broker(包括master和slave)都有自己的消息存储区,这是最简单的高可用性实现的办法。 
master复制所有的消息指令给slave,复制的动作发生在master回复client消息已接收之前。 
slave broker会在启动的时候去连接master,所以理想上,master broker应该先启动,slave broker 不会打开任何transports,也就是说,slave broker不接收任何client请求和网络连接,除非master挂掉。slave通过检测它与master之间的连接失败而判定master挂掉。

shared nothing master-slave模式的处理过程:当一个生产者发送一个持久化消息到master之后,master会复制该消息给slave,再返回接收应答给生产者,生产者才能发送下一个消息。

当master broker挂掉后,slave有两个选择: 
1.关掉自己,因此,它只会保存master的状态。 
2.打开transports并且初始化所有的network connections,因此,该slave自动成为新的master。

如果slave broker成为新的master broker,所有的client可以通过failover机制去连接上新的master。在默认的client连接中,failover传输机制皆可以连接到master和slave: 
failover://(tcp://masterhost:61616,tcp://slavehost:61616)?randomize=false

不过,使用shared nothing master-slave也有限制,如果client先连上master进行工作,而slave还没与master进行连接,master挂掉,消息很可能会丢失。ActiveMQ提供了一个waitForSlave属性去设置master broker,强制master如果还没与slave建立好连接,那么不会接受任何client的连接,另一个限制是,一个master只允许有一个slave。

配置shared nothing master-slave

配置一个broker成为slave很简单,配置一个masterConnector service:

<services>
    <!-- 
    remoteURI:master broker的监听地址
    userName:Optional,如果master需要身份验证
    password:Optional,如果master需要身份验证
    -->
    <masterConnector remoteURI="tcp://remotehost:62001" userName="" password=""/>
</services>

2.shared storage master-slave

share nothing master-slave模式下,每一个broker都独自维护自己的storage,而shared storage master-slave模式允许多个broker共享存储,但同一个时刻只有一个broker是存活的。shared storage master-slave的好处在于,它确保了当master挂掉之后,无需手动干预去保持应用的完整性,另一个好处是,slave的数量不再有所限制。 
share nothing master-slave模式的配置有两种:a relational database和file system-based storage.

shared database master-slave

Using a shared relational database for ActiveMQ master-slave 
当一个ActiveMQ broker使用关系型数据库时,它持有表的锁以确保没有其他broker同时访问这个数据库。多个broker同时运行并尝试去访问数据库时,只有第一个broker会连接成功并拿到锁,其他随后到来的broker会一直poll直到它可以获得锁为止。这些处于polling状态的broker,被视为slave,它们不会开启任何传输连接或者网络连接。 
该配置中所有的broker可以使用同一份配置文件,这使得activemq启动起来简单得多。

shared file system master-slave

Using a file system for ActiveMQ master-slave

它建议使用 KahaDB 消息存储,但是对于消息存储使用底层的共享的文件系统。当KahaDB消息存储启动时,它将尝试获取文件锁,以防止任何其他broker同时访问基于文件的消息存储。

二、ActiveMQ是如何在brokers之间传递消息

ActiveMQ中有一个概念:networks of brokers,它指的是连接ActiveMQ的消息代理在一起形成不同的拓扑结构。 
接下来就是分析brokers是如何在一个network中发现彼此且如何配置broker使其在network中合作。

1.存储和转发(store and forward)

ActiveMQ的存储和转发概念意味着,消息在通过network转发到其他broker之前,总是被存储在本地broker中,也就是说,如果一条消息由于连接原因没有被交付,比如说,正在重连,broker将能够通过网络连接将未交付的消息发送到远程broker。默认情况下,network仅以单向方式操作,如图: 
Passing message between ActiveMQ brokers using store and forward 
当然,这并不是说network只能单向操作,如果想要双向操作,同样可以在远程broker中配置一个network connector指向本地的broker,或者直接指定创建的network connector为双向duplex。

当本地broker和远程broker之间建立好一条network后,远程broker会将其所有持久和处于活动的消费者的目的地信息传递给本地broker,本地broker使用这些信息去判断远程broker对哪种消息感兴趣,并转发该类型消息给它。

这里,书中举了一个场景,假如我们有多个超市需要连接到一个后台办公订购系统,这将很难灵活扩展新的超市,后台办公订购系统不好掌控所有新加入的超市即远程broker。 
这里写图片描述 
给个图示,这里想象超市和后台之间有一个防火墙。(至于为什么这么想象,我并不得知)注意到这里,超市broker和back office之间的network是双向的,超市broker的配置:

<networkConnectors>
    <networkConnector uri="static://(tcp://backoffice:61617)" 
        name="bridge" 
        duplex="true"
        conduitSubscriptions="true"
        decreaseNetworkConsumerPriority="false">
    </networkConnector>
</networkConnectors>

这里关于配置,主要注意一点是,配置的顺序是很重要的,关于networks,persistence,transports的顺序如下:

  1. Networks——必须在消息存储之前创建
  2. Message store——必须在传输配置好之前配置完
  3. Transports——必须在broker配置的最后

举个例子:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://activemq.apache.org/schema/core">
    <broker brokerName="receiver" persistent="true" useJmx="true">
        <networkConnectors>
            <networkConnector uri="static:(tcp://backoffice:61617)"/>
        </networkConnectors>
        <persistenceAdapter>
            <kahaDB directory = "activemq-data"/>       
        </persistenceAdapter>
        <transportConnectors>
            <transportConnector uri="tcp://localhost:62002"/>
        </transportConnectors>
    </broker>
</beans>

来一张,在大型开发场景下的高可用性和network配置结合: 
Combine high availability and networks for an enterprise deployment of ActiveMQ

2.Network发现机制

ActiveMQ提供两种发现机制:

  1. Dynamic——使用组播和会合方式搜索brokers
  2. Static——通过一个URI列表配置brokers

使用组播发现的方式去创建network连接是最简单粗暴的,当你启动一个broker时,它会通过组播IP去搜索其他的broker并创建network连接。配置方式如下:

<networkConnectors>
    <networkConnector uri="multicast://default"/>
</networkConnectors>

这里“default”表示这个broker属于哪个组,建议使用唯一的名字去标识,以免你的broker连接到其他你不知道的应用代理上。 
组播发现机制有一些限制,比如说不能控制哪些broker被发现,事实上,它通常局限于本地网段上去发现其他broker,因为组播IP不通过路由器延伸。 
关于第二种方式,static,事实上,在这之前的配置一直都是static,只不过broker的URL列表有点少而已,

<networkConnectors>
    <networkConnector uri="static:(tcp://remote-master:61617,tcp://remote-slave:61617)"/>
</networkConnectors>

static的配置属性: 
static配置属性表

3.Network配置

对于远程broker现存在的目的地,可能没有任何活动持久的订阅者或消费者,因此,当network初始化连接到远程broker时,远程broker会读取它现存目的地的消息,并传递给本地broker,然后,本地broker也可以转发那些目的地的消息。 
重要的是要注意,一个network将使用broker的名称来代表远程broker创建唯一的持久预订代理。 因此,如果在稍后的时间点更改broker的名称,很可能会通过network丢失持久主题订阅者的消息。 为避免这种情况,请确保为元素上的brokerName属性使用唯一的名称。 有关简要示例,请参阅以下内容:

<broker xmlns="http://activemq.apache.org/schema/core/"
    brokerName="brokerA"
    dataDirectory="${activemq.base}/data">
...
    <networkConnectors>
        <networkConnector name="brokerA to brokerB" uri="tcp://remotehost:61616"/>
    </networkConnectors>
</broker>

关于Network配置还有很多,不一一列举了。

三、为大量并发应用程序部署ActiveMQ

扩展使用ActiveMQ的应用程序可能需要一些时间,需要一些努力。 在本节中,将介绍三种技术来帮助完成此任务。首先是垂直扩展,单个broker用于数千个连接和队列。然后将通过使用network水平扩展应用程序来扩展到数万个连接。 最后,将研究流量分区,这将平衡扩展和性能,但会增加ActiveMQ应用程序的复杂性。

1.垂直扩展

垂直扩展是一种用于增加单个ActiveMQ broker可以处理的连接数(因此增加负载)的技术。默认情况下,ActiveMQ broker设计为尽可能高效地移动消息,以确保低延迟和良好的性能。但是我们可以做一些配置调整,以确保ActiveMQ broker可以处理大量的并发连接和大量的队列。

默认情况下,ActiveMQ将使用阻塞I/O来处理传输连接。 这导致每个连接使用一个线程。 我们可以在ActiveMQ broker上使用非阻塞I/O(而客户端上仍然使用默认传输)来减少使用的线程数。broker的非阻塞I/O配置如下:

<broker>
    <transportConnectors>
        <transportConnector name="nio" uri="nio://localhost:61616"/>
    </transportConnectors>
</broker>

除了每个连接使用一个线程来阻塞I/O外,ActiveMQ broker可以使用线程为每个客户端连接分派消息。可以通过将名为org.apache.activemq.UseDedicatedTaskRunner的系统属性设置为false,让ActiveMQ使用线程池。

ACTIVEMQ_OPTS="-Dorg.apache.activemq.UseDedicatedTaskRunner=false"

确保ActiveMQ broker具有足够的内存来处理大量并发连接有两步过程。 
首先,需要确保启动ActiveMQ broker的JVM配置了足够的内存。

ACTIVEMQ_OPTS="-Xmx1024M \-Dorg.apache.activemq.UseDedicatedTaskRunner=false"

第二,确保专门为ActiveMQ broker在JVM配置适当的内存量。此调整通过< system-Usage >元素的limit属性进行。(最好从512MB开始,如果测试不够再往上加),配置示例:

<systemUsage>
    <systemUsage>
        <memoryUsage>
            <memoryUsage limit="512 mb"/>
        </memoryUsage>
        <storeUsage>
            <storeUsage limit="10 gb" name="foo"/>
        </storeUsage>
        <tempUsage>
            <tempUsage limit="1 gb"/>
        </tempUsage>
    </systemUsage>
</systemUsage>

还应该降低每一个连接的CPU负载,如果使用的OpenWire连接方式,禁用紧密编码,否则会使得CPU过度紧张。

String uri = "failover://(tcp://localhost:61616?" + " wireFormat.tightEncodingEnabled=false)";
ConnectionFactory cf = new ActiveMQConnectionFactory(uri);

前面研究的是broker怎么调整去处理数千个连接,下面开始研究的是怎么调整broker去处理数千个队列。

默认队列配置使用单独的线程来将消息从消息存储区分页到队列中,以便分发给感兴趣的消息消费者。 对于大量队列,建议通过为所有队列启用optimize-Dispatch属性来禁用此功能,

<destinationPolicy>
    <policyMap>
        <policyEntries>
            <policyEntry queue=">" optimizedDispatch="true"/>
        </policyEntries>
    </policyMap>
</destinationPolicy>

为了确保不仅可以扩展到数千个连接,而且还可以扩展到数万个队列,使用JDBC消息存储库或更新和更快的KahaDB消息存储库。 KahaDB默认情况下在ActiveMQ中启用。

到目前为止,我们已经考虑了扩展连接,减少线程使用,并选择正确的消息存储。 调整用于扩展的ActiveMQ的示例配置如以下:

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="amq-broker" dataDirectory="${activemq.base}/data">
    <persistenceAdapter>
        <kahaDB directory="${activemq.base}/data" journalMaxFileLength="32mb"/>
    </persistenceAdapter>
    <destinationPolicy>
        <policyMap>
            <policyEntries>
                <policyEntry queue="&gt;" optimizedDispatch="true"/>
            </policyEntries>
        </policyMap>
    </destinationPolicy>
    <systemUsage>
        <systemUsage>
            <memoryUsage>
                <memoryUsage limit="512 mb"/>
            </memoryUsage>
            <storeUsage>
                <storeUsage limit="10 gb" name="foo"/>
            </storeUsage>
            <tempUsage>
                <tempUsage limit="1 gb"/>
            </tempUsage>
        </systemUsage>
    </systemUsage>
    <transportConnectors>
        <transportConnector name="openwire" uri="nio://localhost:61616"/>
    </transportConnectors>
</broker>

2.水平扩展

除了扩展单个broker之外,还可以使用networks来增加可用于应用程序的ActiveMQ broker的数量。 由于networks会自动将消息传递给具有感兴趣的消费者的连接broker,因此可以将客户端配置为连接到一个broker集群,随机选择一个来连接。

failover://(tcp://broker1:61616,tcp://broker2:61616)?randomize=true
  • 1

为了确保队列或持久主题订阅者的消息不会在broker上孤立,需要将network配置为使用dynamicOnly和低网络prefetchSize。

<networkConnector uri="static://(tcp://remotehost:61617)"
    name="bridge"
    dynamicOnly="true"
    prefetchSize="1">
</networkConnector>

使用network进行水平扩展会带来更多的延迟,因为潜在的消息必须在分发给消费者之前通过多个broker。

另一种替代部署提供了巨大的可扩展性和性能,但需要更多的应用规划。 这种混合解决方案称为流量分区。

3.流量分区

客户端流量分割是垂直和水平分割的混合。 通常不使用network,因为客户端应用程序决定什么流量应该到哪个broker上。 客户端应用程序必须维护多个JMS连接,并决定哪些JMS连接应用于哪些目标。 
不直接使用network connection的优点是,减少在brokers之间转发消息的开销。 需要平衡这与导致典型应用程序的额外复杂性。Fig10.8是流量分区的一个使用代表: 
Using traffic partition with ActiveMQ master/slave deployment


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值