啊啊消息队列就是用来存储消息的容器,假如A应用需要将消息传送给B,那么他并不是直接发送给B,而是将消息发送到消息队列中,由B直接从消息队列中获取。
消息队列作用
解耦
假如系统A需要将数据发送个B,那么直接定义一个发送至B的方法,但是不久之后,A的数据又需要发送到C呢,难道再更改A的代码,这样可扩展性太低了。但是,有了消息队列就不同了,A直接将消息发送到消息队列,不用去管谁需要使用消息。
异步
系统A将数据写到消息队列,就可以直接返回,可以不用管消费者具体怎么处理数据的。
削峰
当短时间内并发量比较大时,可能暂时无法处理这么多请求,可以先将消息存储再消息队列中,等并发量下去了在处理堆积的请求。
三种协议
JMS
ActiveMQ是基于JMS的。
JMS主要有两种消费模式,点对点和发布/订阅模式。这两种模式的区别主要在于消息是否可以重复消费。
点对点

生产者将消息发送到Queue中,消费者从Queue中取出消息并消费。消息被消费完之后,Queue中消息会被删除。
Queue支持存在多个消费者,但是一条消息只可能被一个消费者消费,一旦消费完成消息会被删除。
这种模式消费者需要不断去轮询监听消息队列看有没有新的消息产生。
发布/订阅模型

生产者将消息发送到topic,同时有多个消费者订阅该消息,那么所有的订阅者都会消费该消息。
发布订阅模式缺点是无法感知客户端的实际处理能力。
发布订阅模式下,当发布者消息量很大时,显然单个订阅者的处理能力是不足的。实际上现实场景中是多个订阅者节点组成一个订阅组负载均衡消费topic消息即分组订阅,这样订阅者很容易实现消费能力线性扩展。可以看成是一个topic下有多个Queue,每个Queue是点对点的方式,Queue之间是发布订阅方式。

AMQP
与JMS一样,他也有生产者和消费者,消息也是存储在Queue中的。
最大的不同是,AMQP是通过bindingkey和exchange来决定将消息给哪个消费者消费。
在创建Queue的时候给Queue一个binding key,生产者发送消息的时候,会给这条消息设定一个router key,exchange会将router key与binding key进行比较,将消息发送到符合的Queue中,再由相应的消费者消费消息。
交换机收到生产者投递的消息,基于路由规则及队列绑定关系匹配到投递对应的交换机或者队列进行分发,交换机不存储消息,只做转发。
RabbitMQ使用的是该协议。
MQTT
专门为小设备设计,简单不复杂,适用于物联网。
基于发布/订阅模式。
推/拉两种模式
在消费中,一般有推消息和拉消息两种模式。
推模式即服务端收到消息后,主动将消息推送给消费者,由消费者进行处理,这种模式具有更高的实时性,但是由于服务端不能准确评估消费端的消费性能,所以有可能造成消息推送过多使客户端来不及处理收到的消息;
拉模式则是服务端收到消息后将消息保存在服务端,被动的等待客户端来拉取消息,这种模式下客户端可以根据自己的处理能力来决定拉消息的频率,但是缺点就是消息处理可能有延迟,不过可以通过长轮询的方式来提高实时性。
三种消息级别
至多一次
这个很简单,消息发送完就不管了,不管它有没有消费成功。
至少一次
生产者发消息到 MQ,MQ 收到消息后返回确认信息(ACK)给生产者,生产者收到确认信息后生产过程完成,如果在一定时间内,生产者没有收到确认信息,生产者重新发送消息。
但是这样就容易导致重复发送的问题。
恰好一次
发送端发消息给接收端,接收端收到消息后持久化保存消息 ID 并返回 REC 信息给发送端,通知生产端我已经收到这个消息了。 这时消息是一种中间态,接受端不会进行业务逻辑的处理。这个过程中,如果 REC 消息丢失,服务端重传了消息, 接受端接受到消息后会和本地保存到消息 ID 做对比,如果重复,就丢弃消息不做处理,避免消息被处理多次,而且消息 ID 会持久化到硬盘,防止因为断电内存中数据丢失倒是消息被重复处理。 发送端收到接收端返回的 rec 消息后,发送一个 rel 请求给消费端,告诉消费端我确认收到了你的确认消息,接收端收到 rel 请求后才会进行具体的业务逻辑处理,并返回 comp 信息给发送端,同时在本地删除保存的消息 ID。如果发送端没有收到 comp 信息,会重发 rel 请求而不会重发消息。
其实,在大部分情况下,大部分消息中间件一般只保证至少一次,去重的过程交给消费者自己处理了。 那么,什么场景下,需要保证正好一次呢? 答案是物联网。 而标准的实现协议,是 MQTT。 因为物联网场景下,大部分终端是嵌入式系统,处理能力会比服务器低很多,所以服务端需要帮助终端实现去重,简化终端的业务逻辑。
高可用性
集群来解决。
幂等性
保证消息不会被重复消费。
可靠性保障
保证消息不会丢失。
顺序消息
事务消息
刷盘问题

同步刷盘:写入到pageCache之后,需要手动将pageCache数据落盘才返回。不会丢消息,但是效率低。
异步刷盘:写入到pageCache就返回,pageCache落盘由操作系统定期执行。效率高,但是宕机有可能丢消息。