RabbitMQ

MQ的作用以及应用场景

MQ 就是「中转站 + 缓冲池 + 快递柜」

应用场景:

  • 异步解耦:在业务流程中,MQ将一些很耗时但不需要即使返回结果的操作异步化(比如下单以后的短信通知,积分发放,优惠卷返还之类)
  • 流量削峰:访问量剧增情况下,比如秒杀或者促销可以使用MQ来控制流量,将请求排队,然后系统逐步处理请求
  • 异步通信:很多应用不需要立即处理信息,把一些消息放入MQ中,等到需要处理的时候再慢慢处理
  • 消息分发:比如支付成功后,支付系统向MQ发消息,然后其他系统订阅该消息而不需要轮询数据库
  • 延迟通知:如果用户下单一定时间内未支付,可以使用延迟队列在超时后自动取消订单

了解哪些MQ,以及区别

  1. RabbitMQ:功能完备,万级别QPS,界面友好,社区活跃
  2. Kafka:十万级别QPS、适合大数据、日志、海量消息排队

消息模型

AMQP核心组件:生产者,消费者,交换机,队列,绑定,虚拟主机

说一说RabbitMQ的工作模式

工作模式本质上时生产者,交换机,队列,消费者这几个角色的不同组合方式

  1. 简单队列:默认Direct交换机,直接发送到队列,单生产者,单消费者
  2. 工作队列:默认Direct交换机,轮询分发,多个消费者负载均衡
  3. 发布订阅:Fanout交换机,广播到所有队列
  4. 路由:Direct交换机,精准路由键匹配,点到点精确路由
  5. Topic:Topic交换机,通用夫路由键匹配,一对多模式匹配
  6. RPC:远程调用,通常用于客户端请求服务器的响应
  7. 发布确认:确保生产者消息发送的可靠性,适合需要确保消息成功到达队列的场景

消息队列如何保证消息不丢失

需要在生产,储存和消费三个阶段共同配合

生产者 :在发送消息时应通过同步或异步的方式接收Broker的响应,做好try-catch异常捕获,若收到写入失败等错误,应进行重试,多次重试失败后触发报警并记录日志

Broker :应该在消息写入磁盘后再返回响应,防止因断电导致内存中消息丢失。在集群环境下启用仲裁队列Raft多副本机制,配置为至少写入两个节点后响应

消费者:关闭自动ACK,必须在业务真正执行完再给Broker发送ACK,防止处理到一半消费者宕机,如果消费者持续处理失败,消息队列会自动重试失败,重试多次还是失败的消息会被扔到私信队列,方便事后排查,避免消息丢失(kafka需要自行实现死信队列)

RabbitMQ的保障机制

它通过Confirm模式保证消息到达Broker,开启后Broker会异步回调通知生产者是否成功。然后必须交换机持久化,队列持久化,消息持久化,三者缺一不可。

最后消费阶段要设成手动ACK

消息队列如何处理重复消息(保证消息的幂等性)

  1. 基于唯一标识去重:给每条消息分配一个全局唯一ID,可以用UUID,雪花ID或也业务单号。消息方法收到消息后先拿这个ID去Redis或数据库查一下,查到说明处理过直接返回,没查到就执行业务逻辑然后把ID存进去
  2. 可以利用业务本身幂等性,比如数据库唯一索引和状态机控制
    项目中就是雪花ID+先查后写+MySQL唯一索引

Rabbitmq是怎么保证消息序列的顺序性的

Rabbitmq默认情况下一个队列中的小时是按照顺序存储和投递的,若使用单一队列并配合单一消费者进行消费,则可以保证消息的顺序性。对于高并发场景,可以通过多队列策略,格局业务Key(如订单)哈希后路由到不同队列,每个队列由独立的但消费者消费,从而实现部分有序并提升并发能力。

TTL

用于控制消息在队列中的存活时间防止消息无限期积压,避免占用过多系统资源。

消息级别的TTL优先级大于队列级别的TTL。

如果大量消息同时过期怎么办
  1. 分散过期时间:随机抖动0~60秒
  2. 增加死信队列消费者的并发度
  3. 设置死信队列的TTL
  4. 设置监控与警告,比如一千条积压时警告