消息队列是指在消息的传输过程中保存消息的容器。
消息模型
- 点对点:消息生产者向消息队列中发送了一个消息之后,只能被一个消费者消费一次
- 发布-订阅:消息生产者向频道发送一个消息之后,多个消费者可以从该频道订阅到这条消息并消费
使用场景
异步
发送者将消息发送给消息队列之后,不需要同步等待消息接收者处理完毕,而是立即返回进行其它操作。消息接收者从消息队列中订阅消息之后异步处理。
解耦
如果模块之间不直接进行调用,模块之间耦合度就会很低,那么修改一个模块或者新增一个模块对其它模块的影响会很小,从而实现可扩展性。通过使用消息队列,一个模块只需要向消息队列中发送消息,其它模块可以选择性地从消息队列中订阅消息从而完成调用。
削峰
在高并发的场景下,如果短时间有大量的请求到达会压垮服务器。可以将请求发送到消息队列中,服务器按照其处理能力从消息队列中订阅消息进行处理。
缺点
- 系统可用性降低:消息队列挂了,整个系统就崩溃了
- 系统复杂性提高
- 保证没有重复消费
- 保证可靠数据传输
- 保证数据一致性
- 保证消息顺序
对比
ActiveMQ
:万级吞吐量;ms 级延迟;主从架构;低概率数据丢失;不推荐RabbitMQ
:万级吞吐量;μs 级延迟;主从架构;中小企业推荐RocketMQ
:10万级吞吐量;ms 级延迟;分布式架构;调优可数据另丢失;大公司推荐kafka
:10万级吞吐量;ms 级延迟;分布式架构;调优可数据另丢失 ;适用于大数据计算
重复消费
保证业务逻辑具有幂等性。
可靠性
发送端的可靠性:发送端完成操作后一定能将消息成功发送到消息队列中
- 开启事务,失败回滚并重试
- confirm 模式,异步模式
消息队列可靠性:持久化
接收端的可靠性:接收端能够从消息队列成功消费一次消息
- 保证接收端处理消息的业务逻辑具有幂等性:只要具有幂等性,那么消费多少次消息,最后处理的结果都是一样的
- 保证消息具有唯一编号,并使用一张日志表来记录已经消费的消息编号
顺序
拆分成多个消息队列,每个队列对应一个消费者。
RabbitMQ
RabbitMQ 是实现了高级消息队列协议(AMQP)的消息中间件技术。
名词
- 连接管理器(ConnectionFactory):应用程序与 RabbitMQ 之间建立连接的管理器,程序代码中使用
- 信道(Channel):消息推送使用的通道
- 交换器(Exchange):用于接收和转发消息
- 路由键(RoutingKey):把生成者的数据分配到交换器上
- 绑定键(BindingKey):把交换机的消息绑定到消息队列
信道
RabbitMQ 使用信道的方式进行数据传输。信道是建立在真实 TCP 连接内的虚拟连接,多个请求共享信道。
如果直接使用 TCP 连接,每个请求都会建立 TCP 连接,而 TCP 会话是非常昂贵的开销,并且操作系统每秒创建的 TCP 也是有限的,不利于高并发场景。
消息持久化
消息持久化需要程序员设置消息为持久化消息,RabbitMQ 将持久化消息写入磁盘上的持久化日志中。消息被消费之后将消息日志对应的记录标记为可回收。
交换器的四种模式
direct
:如果路由键匹配,则把消息投递到匹配的消息队列headers
:允许使用 AMQP 的 header 信息进行匹配,其他和direct
一致。性能不佳,不推荐使用fanout
:发布 / 订阅模式。当发送消息时,交换器把消息转发到所有绑定到该交换器的队列上topic
:匹配订阅模式,能够更灵活的匹配自己想订阅的消息
消息确认
为了保证消息能够顺利进入消息队列,RabbitMQ 提供了两种方式:
使用 AMQP 提供的事务机制,事务实现主要是对信道的设置。同步机制,性能很差,不推荐
channel.txSelect()
:声明启动事务模式channel.txComment()
:提交事务channel.txRollback()
:回滚事务使用发送者异步确认模式,也是设置Channel进行发送方确认的。异步监听,性能好