一、RabbitMQ安装配置与基础概念

本文介绍了如何安装配置Erlang和RabbitMQ,包括环境变量设置、服务管理,以及RabbitMQ的基础概念,如Server、Connection、Channel、Message、Virtualhost、Exchange、Queue和死信队列的用法。还讨论了消息丢失的避免策略、消息消费幂等性和不同Exchange类型的区别。

安装配置

📌注意Erlang与MQ的版本对应,可在官网版本页查看

  1. 安装Erlang
  2. 配置环境变量,复制对应bin路径安装目录\Erlang OTP\bin
    将此路径添加到系统环境变量的PATH字段下,之后保存后,打开命令控制台,输入 erl -v查看是否可以正常显示版本号
  3. 安装RabbitMQ
  4. 安装结束后进入对应目录的sbin文件夹,在此处打开命令控制台,输入
    rabbitmq-plugins enable rabbitmq_management待安装完成,
    右键“此电脑”,选择管理,打开windows的服务界面,启动rabbitMQ服务
  5. 浏览器输入MQ的控制台地址,输入帐号密码 guest / guest 即可登录查看

基础概念

📌RabbitMQ是一个开源的消息代理和队列服务器,用来通过普通协议
在完全不同的应用之间共享数据,RabbitMQ是使用Erlang语言来编写
的,并且RabbitMQ是基于AMQP1协议的。

server又称Broker,接受客户端的连接,实现AMQP实体服务
Connection连接,应用程序与Broker的网络连接
Channel网络通道,几乎所有的操作都在Channel中进行,Channel是进行消息读取的通道。客户端可建立多个Channel,每个Channel代表一个会话任务。
Message消息,服务器和应用程序之间传送的数据,由Properties和Body组成。Properties可以对消息进行修饰,比如消息的优先级、延迟等高级特效,Body则就是消息体内容
Virtual host虚拟地址,用户进行逻辑隔离,最上层的消息路由。一个Virtual Host里面可以有若干个Exchange和Queue,同一个Virtual Host里面不能有相同名称的Exchange和Queue
Exchange交换机,接收消息,根据路由键转发消息到绑定的队列
BindingExchange和Queue之间的虚拟连接,binding中可以包含routing key
Routing key一个路由规则,虚拟机可用它来确定如何路由一个特定消息
Queue也称作MessageQueue,消息队列,保存消息并将它们转发给消费者

在这里插入图片描述

死信队列是什么?

死信队列也是一个消息队列,它是用来存放那些没有成功消费的消息的,通常可以用来作为消息重试,如果队列没有配置死信队列,则消息一旦成为“死信”,便会直接丢弃

死信队列并不是什么特殊的队列,只不过是绑定在死信交换机上的队列。死信交换机也不是什么特殊的交换机,只不过是用来接收死信的交换机,所以可以为任何类型(Direct、Fanout、Topic)。一般来说,会为每个业务队列分配一个独有的路由 key,并对应的配置一个死信队列进行监听,也就是说,一般会为 每个重要的业务队列配置一个死信队列

什么情况下消息会进入死信队列?

  1. 消息被消费者拒绝且告知MQ将该消息放入死信队列
    a. 消费者回了一个Nack,而且第三个参数为false,channel.basicNack(deliveryTag, false, false)
    b. 消费者回了一个Reject,且第二个参数为false,channel.basicReject(deliveryTag, false)
  2. 消息在队列中的存活时间过期,即消息可以设置TTL2,TTL超时就会被放进死信队列。
  3. 队列设置了 x-max-length 最大消息数量且当前队列中的消息已经达到了这个数量,再次投递,消息将被挤掉,被挤掉的消息会路由进死信队列
  4. 当重复投递次数达到了设置的消费者设置了自动 ACK,当重复投递次数达到了设置的最大 retry 次数之后,消息也会投递到死信队列,但是内部的原理还是调用了basicNack()或basicReject()
#开启rabbitmq的生产端重试机制,默认是false,默认重试 3 次
spring.rabbitmq.template.retry.enabled=true
#开启rabbitmq的消费端重试机制,默认是false,默认重试 3 次
spring.rabbitmq.listener.simple.retry.enabled=true
#设置重试的次数
spring.rabbitmq.listener.simple.retry.max-attempts=5

什么是延时队列?

延时队列就是用来存放需要在指定时间被处理的消息队列,通常可以用来处理一些具有过期性操作的业务,比如十分钟内未支付则取消订单

本质上就是TTL机制加上死信队列,如消息设置TTL为30分钟,并为其设置一个死信队列,消息到期后就进入死信队列处理了

如何尽量避免消息丢失?

  1. 消息发送+回调确认、开启事务
  2. 开启spring的重试机制(retry)

在这里插入图片描述

如何信息消费的幂等性

  1. 给每条消息确定唯一消息ID

更多做法参考保证接口幂等性

Direct、Fanout、Topic三种交换机的区别

  1. Fanout Exchange交换机将会接到的消息路由到每一个与其绑定的队列中去
    解释:通俗来讲就是有几个队列跟此交换机绑定,发送消息时就会发送给每一个绑定的队列

  2. DirectExchange 会将接收到的信息根据规则路由制定的队列中去,因此也叫做路由模式(routes)
    解释:在与此交换机绑定的基础上,根据routingKey的值来选择性的发送消息

  3. TopicExchange与DirectExchange类似,区别在于routingKey必须是多个单词列表,并且以.分割
    解释:跟DirectExchange类似,只是还可以使用通配符#或者*来代替

    String routingkey = “testTopic.#”; // 匹配多个词
    String routingkey = “testTopic.*”; // 匹配单个词
    

如何保证 RabbitMQ 消息的顺序性?

在 RabbitMQ 中,消息的顺序性指的是消息按照它们被发送的顺序,能够按相同顺序被消费者处理。这在某些应用场景中(如交易、日志处理、事件驱动系统)非常重要。但由于 RabbitMQ 是分布式系统,加上并发处理的机制,保证消息的顺序性需要特定的设计和策略。

以下是几种保证 RabbitMQ 消息顺序性的常见方法:

  1. 单个队列与单个消费者
    最简单、最有效的方式是确保消息只通过一个队列传递,并且只有一个消费者在处理该队列的消息。RabbitMQ 保证同一队列中的消息是按发送顺序进行投递的,因此单一消费者处理消息时,消息的处理顺序可以得到保证。

    优点:简单直接,保证消息按顺序处理。
    缺点:当消息量很大时,单个消费者会成为系统瓶颈,无法充分利用并行处理的优势。

  2. 队列的公平分发 (Prefetch)
    如果需要在一个队列上使用多个消费者,为了保证顺序性,你可以通过设置 prefetch 来确保每个消费者在处理完一条消息后,才能接收下一条消息。这种方式可以确保每个消费者只处理一条消息,直到确认处理完毕,然后再接收下一条。

    具体操作:通过 RabbitMQ 的 basic.qos 设置 prefetch 值为 1,即每个消费者一次只接收一条消息。

    channel.basic_qos(prefetch_count=1);
    优点:可以缓解消费者速度慢导致队列积压的问题,同时保持消息处理顺序。
    缺点:处理并行性有限,多个消费者也只会依次处理消息。

  3. 消息分区(Message Partitioning)
    可以通过根据某种逻辑将消息分区(partitioning)发送到不同的队列,每个队列中的消息由单个消费者处理。这样,消息在同一分区内的顺序可以得到保证。

    举例:如果你在处理订单消息,可以根据订单的 order_id 对消息进行哈希,然后将哈希值映射到不同的队列。这样,相同 order_id 的所有消息会被路由到相同的队列中,并由单个消费者处理,从而保证顺序性。

    优点:能够实现部分并行处理,同时在某些分区内保持顺序。
    缺点:实现起来相对复杂,需要确保分区逻辑合理。跨队列的消息顺序无法保证。

  4. 消息的显式排序(Producer Responsibility)
    有时,可以让消息的生产者在发送消息时显式地标记消息顺序,并在消费者端进行排序。即生产者在每条消息中附加一个序列号,消费者接收消息后按序列号进行排序处理。

    举例:生产者在发送消息时附加 sequence_number,消费者在处理前对消息进行按 sequence_number 排序。
    优点:消息顺序问题交给应用逻辑处理,不受 RabbitMQ 的限制。
    缺点:需要应用在消费者端实现排序逻辑,并且可能引入延迟。

  5. 使用消息确认机制(Acknowledgments and Requeue)
    消费者在处理消息时,如果无法保证消息顺序,可以通过 RabbitMQ 的消息确认机制,即手动确认消息。在这种机制下,消费者处理完消息后再发送 ACK,如果发生处理失败或者乱序,可以通过拒绝(nack)消息并将其重新入队。

    优点:在出现异常时,能够保证消息重新入队并且被正确处理。
    缺点:重新入队可能会导致重复消息处理,并且消息乱序问题还可能持续。

  6. 利用 FIFO 队列的分布式机制
    如果 RabbitMQ 的消息量大且必须要保证全局的消息顺序性,可以通过在应用层实现全局排序机制或使用其他具有 FIFO(先进先出)特性的消息队列,例如 Apache Kafka,它天生支持分区内的顺序性。

    优点:对于需要全局顺序的场景,使用合适的队列工具可以减少 RabbitMQ 的复杂度。
    缺点:这可能意味着需要引入新的技术栈,并且复杂度上升。

小结:
单个队列与单个消费者 是最简单且直接的方式,保证了完全的消息顺序,但不具备高并发性。
设置 prefetch 和 消息分区 可以在保持部分顺序的情况下实现更高的并行处理。
显式排序 和 消息确认机制 则依赖于应用层逻辑,在处理复杂的顺序问题时更加灵活。


  1. Advanced Message Queuing Protocol

    高级消息队列协议 ↩︎

  2. 一条消息或者该队列中所有消息的最大存活时间,如果一条消息设置了TTL属性或者进入了设置TTL属性的队列,那么这条消息如果在TTL设置的时间内没有被消费,则成为死信消息,如果通知配置了队列的TTL和消息的TTL,那么教小的值生效 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值