面试之消息队列

使用mq的优缺点

优点

  • 解耦,生产者与消费者都只需要与mq进行交互,减少了强依赖。

  • 流量削峰,将大量请求放入mq后,服务器可以根据自身能力从mq中拉取消息消费。

  • 异步通信,减少客户端响应时间。

缺点

  • 系统更复杂,运维成本增加。

  • 可用性降低,存在mq服务器宕机的风险。

 

关键角色

  • broker,可理解为一个mq服务器实体。

  • channel,真实TCP连接上的虚拟连接,生产者/消费者与mq服务器通信的工具。

  • queue,存放消息的队列,消费者通过订阅指定队列进行消费。

  • exchange,根据BindingKey和RoutingKey匹配关系,将生产者的发送消息分发给不同的队列。

  • BindingKey,exchange与queue的绑定关系。

  • RoutingKey,生产者将消息发送给exchange时指定的路由键。

根据BindingKey的不同,可以将exchange分为不同模式:

  • direct,如果RoutingKey完全匹配BindingKey则分发,形如“hello”等。

  • fanout,exchange将收到的消息分发给所有绑定的队列,其实是RoutingKey和BindingKey都为空。

  • topic,如果RoutingKey匹配BindingKey的正则表达式则分发,“ * ” 匹配一个任意文本,“ # ”匹配0个或多个任意文本,文本间以“ . ” 隔开,例如BindingKey为“ *.a.# ”,RoutingKey为“ b.a.c ”。

消费者消费消息的两种模式:

  • push,由mq服务器将消息推送给消费者消费,更常用。

  • poll,由消费者主动向mq服务器拉取消息消费。

 

死信队列与延时队列

死信交换机与死信队列

死信交换机其实就是一个普通的交换机,只不过它不会去接收生产者的消息,而是接收来自其他消息队列中的死信。普通的消息队列可以指定x-dead-letter-exchange参数来指定死信交换机,以及x-dead-letter-routing-key参数指定死信的RoutingKey,当队列中的消息变为死信后就将其发送到死信交换机。绑定在死信交换机上的队列称为死信队列,死信交换机根据死信的RoutingKey分发给不同的死信队列。一条普通消息变为死信的情况有:

  • 消息TTL过期,即过期仍未被消费。TTL可以由生产者在发送消息时指定,也可以在创建queue时通过x-message-ttl参数指定(此时所有进入该队列的消息都有指定的TTL),如果两种方式都指定了则取更小值。

  • 消费者消费失败,返回nack,并设置requeue参数的值为false(如果为true则该消息会重新入队)。

  • 队列达到最大长度,可在创建queue时指定最大长度。

此时除了普通的消费者外,还应有专门处理死信队列消息的消费者。

延迟队列

RabbitMQ中并未直接提供延时队列,但可以通过给队列设置消息过期时间并指定死信交换机来实现延时队列。典型的应用场景如:新建订单超过15分钟未支付则自动取消。

 

消息确认

消息发送确认

通过消息发送确认来确保生产者发送的消息能正常到达exchange。Springboot整合的RabbitTemplate中提供了ConfirmCallback接口作为消息发送失败时的回调,需在配置文件中开启publisher-confirms。

消息路由确认

通过消息路由确认来确保生产者发送的消息能被exchange正常路由给队列。Springboot整合的RabbitTemplate中提供了ReturnCallback 接口作为消息路由失败时的回调,需在配置文件中开启publisher-returns。

消息接收确认

通过消息接收确认来确保消费者成功消费消息。消费者确认消息共有三种模式:

  • none,无确认模式,默认。无确认模式下RabbitMQ认为推送出去的消息都被成功消费,会直接在队列中删除消息(无论消费者后续处理异常或者是宕机)。

  • auto,自动确认模式。自动确认模式下RabbitMQ会根据消费者是否抛异常来决定返回ack(无异常)或nack(有异常),返回nack的消息会根据其附带的requeue参数来决定将其重新入队(true)或丢弃(false,也可能是发给死信exchange)。

  • manual,手动确认模式。消费者调用basicAck()、basicReject()或basicNack()手动回复确认消息,其中basicAck()返回ack,后两种返回nack。basicNack()与basicReject()的区别是可以一次性拒绝多条消息。

 

重复消费与顺序消费

重复消费

重复消费的解决办法有两种:

  • 确保一个消息只被消费一次,可以给每条消息添加唯一标识,当消费成功后将其存入Redis标识已被处理,消费者在消费之前先从Redis中查询该消息是否被消费。

  • 保证消费者消费消息的幂等性,即消费者消费一次消息和消费多次消息的起到的效果是一样的,可以借助数据库唯一性约束实现。

顺序消费

将需要被顺序消费的消息放入同一个队列,并保证该队列只有一个消费者,利用队列先进先出的特性保证顺序消费。

posted @ 2023-09-27 21:01  万里阳光号船长  阅读(20)  评论(0编辑  收藏  举报