RabbitMQ

一、什么是 RabbitMQ

RabbitMQ 是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件),最大的特点就是消费并不需要确保提供方存在,实现了服务之间的高度解耦。RabbitMQ 服务器是用 Erlang 语言编写的,而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库。

重要的角色

  1. 生产者:消息的创建者,负责创建和推送数据到消息服务器。
  2. 消费者:消息的接收方,用于处理数据和确认消息。
  3. 代理:就是 RabbitMQ 本身,用于扮演“快递”的角色,本身不生产消息,只是扮演“快递”的角色。

重要的组件

  1. ConnectionFactory(连接管理器):应用程序与 RabbitMQ 之间建立连接的管理器,程序中使用。
  2. Channel(信道):消息推送使用的通道。
  3. Exchange(交换器):用于接受、分配消息。
  4. Queue(队列):用于存储生产者的消息。
  5. RoutingKey(路由键):用于把生成者的数据分配到交换器上。
  6. BindingKey(绑定键):用于把交换器的消息绑定到队列上。

二、为什么要使用 RabbitMQ

  1. 在分布式系统下具备异步、削峰、负载均衡等一系列高级功能。异步通信性能高。
  2. 拥有持久化的机制,进程消息,队列中的信息也可以保存下来。
  3. 实现消费者和生产者之间的解耦。
  4. 高并发场景下,利用消息队列可以使得同步访问变为串行访问达到一定量的限流,利于数据库的操作。
  5. 可以使用消息队列达到异步下单的效果,排队中,后台进行逻辑下单。

三、RabbitMQ 的使用场景

  1. 【流量削峰】抢购活动,削峰填谷,防止系统崩塌。
  2. 【定时任务】延迟信息处理,比如 10 分钟之后给下单未付款的用户发送邮件提醒。
  3. 【解耦、服务间异步通信】对于新增的功能可以单独写模块扩展,比如用户确认评价之后,新增了给用户返积分的功能,此时不用在业务代码里添加新增积分的功能,只需要把新增积分的接口订阅确认评价的消息队列即可,后面再添加任何功能只需要订阅对应的消息队列即可。
  4. 顺序消费。实现原理:同一队列中保持有序;相同业务的 ID 分配到相同的队列。

四、如何确保消息正确地发送至 RabbitMQ?如何确保消息接收方消费了消息?

1️⃣发送方确认模式
将信道设置成 confirm 模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的 ID。一旦消息被投递到目的队列后,或者消息被写入磁盘后(可持久化的消息),信道会发送一个确认给生产者(包含消息唯一 ID)。如果 RabbitMQ 发生内部错误从而导致消息丢失,会发送一条 nack(notacknowledged,未确认)消息。发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。当确认消息到达生产者应用程序,生产者应用程序的回调方法就会被触发来处理确认消息。

2️⃣接收方确认机制
消费者接收每一条消息后都必须进行确认(消息接收和消息确认是两个不同操作)。只有消费者确认了消息,RabbitMQ 才能安全地把消息从队列中删除。这里并没有用到超时机制,RabbitMQ 仅通过 Consumer 的连接中断来确认是否需要重新发送消息。也就是说,只要连接不中断,RabbitMQ 给了 Consumer 足够长的时间来处理消息。保证数据的最终一致性。

3️⃣下面罗列几种特殊情况:
①如果消费者接收到消息,在确认之前断开了连接或取消订阅,RabbitMQ 会认为消息没有被分发,然后重新分发给下一个订阅的消费者。(可能存在消息重复消费的隐患,需要去重)
②如果消费者接收到消息却没有确认消息,连接也未断开,则 RabbitMQ 认为该消费者繁忙,将不会给该消费者分发更多的消息。

消息的可靠性怎么是保证的

①生产者端:通过同步发送消息,收到服务端的确认写入并存储,来保证一致性;RabbitMQ 还支持先写入本地磁盘再发送给服务端
②服务器端:通过把消息写入磁盘、数据库、分布式存储系统中,保证服务端的可靠性。
③消费端:通过消费端确认消费成功,才进行下一条消费;通过消息重试保证最终会被消费。

五、如何避免消息重复投递或重复消费?

MQ 的服务端通常不保证消息不重复,由业务端来去重。主要是消费端业务逻辑保持幂等性;也可以由消息的服务端通过 messageId 保证,但是通常不这么做。在消息生产时,MQ 内部针对每条生产者发送的消息生成一个 inner-msg-id,作为去重的依据(消息投递失败并重传),避免重复的消息进入队列;在消息消费时,要求消息体中必须要有一个 bizId (对于同一业务全局唯一,如支付 ID、订单 ID 等)作为去重的依据,避免同一条消息被重复消费。

消息重复消费的场景

  1. 网络出现抖动。
  2. 消费端任务执行超时。
  3. 消费端出现异常。

业务端如何保证幂等性

  1. 使用唯一字段,建立唯一性索引。
  2. 多版本控制。
  3. 状态机幂等。
  4. 保证数据唯一性的其它方式,比如通过 redis、zk 等方式。

六、RabbitMQ 的消息是怎么发送的

由于 TCP 连接的创建和销毁开销较大,且并发数受系统资源限制,会造成性能瓶颈。RabbitMQ 使用信道的方式来传输数据。信道是建立在真实的 TCP 连接内的虚拟连接,且每条 TCP 连接上的信道数量没有限制。

首先客户端必须连接到 RabbitMQ 服务器才能发布和消费消息,客户端和 rabbit server 之间会创建一个 TCP 连接,一旦 TCP 打开并通过了认证(认证就是你发送给 rabbit 服务器的用户名和密码),你的客户端和 RabbitMQ 就创建了一条 amqp 信道(channel),信道是创建在“真实” TCP 上的虚拟连接,amqp 命令都是通过信道发送出去的,每个信道都会有一个唯一的 id,不论是发布消息,订阅队列都是通过这个信道完成的。若该队列至少有一个消费者订阅,消息将以循环(round-robin)的方式发送给消费者。每条消息只会分发给一个订阅的消费者(前提是消费者能够正常处理消息并进行确认)。通过路由可实现多消费的功能。

七、消息怎么路由

消息提供方—>路由—>一至多个队列。消息发布到交换器时,消息将拥有一个路由键(routing key),在消息创建时设定。通过队列路由键,可以把队列绑定到交换器上。消息到达交换器后,RabbitMQ 会将消息的路由键与队列的路由键进行匹配(针对不同的交换器有不同的路由规则)。

常用的交换器(广播类型)主要分为以下四种:

  1. direct(默认):最基础最简单的模式,发送方把消息发送给订阅方,如果有多个订阅者,默认采取轮询的方式进行消息发送。如果路由键完全匹配,消息就被投递到相应的队列。
  2. headers:与 direct 类似,只是性能很差,此类型几乎用不到。
  3. fanout:分发模式,把消费分发给所有订阅者。如果交换器收到消息,将会广播到所有绑定的队列上。
  4. topic:匹配订阅模式,使用正则匹配到消息队列,能匹配到的都能接收到。可以使来自不同源头的消息能够到达同一个队列。 使用 topic 交换器时,可以使用通配符。

八、RabbitMQ 怎么避免消息丢失

消息持久化,当然前提是队列必须持久化。RabbitMQ 确保持久性消息能从服务器重启中恢复的方式是,将它们写入磁盘上的一个持久化日志文件,当发布一条持久性消息到持久交换器上时,RabbitMQ 会在消息提交到日志文件后才发送响应。一旦消费者从持久队列中消费了一条持久化消息,RabbitMQ 会在持久化日志中把这条消息标记为等待垃圾收集。如果持久化消息在被消费之前 RabbitMQ 重启,那么 RabbitMQ 会自动重建交换器和队列(以及绑定),并重新发布持久化日志文件中的消息到合适的队列。每个集群中至少有一个物理磁盘,保证消息落入磁盘。

九、RabbitMQ 持久化的缺点

持久化的缺点就是降低了服务器的吞吐量,因为使用的是磁盘而非内存存储,从而降低了吞吐量。可尽量使用 ssd 硬盘来缓解吞吐量的问题。

十、要保证消息持久化成功的条件有哪些

  1. 声明队列必须设置持久化 durable 设置为 true.
  2. 消息推送投递模式必须设置持久化,deliveryMode 设置为 2(持久)。
  3. 消息已经到达持久化交换器。
  4. 消息已经到达持久化队列。

以上四个条件都满足才能保证消息持久化成功。

十一、RabbitMQ 节点的类型

  1. 磁盘节点:消息会存储到磁盘。
  2. 内存节点:消息都存储在内存中,重启服务器消息丢失,性能高于磁盘类型。

十二、RabbitMQ 集群中唯一的磁盘节点崩溃了会怎样

如果唯一磁盘的磁盘节点崩溃了,不能进行以下操作:

  1. 不能创建队列
  2. 不能创建交换器
  3. 不能创建绑定
  4. 不能添加用户
  5. 不能更改权限
  6. 不能添加和删除集群节点

唯一磁盘节点崩溃了,集群是可以保持运行的,但不能更改任何东西。

十三、RabbitMQ 为什么每个节点不是其他节点的完整拷贝

  1. 存储空间的考虑:如果每个节点都拥有所有队列的完全拷贝,这样新增节点不但没有新增存储空间,反而增加了更多的冗余数据。
  2. 性能的考虑:如果每条消息都需要完整拷贝到每一个集群节点,那新增节点并没有提升处理消息的能力,最多是保持和单节点相同的性能甚至是更糟。

十四、RabbitMQ 的集群镜像集群模式

无论元数据还是 queue 里的消息都会存在于多个实例上,然后每次写消息到 queue 的时候,都会自动到多个实例的 queue 里进行消息同步。

好处在于:任何一个机器宕机了,别的机器都可以用。
坏处在于:①性能开销太大,消息同步所有机器,导致网络带宽压力和消耗很重。②没有扩展性可言,如果某个 queue 负载很重,加机器,新增的机器也包含了这个 queue 的所有数据,并没有办法线性扩展 queue。

十五、RabbitMQ 集群有什么用

集群主要有以下两个用途:
高可用:某个服务器出现问题,整个 RabbitMQ 还可以继续使用;
高容量:集群可以承载更多的消息量。

十六、RabbitMQ 集群搭建需要注意哪些问题

各节点之间使用“–link”连接,此属性不能忽略。
各节点使用的 erlang cookie 值必须相同,此值相当于“秘钥”的功能,用于各节点的认证。
整个集群中必须包含一个磁盘节点。

十七、RabbitMQ 对集群节点停止顺序有要求吗

RabbitMQ 对集群的停止的顺序是有要求的,应该先关闭内存节点,最后再关闭磁盘节点。如果顺序恰好相反的话,可能会造成消息的丢失。

十八、RabbitMQ 中 vhost 的作用是什么

每个 RabbitMQ 都能创建很多 vhost,称之为虚拟主机,每个虚拟主机其实都是 mini 版的RabbitMQ,它拥有自己的队列,交换器和绑定,拥有自己的权限机制。

十九、RabbitMQ 实现延迟消息队列的两种方式

  1. 通过消息过期后进入死信交换器,再由交换器转发到延迟消费队列,实现延迟功能。
  2. 使用 RabbitMQ-delayed-message-exchange 插件实现延迟功能。

二十、消息队列消息推拉模式是什么意思,分别在什么场景下适用

①推:服务端主动;拉:消费端主动。
②看消费端的消费能力,处理复杂时间长的适合拉模式,推模式实时性响应更好;其中推对于消费端要求更高,拉对于 MQ 服务端的堆积能力要求较高。

二十一、假设发送一条消息需要 2ms,如何用最短时间完成300条消息的发送

创建多个 producter,然后使用一个线程池进行分组发送。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JFS_Study

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值