本文针对近期使用activemq,涉及基本概念及原理,总结如下。个人版本5.X
1.两种模式
queue、topic
2.投递模式
生产者将消息发送到broker
2.1同步投递
方法:send(msg)
特点:发送一条,阻塞等待broker返回ack信息,再发下一条。消息可靠但性能不高。
2.2异步投递(回调)
方法:send(msg,AsyncCallback())
特点:不会阻塞。性能高但消息可能丢失。
配置: 1.ConnectionFactory级别、Connection级别、消息者级别三种
2.参数dispatchAsync、useAsyncSend设为true
默认情况:非持久消息、事务内消息采用异步投递;未使用事务的持久化消息、明确指定同步方式下采用同步投递。
3.消费端获取消息方式
3.1同步:.receive()方法
3.2异步:实现MessageListener接口,监听消息
4.消费模式
4.1、push(默认)
4.2、pull
- activeMQ中根据prefetch limit参数来决定(consumer中prefetchSize)
- 当 prefetchSize = 0 时,pull;当 prefetchSize > 0 时,push
- prefetchSize参数默认为1000即push
4.3、预取机制prefetchSize
4.3.1同步方式下:prefetch limit可设为0,也可大于0
- =0时pull:receive()方法首先发送一个pull命令并阻塞,直到broker返回,也就是只能消费者逐个获取消息
- >0时push:broker端批量push到client一定数量(<=prefetchSize)消息,client端将消息放到本地队列,只要此队列有消息,receive()方法立即返回,当一定量的消息ACK后,broker端继续批量push
4.3.2异步方式:只能>0
只能大于0,用push,因为异步方式下消费者被动获取消息不会主动去轮询消息,而=0意味着不会主动push消息给消费者,二者矛盾。
5.消费端参数
- taskExecutor:任务调度器,使用线程池并发消费。
- concurrentConsumers:消费者最大个数(并行消费,默认值1)
- spring中messageListener实例是单例的,所以spring-jms不能自作主张的创建多个messageListener实例来并发消费,
- 所以spring在内部,创建了多个MessageConsumer实例,并使用consumer.receive()方法以阻塞的方式来获取消息,当获取消息后,在执行messageListener.onMessage()方法
- concurrentConsumers属性就是为了指定spring内部可以创建MessageConsumer的最大个数
- 若右consumer空闲则会“idle”并从consumer列表移除,若都是“actice”,则会创建新的consumer实例直到maxConcurrentConsumers
- optimizeAcknowledge:优化ACK批量确认
- 可在connectionFactory中配置
- 对consumer而言,该属性只在自动ack下生效
- 结合prefetchSize参数,协同作用,优化消费端起到批量获取消息、批量延迟确认。
6.持久化
6.1默认
queue默认是持久化,topic默认非持久化
6.2方式
AMQ/KahaDB(默认)/LevelDB/JDBC
6.3逻辑
发送者将消息发送到MQ服务器后,消息中心首先将消息持久化到本地数据文件、内存数据库或者远程库等,在试图将消息发送给接收者,成功则将消息从存储中删除,失败则继续尝试发送。
6.4目录
db.1.log:数据被追加到db-编号.logs中,当不在需要log文件中的数据时,log文件会被丢弃。
db.data:索引(B-tree)文件,指向db.number.log中每一条消息
db.redo:用来进行消息恢复,恢复BTree索引
6.5KahaDB消息存储器结构
- Data logs:存储每一条持久化的消息内容,尾部追加方式,默认32M一个文件(预占),文件中全部消息都被成功消费后,会在Metadata cache中被标记删除,下个周期删除
- Metadata Cache:为更快查找某个具体消息在Data logs中的位置,消息的位置索引B-tree结构被存储在内存中,如果消息快速消费了就不用再存到磁盘了
- Metadata Store:内存中没被处理的消息索引B-tree会以一定周期或一定数量的方式(可配)同步到store中,以便mq节点重启后Metadata Cache进行恢复
6.6KahaDB配置属性
activemq.xml中KahaDB相关常用参数如下
- directory:指定持久化消息的存储目录
- journalMaxFileLength:指定保存消息的日志文件大小(默认32M),具体根据实际应用配置
- indexWriteBatchSize:Metadata cache区域和Metadata store区域不同的索引数量达到这个值后,Metadata cache将会发起checkpoint同步(默认1000)
- indexCacheSize:内存中,索引的页大小(默认1000)。超过这个大小Metadata cache将会发起checkpoint同步
- cleanupInterval:清除(或归档)不再使用的db-*.log文件的时间周期(毫秒)(默认30000)。
bin/env中可配置mq的jvm参数,对应ACTIVEMQ_OPTS_MEMORY属性
7.死信策略
通过配置文件(conf/activemq.xml)来调整死信发送策略
1.共享(默认)
将所有死信放入一个共享队列中,默认名ActiveMQ.DLQ,可设置
2.独立
放入各自死信队列中,前缀ActiveMQ.DLQ.Queue(queue)、ActiveMQ.DLQ.Topic(topic),默认情况下对于queue和topic,broker都将使用queue保存死信即死信通道通常为Queue,也可指定Topic
- 删除过期的消息而不发送到死信队列中
新增policyEntry标签节点,"processExpired"表示是否将过期的消息放到死信队列,默认true
注意:对于非过期因素而进入死信队列的数据,上述配置无法删除
- 死信队列清除
策略1:新增policyEntry标签节点,使用插件plugins节点直接抛弃该队列
策略2:新增policyEntry标签节点,使用定时删除策略,区分queue='>'和topic='>'
注意:修改配置前进入的数据不会清除
- 存放非持久的消息到死信队列
默认持久消息过期会被送到DLQ,非持久消息不会送到DLQ。可通过"processNonPersistent"(默认false)来配置将非持久消息过期到死信。
8.定期清理不活动队列
8.1场景
一定时间内为空队列。Topic和Queue在不使用之后,可以通过web控制台或是JMX方式来删除掉,也可配置如下
8.2配置
新增policyEntry标签节点,三个参数(周期、开关、检测次数)