RabbitMq的学习总结

3 篇文章 0 订阅
2 篇文章 0 订阅

为什么要使用MQ

  • 应用解耦: 一个系统需要给多个系统提供数据时,使用接口调用,调用系统的增加与减少,要直接修改代码,耦合很严重,所以直接推送消息到队列,哪个系统需要数据直接订阅即可

  • 异步消息:一个下单的业务流程伴随订单的成功,需要减库存,发送短信等操作,业务的总响应时间=发邮件执行时间 + 发送短信执行时间,此时可以把发短信、发邮件等操作使用MQ来异步操作,不需要等待发短信等操作返回,直接响应给客户端,大大提高了性能

  • 流量削峰:假如每天的某一刻访问量会暴增5000,此时数据库的承受访问量3000,那么直接将访问请求放过会导致数据库宕机,将访问的请求放入MQ的队列中,每次只拉取部分操作,进而保护了数据库

RabbitMQ的工作模式有哪些

简单模式
  • 消息生产者投递消息到队列
  • 消息消费者监听消息队列,消费队列中的消息

python-one.png

work模式
  • 消息生产者投递消息到队列
  • 多个消息消费者监听消息队列,若A消息投递到队列,消费者会以竞争的关系去竞争消费
  • 若 C1 消费了A消息,A消息直接从队列中丢弃,C2就消费不了已经消费的A消息,也就是说谁抢到的消息谁消费

python-two.png

发布订阅模式
  • 消息生产者投递消息到交换机
  • 交换机把消息投递到绑定此交换机的每个消息队列
  • 消费者去监听各自的消息队列,每一个消费者都能接收到相同的消息

python-three.png

路由模式
  • 生产者去投递消息到交换机
  • 交换机将消息按照 routing key 的匹配规则投递消息到匹配的队列中
  • 消费者去监听各自的消息队列去消费消息

python-four.png

主题模式
  • 生产者去投递消息到交换机
  • 交换机将消息按照 routing key 的模糊匹配规则投递消息到匹配的队列中
  • 消费者去监听各自的消息队列去消费消息
  • 主题模式和路由模式不同之处: 主题模式的路由可以支持通配符
    • a. *星号代表多个单词
    • b. #井号代表一个单词

python-five.png

交换机类型

  • 通配符交换机
    • toppic 交换机 消息会发送到路由键 * # 规则匹配到的队列上
  • 直连交换机
    • direct 交换机 消息会发送到路由键完全匹配的队列上
  • 扇形交换机
    • fanout 交换机 消息发送到绑定交换机的所有队列上,每一个绑定队列的消费者消费同样的消息
  • 头交换机
    • head 交换机 消息根据头中的属性进行匹配发送到对应的队列上

使用MQ的常见问题

  • 消息的重复问题(幂等性)
  • MQ消息的可靠性/消息的丢失
  • MQ的高可用

怎么保证MQ的高可用

首先是使用MQ集群

  • 常用的集群方案
    • 镜像集群:消息实体会在集群中进行同步,所以一个节点宕机不影响消息的使用,但是会损耗服务器性能和网络带宽
    • 普通模式:集群的元数据(队列相关的数据)会同步到各个节点,但是消息实体不会在节点间进行同步,在消费者消费队列的消息时,发现需要的消息不在此时正在消费的队列中,消息实体就会临时在节点间传输,把消息实体拉取给正在消费的队列,所以此模式下若存放消息的节点宕机依然会消息丢失,不建议使用

怎么保证MQ消费的幂等性

  • 使用全局唯一的ID进行防重复校验:消费者消费消息的时候,去使用全局唯一的 ID 查询是否已经存在,不存在就去消费
    ps:此时在并发场景会有问题,A线程查询结果为唯一ID不存在可以进行消费,此时CPU时间片丢失, B线程获取到,同样校验这个ID不存在进而保存成功,然后时间片A线程重新获取到,继续执行业务,再次保存成功,产生重复消费

  • 解决:使用 redis分布式锁

  • 可以在数据库的唯一索引去重,若ID已存在则不会保存成功

  • 使用乐观锁版本号机制,假如使用消费的信息更新数据库,可以数据库增加一个version字段,当线程A需要更新数据时,读取到的 version 等于当前数据库中的 version 值才会更新成功,同时version值已经+1,由于inndb的锁级别是行锁,只有更新成功后别的线程才可以去更新,此时version的值已经+1,别的线程更新不到此行数据

怎么保证MQ的可靠性(怎么防止数据丢失)

  • 首先要使用高可用模式的镜像集群
  • 生产者:
    • 生产者发送消息到交换机的时候,开启回调,增加日志或者发送报警邮件给运维人员
  • 交换机
    • 交换机转发消息到队列中的时候,开启回调,增加日志或者发送报警邮件给运维人员
    • 开启持久化
  • 消费者:
    • 开启手动ACK机制
    • 消费重试机制
      • 使用MQ的重试机制,使用手动ACK,消费失败重新放回队列再次消费,若依然失败发送邮件后保存日志告警
      • SpringBoot的重试机制,进行重新执行消费,若消费失败抛出异常,抛出异常的同时,记得持久化日志,发送邮件告警
  • MQ:
    • 开启队列的持久化
    • 开启消息的持久化

怎么解决数据堆积

  • todo

如何实现定时消费

  • 使用死信队列

    • 什么是死信队列?

      • 死信就是消息的状态,达到这个状态的消息就会被投递到死信交换机上,死信交换机转发消息到绑定的队列中,再逻辑上称之为死信队列和死信交换机
      • ps:死信不是队列和交换机的类型,是为了专门管理达到某种条件变为死信的消息的队列和交换机,我们逻辑上称之为死信交换机和死信队列
    • 消息什么情况会变为死信?

      • 当设置 TTL 的消息,到达过期时间没有被消费
      • 消费者拒绝消费basicNack/basicReject 并且不把消息重新放入原队列requeue=false
      • 队列到达最大长度限制后,最先入队的消息会被放入死信队列
    • 使用DLX + TTL死信队列实现延迟队列

      • 下单后订单存入订单队列 order.queue
      • 当队列的消息达到过期时间(30min),被投递到 order.dead.queue 死信队列中
      • 死信队列绑定费者,去消费死信队列中的数据,执行取消订单的操作
    • 使用死信队列实现定时消费缺点?

      • 给队列设置 TTL,不同过期时间的订单需要多个死信队列
      • 给消息配置 TTL,时序问题,MQ检查先进入的消息是否过期,过期后会被投放死信队列,排在之后的已经过期的消息有可能被阻塞
  • 使用延迟队列插件

    • 下载插件放入MQ的安装目录的plugin文件夹

    • 启用插件

         rabbitmq-plugins enable rabbitmq_delayed_message_exchange
      
    • 停用插件

        rabbitmq-plugins disable rabbitmq_delayed_message_exchange
      
    • 使用方式

      • 声名x-delayed-message 类型的交换机
      • 消息发送时指定消息头x-delay,单位以毫秒为单位将消息进行延迟投递
      • 指定基本交换机类型
        • 需要路由行为指定 x-delay-type: topic,
        • 不需要路由行为指定 x-delay-type: direct
      • 消息将持久保存到 Mnesia
  • 私信队列详细使用方式

ps: 此插件的当前设计并不适合具有大量延迟消息的场景(例如,数千或数百万的100个)。有关详细信息,请参阅 #72

Reference

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值