MQ系列1-ActiveMQ

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huanshirenjian/article/details/89766642

1.JMS

JMS(Java Messaging Service)是Java平台上有关面向消息中间件的技术规范,实际上是一套api,ActiveMQ而是这个规范的一个具体实现。
JMS规范:

  • 连接工厂:负责创建一个JMS连接
  • JMS连接:表示客户端和服务器端之间的一个活动的连接,通过连接工厂建立的
  • JMS会话:表示客户与服务器之间的会话状态。会话建立在连接上,表示客户与服务器之间的一个会话线程
  • JMS目的/ Broker。生产和消费消息的目标
  • JMS生产者和消费者。生产者(Message Producer)和消费者(Message Consumer)对象由Session对象创建,用于发送和接收消息

2.ActiveMQ

ActiveMQ可以支持单台6000+的并发。

2.1 队列和主题

队列:每条消息通仅会有一个消费者消费
主题:只要订阅这个主题的消费者都可以收到消息

2.2 同步和异步

消费者同步:使用receive方法,消息没来之前一直阻塞
消费者异步:使用监听器
生产者同步:使用send方法,一直阻塞到MQ确认收到消息。持久化非事务下,默认同步。
生产者异步:使用send方法,不会阻塞,这种可能丢失数据。非持久化情况下,默认异步。在开启事务时,默认使用异步,虽然send不会阻塞,但commit方法会阻塞。

2.3 持久化

队列消息默认是持久化,主题默认是非持久化。非持久化数据保存在内存中,一旦MQ重启,数据丢失,并且非持久化数据如果消息者在生产者发送消息之后再启动,无法消费到数据。
(1)AMQ消息存储
AMQ消息存储是基于文件的存储方式,写入速度快和容易恢复。消息存储在一个个文件中,文件默认大小为32M,如果一条消息的大小超过了32M,那么这个值需要设置大一点。当一个存储文件中的消息已经全部被消费,那么这个文件将被标识为可删除,在下一个清除阶段,这个文件被删除。AMQ适用于ActiveMQ5.3之前的版本。
(2)KahaDB
5.4版本之后默认的持久化方式。基于文件的本地数据库储存形式,提高了容量和恢复能力,强扩展性、恢复的时间比AMQ短,但写入速度没有AMQ的速度快。默认KahaDB文件存在ActiveMQ安装路径下的/data/KahaDB目录。
(3)关系型数据库存储
ActiveMQ 4版本开始,ActiveMQ支持使用关系型数据库进行持久化。
使用JDBC的方式持久化

  • 修改配置文件conf/activemq.xml:
<persistenceAdapter>
       <jdbcPersistenceAdapter  dataSource="#mysql-ds "/>
</persistenceAdapter>
  • 标签后,增加数据源配置:
<bean id="mysql-ds" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/activemq?relaxAutoCommit=true&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="poolPreparedStatements" value="true"/>
    </bean>

其中?relaxAutoCommit=true必须有,其他的属性根据数据库的配置自行决定。

  • 将mysql驱动包放入ActiveMQ的/ lib目录下
  • Mysql数据库中创建连接字符串中设置的数据库activemq
  • 运行后,数据库库中增加了3个表

activemq_acks:用于存储订阅关系,字段如下:

container:消息的目的地
sub_dest:如果是使用static集群,这个字段会有集群其他系统的信息
client_id:每个订阅者都必须有一个唯一的客户端id用以区分
sub_name:订阅者名称
selector:选择器,可以选择只消费满足条件的消息。条件可以用自定义属性实现,可支持多属性and和or操作
last_acked_id:记录消费过的消息的id

activemq_lock:记录哪个Broker是当前的Master Broker,在集群环境中才有用,只有一个Broker可以获得消息,称为Master Broker,其他的只能作为备份。
activemq_msgs:用于存储消息,Queue和Topic都存储在这个表中。

id:自增的数据库主键
container:消息的目的地
msgid_prod:消息发送者客户端的主键
msg_seq:是发送消息的顺序,msgid_prod+msg_seq可以组成jms的messageid
expiration:消息的过期时间,存储的是从1970-01-01到现在的毫秒数
msg:消息本体的java序列化对象的二进制数据
priority:优先级,从0-9,数值越大优先级越高

2.4 消费者确认机制

(1)AUTO_ACKNOWLEDGE
自动确认, 同步(receive)方法返回message给消息时会立即确认。在异步(messageListener)中,如果onMessage方法正常结束,消息将会正常确认。如果onMessage方法异常,将要求ActiveMQ重发消息。但消息的重发次数有限制,每条消息中都包含“redeliveryCounter”计数器,如果重发次数达到阀值,将导致broker端认为此消息无法消费,此消息将会被删除或者迁移到"dead letter"通道中。
(2)CLIENT_ACKNOWLEDGE
客户端手动确认。使用message.acknowledge()和session.acknowledge()效果一样。
消息未确认会导致重发。
(3)DUPS_OK_ACKNOWLEDGE
自动批量确认,具有延迟确认的特点,ActiveMQ会根据内部算法,在收到一定数量的消息自动进行确认。在此模式下,也可能会出现重复消息,比如consumer故障重启后,那些尚未ACK的消息会重新发送过来。
(4)SESSION_TRANSACTED
当session使用事务时,就是使用此模式,其他模式设置也不生效。使用此模式,必须调用session.commit()方法,将当前session的事务中所有消息立即被确认。在事务开始之后的任何时机调用rollback(),意味着当前事务的结束,事务中所有的消息都将被重发。当然在commit之前抛出异常,也会导致事务的rollback。

2.5 通配符式订阅

“.” 用于作为路径上名字间的分隔符。
“*” 用于匹配路径上的任何名字。
“>” 用于递归地匹配任何以这个名字开始的destination。

2.6 死信队列

死信队列是用来保存处理失败或者过期的消息。
出现下面情况时,消息会被重发:

  • 事务会话被回滚
  • 事务会话在提交之前关闭
  • 会话使用CLIENT_ACKNOWLEDGE模式,并且Session.recover()被调用
  • 自动应答失败
    当一个消息被重发超过最大重发次数(默认为6次)时,会给broker发送一个"有毒标记“,这个消息被认为是有问题,这时broker将这个消息发送到死信队列,以便后续处理。

2.7 集群下的ActiveMQ

如何保证一个消息可以被不同集群下消息者都消息,但同一集群下消息者只能有一个消费。队列和主题单独使用都不能满足
(1)队列和主题级联
比如先将消息发往主题,多个消息者消费后再发往队列。
(2)虚拟主题
对生产者来说就是一个正常的Topic,名称以VirtualTopic.开头。如VirtualTopic.AA。默认虚拟主题的前缀是 :VirtualTopic。
对于消费者来说是个队列,不同集群使用不同的前缀作为队列的名称,即可实现消费端应用分组。例如Consumer.A.VirtualTopic.AA,说明它是名称为A群组的消费端,同理Consumer.B.VirtualTopic.AA说明是一个名称为B群组的消费端。
消费虚拟地址默认格式:Consumer.*.VirtualTopic。
(3)组合队列
组合队列允许用一个虚拟的destination代表多个destinations。这样就可以通过在一个操作中同时向多个destination发送消息。多个destination之间采用“,”分割。例如:
Queue queue = new ActiveMQQueue(“A,B,C”);如果使用不同类型的destination,那么需要加上前缀如queue:// 或topic://,例如:Queue queue = new ActiveMQQueue(“A,topic://B”);

2.8 延迟队列

ActiveMQ中可以延迟投递消息,这个不多说。首先在activemq.xml启动延迟投递配置,然后代码中设置消息属性。

  • AMQ_SCHEDULED_DELAY :延迟投递的时间
  • AMQ_SCHEDULED_PERIOD :重复投递的时间间隔
  • AMQ_SCHEDULED_REPEAT:重复投递次数
  • AMQ_SCHEDULED_CRON:Cron表达式

2.9 构建ActiveMQ集群

ActiveMQ的集群方式主要由两种:Master-Slave和Broker Cluster。

2.9.1 Master-Slave

Master-Slave方式中,只有Master提供服务,Slave是实时地备份Master的数据,以保证消息的可靠性。当Master失效时,Slave会自动升级为Master。Master-Slave模式分为四类:Pure Master Slave、Shared File System Master Slave和JDBC Master Slave,以及Replicated LevelDB Store方式 。
(1)Pure Master Slave
ActiveMQ5.8以前支持。Slave配置activemq.xml文件,在节点中添加连接到Master的URI和设置Master失效后不关闭Slave。
(2)Shared File System Master Slave
利用共享文件系统做ActiveMQ集群,基于kahaDB完成的,kahaDB的底层是文件系统。这种方式的集群,Slave的个数没有限制,哪个ActiveMQ实例先获取共享文件的锁,那个实例就是Master,其它的ActiveMQ实例就是Slave。
如果各个ActiveMQ实例需要运行在不同的机器,就需要用到分布式文件系统了。
(3)Shared JDBC Master Slave
JDBC Master Slave模式和Shared File Sysytem Master Slave模式的原理是一样的,只是把共享文件系统换成了共享数据库。只需在所有的ActiveMQ的配置文件activemq.xml中添加数据源,所有的数据源都指向同一个数据库。
(4)Replicated LevelDB Store
ActiveMQ5.9以后新增特性,使用ZooKeeper协调选择一个node作为master。被选择的master broker node开启并接受客户端连接。 其他node转入slave模式,连接master并同步他们的存储状态。slave不接受客户端连接。所有的存储操作都将被复制到连接至Master的slaves。
(5)LevelDB
Leveldb是一个google实现的非常高效的kv数据库,具有很高的随机写,顺序读/写性能,但是随机读的性能很一般。

2.9.2 Broker Cluster

Broker-Cluster中各个broker通过网络互相连接,并共享queue。当broker-A上面指定的queue-A中接收到一个message处于pending状态,而此时没有consumer连接broker-A时。如果cluster中的broker-B上面由一个consumer在消费queue-A的消息,那么broker-B会先通过内部网络获取到broker-A上面的message,并通知自己的consumer来消费。Broker的集群分为Static Discovery和Dynamic Discovery两种
(1)Static Discovery集群
Static Discovery集群就是通过硬编码的方式使用所有已知ActiveMQ实例节点的URI地址。如:消息生产者应用连接一个ActiveMQ实例,我们暂时称为MQ1,所有的消息都由该实例提供;两个消息消费者应用分别连接另外两个ActiveMQ实例,分别为MQ2和MQ3,两个消息消费者需要消费MQ1上的消息,但它们连接的都不是MQ1,可以通过Static Discovery方式把MQ1上的消息路由到MQ2和MQ3,为了保证消费者不因某个节点的失效而导致不能消费消息,在消费者应用中需要配置所有节点的URI。
(2)Dynamic Discovery
Dynamic Discovery集群方式在配置ActiveMQ实例时,不需要知道所有其它实例的URI地址,只需在所有实例的activemq.xml文件中配置同一地址

猜你喜欢

转载自blog.csdn.net/huanshirenjian/article/details/89766642