安装配置
📌注意Erlang与MQ的版本对应,可在官网版本页查看
- 安装Erlang
- 配置环境变量,复制对应bin路径
安装目录\Erlang OTP\bin
将此路径添加到系统环境变量的PATH字段下,之后保存后,打开命令控制台,输入erl -v查看是否可以正常显示版本号 - 安装RabbitMQ
- 安装结束后进入对应目录的sbin文件夹,在此处打开命令控制台,输入
rabbitmq-plugins enable rabbitmq_management待安装完成,
右键“此电脑”,选择管理,打开windows的服务界面,启动rabbitMQ服务 - 浏览器输入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 | 交换机,接收消息,根据路由键转发消息到绑定的队列 |
| Binding | Exchange和Queue之间的虚拟连接,binding中可以包含routing key |
| Routing key | 一个路由规则,虚拟机可用它来确定如何路由一个特定消息 |
| Queue | 也称作MessageQueue,消息队列,保存消息并将它们转发给消费者 |


死信队列是什么?
死信队列也是一个消息队列,它是用来存放那些没有成功消费的消息的,通常可以用来作为消息重试,如果队列没有配置死信队列,则消息一旦成为“死信”,便会直接丢弃
死信队列并不是什么特殊的队列,只不过是绑定在死信交换机上的队列。死信交换机也不是什么特殊的交换机,只不过是用来接收死信的交换机,所以可以为任何类型(Direct、Fanout、Topic)。一般来说,会为每个业务队列分配一个独有的路由 key,并对应的配置一个死信队列进行监听,也就是说,一般会为 每个重要的业务队列配置一个死信队列
什么情况下消息会进入死信队列?
- 消息被消费者拒绝且告知MQ将该消息放入死信队列
a. 消费者回了一个Nack,而且第三个参数为false,channel.basicNack(deliveryTag, false, false)
b. 消费者回了一个Reject,且第二个参数为false,channel.basicReject(deliveryTag, false) - 消息在队列中的存活时间过期,即消息可以设置TTL2,TTL超时就会被放进死信队列。
- 队列设置了
x-max-length最大消息数量且当前队列中的消息已经达到了这个数量,再次投递,消息将被挤掉,被挤掉的消息会路由进死信队列 - 当重复投递次数达到了设置的消费者设置了自动 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分钟,并为其设置一个死信队列,消息到期后就进入死信队列处理了
如何尽量避免消息丢失?
- 消息发送+回调确认、开启事务
- 开启spring的重试机制(retry)



如何信息消费的幂等性
- 给每条消息确定唯一消息ID
更多做法参考保证接口幂等性
Direct、Fanout、Topic三种交换机的区别
-
Fanout Exchange交换机将会接到的消息路由到每一个与其绑定的队列中去
解释:通俗来讲就是有几个队列跟此交换机绑定,发送消息时就会发送给每一个绑定的队列 -
DirectExchange 会将接收到的信息根据规则路由制定的队列中去,因此也叫做路由模式(routes)
解释:在与此交换机绑定的基础上,根据routingKey的值来选择性的发送消息 -
TopicExchange与DirectExchange类似,区别在于routingKey必须是多个单词列表,并且以
.分割
解释:跟DirectExchange类似,只是还可以使用通配符#或者*来代替String routingkey = “testTopic.#”; // 匹配多个词 String routingkey = “testTopic.*”; // 匹配单个词
如何保证 RabbitMQ 消息的顺序性?
在 RabbitMQ 中,消息的顺序性指的是消息按照它们被发送的顺序,能够按相同顺序被消费者处理。这在某些应用场景中(如交易、日志处理、事件驱动系统)非常重要。但由于 RabbitMQ 是分布式系统,加上并发处理的机制,保证消息的顺序性需要特定的设计和策略。
以下是几种保证 RabbitMQ 消息顺序性的常见方法:
-
单个队列与单个消费者
最简单、最有效的方式是确保消息只通过一个队列传递,并且只有一个消费者在处理该队列的消息。RabbitMQ 保证同一队列中的消息是按发送顺序进行投递的,因此单一消费者处理消息时,消息的处理顺序可以得到保证。优点:简单直接,保证消息按顺序处理。
缺点:当消息量很大时,单个消费者会成为系统瓶颈,无法充分利用并行处理的优势。 -
队列的公平分发 (Prefetch)
如果需要在一个队列上使用多个消费者,为了保证顺序性,你可以通过设置 prefetch 来确保每个消费者在处理完一条消息后,才能接收下一条消息。这种方式可以确保每个消费者只处理一条消息,直到确认处理完毕,然后再接收下一条。具体操作:通过 RabbitMQ 的 basic.qos 设置 prefetch 值为 1,即每个消费者一次只接收一条消息。
channel.basic_qos(prefetch_count=1);
优点:可以缓解消费者速度慢导致队列积压的问题,同时保持消息处理顺序。
缺点:处理并行性有限,多个消费者也只会依次处理消息。 -
消息分区(Message Partitioning)
可以通过根据某种逻辑将消息分区(partitioning)发送到不同的队列,每个队列中的消息由单个消费者处理。这样,消息在同一分区内的顺序可以得到保证。举例:如果你在处理订单消息,可以根据订单的 order_id 对消息进行哈希,然后将哈希值映射到不同的队列。这样,相同 order_id 的所有消息会被路由到相同的队列中,并由单个消费者处理,从而保证顺序性。
优点:能够实现部分并行处理,同时在某些分区内保持顺序。
缺点:实现起来相对复杂,需要确保分区逻辑合理。跨队列的消息顺序无法保证。 -
消息的显式排序(Producer Responsibility)
有时,可以让消息的生产者在发送消息时显式地标记消息顺序,并在消费者端进行排序。即生产者在每条消息中附加一个序列号,消费者接收消息后按序列号进行排序处理。举例:生产者在发送消息时附加 sequence_number,消费者在处理前对消息进行按 sequence_number 排序。
优点:消息顺序问题交给应用逻辑处理,不受 RabbitMQ 的限制。
缺点:需要应用在消费者端实现排序逻辑,并且可能引入延迟。 -
使用消息确认机制(Acknowledgments and Requeue)
消费者在处理消息时,如果无法保证消息顺序,可以通过 RabbitMQ 的消息确认机制,即手动确认消息。在这种机制下,消费者处理完消息后再发送 ACK,如果发生处理失败或者乱序,可以通过拒绝(nack)消息并将其重新入队。优点:在出现异常时,能够保证消息重新入队并且被正确处理。
缺点:重新入队可能会导致重复消息处理,并且消息乱序问题还可能持续。 -
利用 FIFO 队列的分布式机制
如果 RabbitMQ 的消息量大且必须要保证全局的消息顺序性,可以通过在应用层实现全局排序机制或使用其他具有 FIFO(先进先出)特性的消息队列,例如 Apache Kafka,它天生支持分区内的顺序性。优点:对于需要全局顺序的场景,使用合适的队列工具可以减少 RabbitMQ 的复杂度。
缺点:这可能意味着需要引入新的技术栈,并且复杂度上升。
小结:
单个队列与单个消费者 是最简单且直接的方式,保证了完全的消息顺序,但不具备高并发性。
设置 prefetch 和 消息分区 可以在保持部分顺序的情况下实现更高的并行处理。
显式排序 和 消息确认机制 则依赖于应用层逻辑,在处理复杂的顺序问题时更加灵活。
本文介绍了如何安装配置Erlang和RabbitMQ,包括环境变量设置、服务管理,以及RabbitMQ的基础概念,如Server、Connection、Channel、Message、Virtualhost、Exchange、Queue和死信队列的用法。还讨论了消息丢失的避免策略、消息消费幂等性和不同Exchange类型的区别。
452

被折叠的 条评论
为什么被折叠?



