计算机系统应用教程网站

网站首页 > 技术文章 正文

RabbitMq要点讲解

btikc 2025-02-07 16:41:50 技术文章 16 ℃ 0 评论

一、什么RabbitMq

  1. MQ就是message queue,即消息队列
  2. 一个处理即时消息/延时消息的中间件
  3. 一个传递消息的中间站

二、实际应用场景

  1. 消息通讯
    如短信通知,实时聊天等
  2. 数据量大的时效性任务
    如订单到时自动失效,定时任务,延时通知等
  3. 限制流量
    在双十一,618等期间订单的暴增会对服务器造成极大的负担,通过rabbitMq的消息队列的限流可以为服务器减载

三、最基本的框架

最简单的理解就是,producer生产者,即产生消息方,发送到中间件rabbitmq,通过交换机,路由等放入指定queue队列中,然后然后consumer消费者,即消息处理/接受方,获取到队列中的消息

四、轮询与不公平分发

1. 轮询

  • 原理图

此处的工作线程其实就是一个个的消费者,队列中的消息一开始会随机给到一个线程的消费者,然后下一个消息就会给下一个工作线程,如下图,若先是a收到消息,则下一条消息会给b,然后c,接着继续a,就轮着来

  • 缺点:太理想,效率低

2. 不公平分发

  • 理解:相比于轮询分发来说的(即helloworld那种消费方式),简单来见就是能者多劳,处理消息快的消费者就会多收消息,处理慢的少收消息
  • 原理
    channel.basicQos(int prefetchCount)方法:假设此处设置为1,那么当该消费者接收到一个消息后,还没应答前不会再接受消息了,而消息会被发到那些应答成功的消费者去
    • prefetchCount为服务会分发的消息的最大数量
    • basicQos:qos即quality of server,即服务的质量
    • 因此通过channel.basicQos(数量)可以设置每个消费者一定会收到多少条消息
  • 实例演示前提:消费者C1处理消息比较慢(线程睡眠来模拟快慢),消费者C2处理消息比较快1、在消费者C1消费前调用channel.basicQos(1)
    2、则在连续发送多条消息后,可以发现除了第一条消息是C1处理的,其他的都是C2处理的。
    原因:第一条消息的分发是多线程随机分发的,因此发给了C2,由于C2设置了最大通道量为1,因此在收到了aa第一个消息后,由于处理时间较长,还没处理完的这个期间,C2就不再接受消息了,即阻塞,因此消息全部由C1接受

五、防止消息丢失

1. 路线

2. 手动应答

  • 消息应答的概念
  • 基本应答方法
  • 消息自动重新入队机制一个消费者处理失败的消息会重新进入mq继续排队然后给下一个空闲的消费者处理,使消息不丢失

3. 持久化

  • 作用:前面我们保证了消息不丢失是在rabbitmq正常运作而消费者出问题的情况下,若rabbitmq宕机了,那么消息和队列都会不见!此时我们就要对队列和消息分别设置持久化
  • 持久化的方法不多赘述,这里讲几个要点
  • 已经声明(已存在)的没有设置持久化的队列在mq重启时就会丢失,对已经存在的队列就设置不了持久化,需要通过面板把它删掉,然后再创建

4. 发布确认

  • 前面我们讲到的防止因宕机而导致消息丢失的两个方法,消息持久化&队列持久化,做到这两点还是有可能导致数据丢失,即消息刚好要持久化之前就宕机了(还没来得及保存到磁盘上),这样还是会导致消息丢失
  • 因此发布确认的出现就是防止消息的这一部分丢失
  • 概念
    • 简单来讲就是,为了防止消息未存入磁盘之前就宕机导致数据丢失,需要在存入磁盘后通过mq通知生产者消息已经发布成功了,不成功生产者再进一步处理,这样才能真的保证所有消息真真正正地不丢失!
  • 发布确认三种方式,其中异步确认性能最好,效率最高
  • 三种发布确认的原理举例
    • 单个确认/批量确认:寄件人(生产者)自己打电话问快递站包裹(消息)到站(mq)了没,没确认前无法继续寄包裹(发消息不丢是)
    • 异步确认:寄件人(生产者)发包裹(消息)后,快递站(broker)主动通知包裹是否到达(确认),寄件人专心发剩下的包裹,不需要打电话确认
  • 消息队列可以看作一个map,当发布成功后会通过回调函数返回消息的key值,未确认的也会通过回调函数返回消息的key值,回调函数实际上是一个监听器,监听broker,是另开了一条线程,因此对原来线程的发布消息没有影响

六、交换机

  • 是什么、rmq中,生产者的消息从不直接发给队列,而是发给交换机,并由交换机发给队列,交换机通过routingkey这个标识找到绑定的队列然后将消息发给它们
  • 注意生产者类关注交换机和路由键(routingkey)消费者类关心队列名、交换机、路由键的绑定!最好两个都声明交换机

七、其他

  • 延迟队列死信的另一种表现形式
  • fanout只能群发,direct只能发给对应的队列,而不能将某个消息同时发给两个指定的消费者(当然可以使其routingkey一致,但是使其一致后又无法单独发送给指定的了,限制很大)
  • 交换机如果已经创建过了,且在页面中绑定过,在可视化页面可以找到的话,那么在java中使用都不用声明了,可以直接通过名称使用

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表