消息队列---ActiveMQ
ActiveMQ java语言写的和java系统紧密结合
RabbitMQ Erang写的,天生支持并发,非java系统的首选,优于ActiveMQ
ZeroMQ 内存中使用,不支持持久化,多用于金融场景
RocketMQ 阿里开源中间件 专门为java系统定制 现已捐赠给Apache
Kafka 天生设计为分布式,很方便扩展,超高并发 推荐java使用
MQ的消息可靠性传输
ACK机制 ACKONWLEDGE 通知确认
producer发送destination,broker收到之后会返回一个ACK,如果producer没有收到ACK那么会重新发送消息,一般会限制一个重试次数。(默认是6次)
如果做了集群的话,broker之间传输也会有ACK机制。
同样Consumer也有ack机制,成功接受消息之后返回ACK,Broker成功接收ACK之后删除消息,否则同样发起重试。
AUTO_ACKNOWLEDGE = 1 自动确认
CLIENT_ACKNOWLEDGE = 2 客户端手动确认 (如果使用了JMS那么即是设置了客户端手动确认,那也是自动确认源码中实现了)
DUPS_OK_ACKNOWLEDGE = 3 自动批量确认
SESSION_TRANSACTED = 0 事务提交并确认
此外ActiveMQ补充了一个自定义的ACK
INDIVIDUAL_ACKNOWLEDGE = 4 单条消息确认
问题:broker成功收到消息而且向下执行成功,但是发送ACK的时候出现问题(例如网络问题)导致ACK没有发送成功,那么producer又重新请求了一次,又产生了新的业务逻辑。
幂等:多次调用或者说消息多次发送和一次调用结果一致。(这是一个宏观的概念不仅限于消息队列)
实现:例如一条消息对应一个messageId存入broker。
Consumer去消费消息有两种 方式:
push:当broker收到消息之后主动将消息推送给Consumer 消息比较及时实现代价比较大 设置perfetch 0
pull:Consumer去拉取消息(轮询) 轮询消耗资源 有延迟
消息持久化
在配置文件activemq.xml中的 persistenceAdapter 标签实现持久化
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
持久化默认是打开的!(可以配置,也可以在代码中设置)重要消息持久化,不重要的可以考虑不持久化
所有的发送数据会有一个Data Logs,为了提高访问速率为Data Logs提供了一个BTree的索引(Metadata Store)有一份索引是在内存中的(Metadata Cache)。
持久化发生在什么时候?
在broker接受到消息之后,会先将消息进行持久化(可靠介质,MySQL、kahaDB[默认]),持久化成功之后才会返回ACK。
还有另一种持久化:
topic模式:
持久化订阅者:一直保持链接,服务挂了之后也可以接受消息。
非持久化订阅者:服务挂了就不接受消息。
ActiveMQ高可用
高可用配置(主从):
kahaDB目录中有一个lock文件,谁抢到锁谁就是master,修改activemq.xml配置文件的openwire端口号,修改jetty配置文件的端口号,然后 两个配置文件的kahaDB文件目录要一致
高可用配置(集群负载均衡):
缺点:当消息刚刚发送到node1但是Consumer还没来得及消费,node1就挂掉造成消息丢失。