消息队列
概念
消息(Message)是指在应用间传送的数据。消息可以非常简单,比如只包含文本字符串,也可以更复杂,可能包含嵌入对象。
消息队列(Message Queue)是一种应用间的通信方式,消息发送后可以立即返回,由消息系统来确保消息的可靠传递。消息发布者只管把消息发布到 MQ 中而不用管谁来取,消息使用者只管从 MQ 中取消息而不管是谁发布的。这样发布者和使用者都不用知道对方的存在。
场景
如果商品服务和订单服务是两个不同的微服务,在下单的过程中订单服务需要调用商品服务进行扣库存操作。按照传统的方式,下单过程要等到调用完毕之后才能返回下单成功,如果网络产生波动等原因使得商品服务扣库存延迟或者失败,会带来较差的用户体验,如果在高并发的场景下,这样的处理显然是不合适的。
消息队列提供了一个异步通信的机制,消息的发送者不必一直等待到消息被成功处理才返回,而是立即返回。消息中间件负责服务间的网络通信,如果网络连接不可用,消息被暂存于队列当中,当网络畅通的时候在将消息转发给相应的应用程序或者服务,当然前提是这些服务订阅了该队列。如果在商品服务和订单服务之间使用消息中间件,既可以提高并发量,又降低服务之间的耦合度。
作用
一般用来解决应用解耦,异步处理,流量削峰等问题,实现高性能,高可用,可伸缩和最终一致性架构。
解耦:服务间通过MQ消息进行通信,至于生产者发送MQ的逻辑和消费者消费的逻辑,对于两边来说都是不关注的,即使两边各自修改了逻辑,只要消息结构不变,就不会导致另一方跟着修改代码。
异步处理:上述场景。要确保2个服务之间没有强依赖的关系,即上游可以不用等到下游返回结果就可以自行处理之后的逻辑,使用时应该多从业务的角度出发。
流量削峰:大量的请求同时进来,会对服务器造成很大的压力,此时,只需要把待处理的请求放到MQ中,然后服务器再去消费请求,这样,请求的处理速度就取决于服务器本身,就不会出现超过服务器最大请求量的情况了。
常用的消息中间件
协议
JMS(Java Message Service)
JMS 是 JavaEE 的消息服务接口,和 JDBC 一样,JMS 作为规范,只是提供了一套接口,并不包含具体的实现,如果我们要使用 JMS,还需要有对应的实现,这就像使用 JDBC 需要对应的驱动一样,开源的支持 JMS 的消息中间件有Kafka、ActiveMQ等。
通信模式
点对点(Point-to-Point Messaging Domain )
在点对点通信模式中,应用程序由消息队列,发送方,接收方组成。每个消息都被发送到一个特定的队列,接收者从队列中获取消息,队列保留着消息,直到他们被消费或超时。
- 每个消息只有一个消费者
- 发送者和接收者在时间上是没有时间的约束,也就是说发送者在发送完消息之后,不管接收者有没有接受消息,都不会影响发送方发送消息到消息队列中
- 发送方不管是否在发送消息,接收方都可以从消息队列中取到消息
- 接收方在接收完消息之后,需要向消息队列应答成功
发布/订阅模式(Publish/Subscribe Messaging Domain)
在发布/订阅消息模型中,发布者发布一个消息,该消息通过topic传递给所有的客户端。该模式下,发布者与订阅者都是匿名的,即发布者与订阅者都不知道对方是谁。并且可以动态的发布与订阅Topic。Topic主要用于保存和传递消息,且会一直保存消息直到消息被传递给客户端。
- 一个消息可以传递个多个订阅者(即:一个消息可以有多个接受方)
- 发布者与订阅者具有时间约束,针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息,而且为了消费消息,订阅者必须保持运行的状态
- 为了缓和这样严格的时间相关性,JMS允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有被激活(运行),它也能接收到发布者的消息
Kafka
模型:
1.配置 消费组,监听topic
2.分区 时序性
3.消息堆积,服务方消费能力不足
4.offset
5.幂等
6.死信队列
AMQP(Advanced Message Queuing Protocol)
进程间传递异步消息的网络协议。AMQP 协议的一些具体的消息中间件产品:ActiveMQ、RabbitMQ
工作过程
- 发布者(Publisher)发布消息(Message),经由交换机(Exchange)。
- 交换机根据路由规则将收到的消息分发给与该交换机绑定的队列(Queue)。
- 最后 AMQP 代理会将消息投递给订阅了此队列的消费者,或者消费者按照需求自行获取。