JMS和ActiveMQ介绍(4)_ActiveMQ

183716167.jpg

下面,咱们再看看ActiveMQ是如何实现高可用的。数据库

ActiveMQ实现高可用有两类方案:编程

第一类方案是构建服务器网络,消息在服务器网络中进行传递,客户端经过failover或discovery链接网络中的一个服务器发送或接收消息,当服务器失效时,客户端自动重连另外一个服务器。安全

第二类方案是构建服务器主从集群,在某个时间只有一个服务器做为主对外提供服务,当主服务器失效时,从服务器切换成主服务器对外提供服务,客户端自动重连至新的主服务器。服务器

MasterSlave有4种具体实现方案,下面将介绍一下前3种,第4种在官网上已有介绍,是基于HahaDBA和Zookeeper的,但目前还不支持该功能。网络

183754723.jpg

PureMaster Slave须要两个启动两个ActiveMQbroker,主broker不须要作额外配置,从broker中须要做以下配置,在其中设定主broker的链接,这样在从broker启动后,会创建与主broker的链接,并对主broker的消息进行同步。当主broker失败时,从broker自动切换成主broker。并发

另外,在使用PureMaster Slave时,须要客户端使用failover方式链接ActiveMQbroker,并设定randomize的值为false,这样,客户端在链接主broker失败后,会自动尝试链接从broker。负载均衡

PureMaster Slave配置简单,易于实现,以前是ActiveMQ比较推荐的高可用解决方案,但在Pure Master Slave中,消息传送必须通过主、从服务器的确认,另外Pure Master Slave还存在如下不足:dom

1)主服务器只能有一个从服务器;ide

2)主服务器失败重启后,还必须重启从服务器才能恢复主服务器;插件

3) 主、从服务器之间没有自动同步机制。

咱们在实践中也遇到过由没有自动同步机制致使的问题:有一次使用中咱们建立持久订阅者链接服务器,开始时,持久订阅者的状态在主从上是同步的,均为活跃,但在作了一次重启从服务器的操做后,从服务器中原先活跃的持久订阅者变动为了非活跃,与主服务器状态不一致,因此发往主从的消息因为从服务器上订阅者为非活跃状态不消费形成消息阻塞。

因为PureMaster Slave具备以上不足,所以在ActiveMQ5.8.0版本中已去掉了该功能。

183817488.jpg

使用基于JDBC的Master Slave时,多个消息服务器实例尝试获取数据库排他锁(exclusive lock),只有一个成功获取锁,对外提供服务,成为主服务器,其余等待。

客户端链接采用failover方式,从多个地址中找到当前可用的消息服务器实例并链接。

当Master失去排他锁或失去数据库链接时,Master将会关闭,其余服务器实例经过竞争,由一个实例获取锁成为新Master,客户端经过failover从新链接至新Master。

原Master在从新启动后成为Slave等待锁。

SharedFile System MasterSlave的实现原理与JDBCMaster Slave相似,多个服务器共用一个存储消息的文件系统(SAN);须要确认文件系统存在文件读写锁,获取读写锁的服务器自动成为主服务器,直至失败放弃读写锁;客户端也是使用failover进行链接。

183840847.jpg

下面是关于ActiveMQ的安全机制。

ActiveMQ的安全机制包括两部分:

验证,经过访问者的用户名和密码实现用户身份的验证;

受权,为消息目标(队列或主题)的读、写、管理指定具备相应权限的用户组,并为用户分配权限。

ActiveMQ的安全机制基于插件实现,能够灵活配置。

ActiveMQ提供两种验证插件,分别是:

1)简单验证插件;

2)JAAS验证插件。

ActiveMQ提供一种受权插件。

183907146.jpg

以上是简单验证和JAAS验证插件的配置示例,均须要配置用户名、用户组和密码。

设置插件后,在建立链接时,须要输入帐号和密码。

connectionFactory.createConnection(“user”,”password”);

183929146.jpg

以上是受权插件的配置示例,能够设置某一个队列、主题或某一类队列、主题的读、写、管理权限组。

184001720.jpg

下面再经过简单验证插件源码介绍一下ActiveMQ的插件机制以及验证是如何实现的

ActiveMQ的插件机制如图所示,主要涉及BrokerPlugin和BrokerFilter这两个接口和类。

BrokerPlugin中的installPlugin方法用于安装插件,在installPlugin方法中会传入Broker对象,而BrokerFilter是Broker的实现,在BrokerFilter中包含着一个对Broker的引用next,能够在installPlugin方法中,新建BrokerFilter对象,并将installPlugin方法传入Broker对象赋值给next,这样多个BrokerFilter对象就经过next引用造成链。这与struts中Interceptor的原理是相似的。

对于简单验证插件,在SimpleAuthenticationBroker类中,重写了BrokerFilter的addConnnection方法,在新建链接时,若容许匿名访问,则不进行验证,若不容许匿名访问,则验证链接的用户名和密码是否与配置文件中的一致,若不一致,则抛出安全异常。

184025697.jpg

通知信息机制是ActiveMQ服务器经过发布特定的通知消息记录服务器和客户端的操做日志,便于系统监控。另外,ActiveMQ服务器网络之间的通讯也是基于通知消息的。

发送通知消息的操做有:

消费者、生产者和链接的建立和关闭;

队列、主题的建立和销毁;

消息的过时;

消息发送至无消费者的目的地址。

通知消息发布至相应的主题上,通知消息的主题有两类:

第一类是基于客户端的主题,包括链接、生产者、消费者的建立和关闭,例如链接的建立和关闭消息发布在Connection主题上;

第二类是基于目的地址和消息的主题,包括队列、主题的建立和销毁,消息的过时等,例如,队列、主题的建立和销毁消息发布至Queue和Topic主题上。

184048153.jpg

这一页介绍一下有关排他消费者和消息组的相关概念。

对于队列,当有多个消费者时,消息服务器将把消息平均地发送给每一个消费者,实现负载均衡,可是多个消费者接收、处理消息时并不会在线程上同步,这就致使消息在并发处理时,没法保证消息原有的顺序。

排他消费者(Exclusive Consumer)是在多消费者状况下,消息服务器指定一个消费者接收消息,这样能够保证消息的有序性。其余消费者处于等待状态。

当原先指定的消费者没法接收消息时,消息服务器将从等待的消费者中再指定一个消费者接收消息。

排他消费者能够在多个消费者的状况下,保证消息的有序性,且在单个消费者故障时,可以保证消息继续被消费,但因为每次只有一个消费者消费消息,形成吞吐量低,其余消费者的资源浪费。

使用消息组(message group)能够避免排他消费者的不足。

消息组是指经过设定消息的JMSXGroupID属性来为消息进行分组,而同一组消息将被发送至同一个消费者进行处理,所以能够保证在多消费者状况下,消息可以有序处理。

184105201.jpg

以前咱们讨论过,对于主题,若订阅者不链接,则存在消息丢失,若须要保证消息所有接收,则须要建立持久订阅者,但对于持久订阅者,因为其须要指定ClientID,所以只能保证同一个ClientID只有一个消费者、一个线程访问主题,这就致使如下两个问题:

没法实现消息消费的负载均衡;

消费者失败时,不能由其余的消费者恢复。

如何同时既能实现主题的特性,同一个消息由多个消费者消费,也能实现队列的特性,多消费者实现负载均衡?能够经过使用虚主题解决上述问题。

虚主题以VirtualTopic.主题名的形式命名,当配置虚主题后,ActiveMQ能够将该主题映射到以Consumer.队列名.VirtualTopic.主题名的形式命名的队列上,消息生产者仍将消息发送至主题,而ActiveMQ会将消息再转发至队列上,消息消费者经过使用队列接收来自主题的消息,这样就能够启动多个消费者,实现负载均衡。

虚主题的配置以下所示。

184129203.jpg

ActiveMQ支持除Java之外的多种语言,包括C/C++,.NET,Perl,PHP,Python,Ruby等,对于脚本语言,通常采用STOMP协议链接ActiveMQ。

STOMP是一种相似于HTTP的协议,支持命令有:SEND,SUBSCIRBE,UNSUBSCRIBE等,在使用STOMP链接ActiveMQ时,首先须要在ActiveMQ配置STOMP链接,一般通常占用61613端口。

如下分别是Python和PHP使用STOMP链接消息服务器并接收主题消息的示例代码。

对于C,ActiveMQ提供C++ API和.NET API,对于Web编程,ActiveMQ提供RESTAPI和AjaxAPI,你们有兴趣能够去尝试一下。

184146195.jpg

在使用消息服务器时,有时候咱们不但愿ActiveMQ在单独的JVM中运行,而是集成在已有的Java应用中。

在Java应用中嵌入ActiveMQ服务器有以下几种方法:

建立BrokerService实例;

使用BrokerFactory方法建立BrokerService实例。

184205286.jpg