一、是什么?
RabbitMQ作为消息中间件的一种实现,常常被当作一种服务总线来使用。RabbitMQ原生就支持上面提到的两种消息模式。其他一些流行的消息中间件的实现有ActiveMQ,ZeroMQ,Azure Service Bus以及Amazon Simple Queue Service(SQS)。这些消息中间件的实现有许多共通的地方,这边文章中提到的许多概念大部分都适用于这些中间件。
二、异步消息模型
1.消息队列
解决问题:解耦生产者和消费者
利用消息队列可以解耦生产者和消费者。多个生产者可以向同一个消息队列发送消息;但是,一个消息在被一个消费者处理的时候,这个消息在队列上会被锁住或者被移除并且其他消费者无法处理该消息。也就是说一个具体的消息只能由一个消费者消费。
消息队列
需要额外注意的是,如果消费者处理一个消息失败了,消息系统一般会把这个消息放回队列,这样其他消费者可以继续处理。消息队列除了提供解耦功能之外,它还能够对生产者和消费者进行独立的伸缩(scale),以及提供对错误处理的容错能力。
2、发布/订阅
发布/订阅(pub/sub)模式中,单个消息可以被多个订阅者并发的获取和处理。
例如,一个系统中产生的事件可以通过这种模式让发布者通知所有订阅者。在许多队列系统中常常用主题(topics)这个术语指代发布/订阅模式。在RabbitMQ中,主题就是发布/订阅模式的一种具体实现(更准确点说是交换器(exchange)的一种),但是在这篇文章中,我会把主题和发布/订阅当做等价来看待。
一般来说,订阅有两种类型:
1)临时(ephemeral)订阅,这种订阅只有在消费者启动并且运行的时候才存在。一旦消费者退出,相应的订阅以及尚未处理的消息就会丢失。
2)持久(durable)订阅,这种订阅会一直存在,除非主动去删除。消费者退出后,消息系统会继续维护该订阅,并且后续消息可以被继续处理。
三、RabbitMQ优点
开箱即用的消息队列,开发者可以定义一个命名队列,然后发布者可以向这个命名队列中发送消息,最后消费者通过这个命名队列获取待处理的消息,RabbitMQ使用消息交换器来实现发布/订阅模式,发布者可以把消息发布到消息交换器上而不用知道这些消息都有哪些订阅者(观察者模式)
每一个订阅了交换器的消费者都会创建一个队列,然后交换器会把生产的消息放入队列,以供消费者消费。消息交换器也可以基于各种路由规则为一些订阅者过滤消息。
RabbitMQ消息交换器
需要重点注意的是RabbitMQ支持临时和持久两种订阅类型。消费者可以调用RabbitMQ的API来选择他们想要的订阅类型。
根据RabbitMQ的架构设计,我们也可以创建一种混合方法——订阅者以组队的方式然后在组内以竞争关系作为消费者去处理某个具体队列上的消息,这种由订阅者构成的组我们称为消费者组。按照这种方式,我们实现了发布/订阅模式,同时也能够很好的伸缩(scale-up)订阅者去处理收到的消息。
发布/订阅与队列的联合使用
消息生产者往队列发布消息,会通过绑定(binding key)和路由键(routing key)来进行分发,绑定是你设置的用来连接一个队列和交换机的连接,路由键是一个消息的属性,交换机会根据路由键来决定消息分发到那个队列。
交换机则启动一个连接的作用,从生产者把消息接收过来直接发送的根据绑定和路由键发送到队列,消息会留在队列,以供消费者消费,消费可以包括上面两种方法,临时和持久,临时则是消费者退出,消息释放,持久则是如果不手动删除这个消息,消息一直会保留的队列,直到消费掉。
应用场景
- 异步处理
- 应用解耦
- 流量消费
rabbitmq 有哪些重要的组件?
- ConnectionFactory(连接管理器):应用程序与Rabbit之间建立连接的管理器,程序代码中使用。
- Channel(信道):消息推送使用的通道。
- Exchange(交换器):用于接受、分配消息。
- Queue(队列):用于存储生产者的消息。
- RoutingKey(路由键):用于把生成者的数据分配到交换器上。
- BindingKey(绑定键):用于把交换器的消息绑定到队列上。
原理(用到的模式)
四、如何保证消息一致性
1.生产者生产消息到RabbitMQ Server 消息丢失场景
1) 外界环境问题导致:发生网络丢包、网络故障等造成RabbitMQ Server端收不到消息,因为生产环境的网络是很复杂的,网络抖动,丢包现象很常见,下面会讲到针对这个问题是如何解决的。
2) 代码层面,配置层面,考虑不全导致消息丢失
事例1:
一般情况下,生产者使用Confirm模式投递消息,如果方案不够严谨,比如RabbitMQ Server 接收消息失败后会发送nack消息通知生产者,生产者监听消息失败或者没做任何事情,消息存在丢失风险;
事例2:
生产者发送消息到exchange后,发送的路由和queue没有绑定,消息会存在丢失情况,下面会讲到具体的例子,保证意外情况的发生,即使发生,也在可控范围内。