RabbitMQ最全教程-Part1(基础使用)

一、消息队列基本概念

消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构

1、消息队列的特点

可靠性

消息持久化: 消息可以被持久化存储,即使消费者暂时不可用,消息也不会丢失。
**确认机制:**消费者成功处理消息后可以发送确认,确保消息被正确处理。如果处理失败,消息可以被重新发送或回滚。

负载均衡

多消费者: 多个消费者可以竞争消费同一个队列中的消息,实现负载均衡。
**高并发:**通过增加消费者数量,可以提高系统的处理能力和吞吐量。

扩展性

水平扩展: 可以通过增加更多的生产者和消费者来扩展系统的处理能力。
**垂直扩展:**可以通过增加服务器资源来提升单个节点的处理能力。

消息排序

顺序消息: 某些消息队列支持消息的有序性,确保消息按照发送的顺序被消费。
**优先级:**可以设置消息的优先级,确保高优先级的消息优先被处理。

2、消息队列的通讯模式

点对点通讯模式

在这种模式下,消息生产者发送的消息会被存储在一个特定的消息队列中,然后由一个或多个消息消费者从该队列中接收消息

发布订阅模式

Pub/Sub 模式允许消息的发送者(发布者)和接收者(订阅者)之间松散耦合,使得多个订阅者可以同时接收相同的消息,消息生产者发布消息到指定Topic,由订阅这个Topic的消费者进行消费

两种模式的比较

请求/回复(Request/Reply)模式

客户端发送请求消息,并等待服务端的回复。服务端将回复消息发送到一个临时队列中,客户端从该队列中获取回复。

延迟消息模式

消息被存储在延时队列中,直到达到指定的时间点才被发送。

广播模式

消息可以被发送到多个队列或主题,每个队列或主题的消费者都会收到消息。

死信队列模式

无法被正常处理的消息会被转移到一个专门的死信队列中。可以对死信队列中的消息进行单独处理,如重试、记录日志等。

3、为什么要使用消息队列

这里列举几种常见应用场景

1)异步处理

举个例子,当用户下单后,将会面临一系列服务调用的流程,比如库存检查、支付处理等,但是这些后续的服务调用都是后台默默做,并不直接影响用户下单这个行为,所以我们可以将这些服务调用变成异步处理,处理完了有结果通知反馈一下就行。

这个异步处理我们可以借助MQ,具体做法:订单系统将订单信息发送到消息队列,后台系统监听到MQ有任务通知,则执行异步处理订单,如库存检查、支付处理、物流安排等。

2)流量削峰

就像用户投递快递,高峰到40W每秒,但是我们的后续处理业务每秒只能20W,还剩下20W在MQ进行堆积,这就是MQ很重要的流量削峰的能力,将用户的洪峰流量,让后台慢慢来处理,MQ承担一个缓冲的作用

比如可以这样做,用户的请求,服务器收到之后,首先写入消息队列进行排队等候真正的服务被执行,但是当加入消息队列长度超过最大值,则直接抛弃用户请求或跳转到错误页面.(这里可以做熔断降级)

3)系统解耦

我们可以看到,如果没加MQ,则一系列调用都是一条完整的同步调用链,某一个服务执行的失败会影响前后的服务。

但是我们通过MQ,可以将后续多个服务单独执行,互不影响,如果有依赖关系,某一个服务执行失败了,我们可以进行一些补偿、回滚机制等

4)实时通知

对于需要实时更新的数据,生产者将更新后的数据发布到Topic上,只要订阅了这个Topic的服务都能够收到这个实时更新的推送,进而做一些实时性的后续处理。

4、消息队列有什么缺点

最直观的就是增加了系统的复杂性,引入了第三方中间件

还有就是增加了网络开销,因为消息的传递是会消耗网络带宽资源的,并且也会带来一定的网络延迟

还有系统可用性降低,因为当MQ宕机了,那么我们有些依赖于MQ进行通信的两两服务之间就失联了

还有一个数据一致性问题,如下图所示,系统需要保证快递投递,扣减系统费,通知等之间的数据一致性,如果系统短信通知,快递通知执行成功,扣减系统费执行失败时,就会出现数据不一致问题

5、各类消息队列的比较

特性 ActiveMQ RabbitMQ Kafka RocketMQ
生产者-消费者模式 支持 支持 支持 支持
发布-订阅模式 支持 支持 支持 支持
REQUEST-REPLY模式 支持 支持 - 支持
API完备性 低(静态配置)
多语言支持 支持,JAVA优先 语言无关 支持,JAVA优先 支持
单机呑吐量 万级 万级 十万级 单机万级
消息延迟 毫秒级 微秒级 毫秒级 毫秒级
可用性 高(主从) 高(主从) 很高(分布式) 非常高(分布式)
消息丢失 - 理论上不会丢失 理论上不会丢失
消息重复 - 可控制 理论上会有重复 允许重复
文档的完备性
提供快速入门
首次部署难度 -

注: - 表示尚未查找到准确数据

二、RabbitMQ的基本使用

1、RabbitMQ的一些基本概念、名词解释

Publisher

消息生产者,就是投递消息的程序

发布者 (或称为生产者) 负责生产消息并将其投递到指定的交换器上。

Message

消息由消息头和消息体组成,消息头用于存储与消息相关的元数据:如目标交换器的名字 (exchange_name 指明消息发给哪一个交换器)路由键 (RountingKey)和其他可选配置 (properties) 信息。消息体为实际需要传递的数据。

Exchange

交换器负责接收来自生产者的消息,并将消息路由到一个或者多个队列中,如果路由不到,则返回给生产者或者直接丢弃,这取决于交换器的 mandatory 属性:

当 mandatory 为 true 时:如果交换器无法根据自身类型和路由键找到一个符合条件的队列,则会将该消息返回给生产者;

当 mandatory 为 false 时:如果交换器无法根据自身类型和路由键找到一个符合条件的队列,则会直接丢弃该消息。

BindingKey

交换器与队列通过 BindingKey 建立绑定关系。 (理解为@RequesMapping,定义了路由跳转)

Routingkey

基于交换器类型的规则相匹配时,消息被路由到对应的队列中

生产者将消息发给交换器的时候,一般会指定一个 RountingKey,用来指定这个消息的路由规则,当 RountingKey 与 BindingKey相匹配时,消息被路由到对应的队列中。

(理解为写的/order/findById 定义了url)

Queue

消息队列载体,每个消息都会被投入到一个或多个队列。

用于存储路由过来的消息,多个消费者可以订阅同一个消息队列,此时队列会将收到的消息将以轮询的方式分发给所有消费者,即每条消息只会发送给一个消费者,不会出现一条消息被多个消费者重复消费的情况。

Consumer

消息消费者,就是接受消息的程序

消费者订阅感兴趣的队列,并负责消费存储在队列中的消息。为了保证消息能够从队列可靠地到达消费者,RabbitMQ 提供了消息确认机制 (messageacknowledgement),并通过 autoAck 参数来进行控制

当 autoAck 为 true 时:此时消息发送出去 (写入TCP套接字) 后就认为消费成功,而不管消费者是否真正消费到这些消息。当 TCP 连接或 channel 因意外而关闭,或者消费者在消费过程之中意外宕机时,对应的消息就丢失。因此这种模式可以提高吞吐量,但会存在数据丢失的风险。

当 autoAck 为 false 时:需要用户在数据处理完成后进行手动确认,只有用户手动确认完成后,RabbitMQ 才认为这条消息已经被成功处理,这可以保证数据的可靠性投递,但会降低系统的吞吐量。

Connection

用于传递消息的 TCP 连接。

Channel

消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。

RabbitMQ 采用类似 NIO (非阻塞式 IO ) 的设计,通过 Channel 来复用 TCP 连接,并确保每个 Channel的隔离性,就像是拥有独立的 Connection 连接。当数据流量不是很大时,采用连接复用技术可以避免创建过多的 TCP 连接而导致昂贵的性能开销。

Virtual Host

虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离

RabbitMQ 通过虚拟主机来实现逻辑分组和资源隔离,一个虚拟主机就是一个小型的 RabbitMQ服务器,拥有独立的队列、交换器和绑定关系。用户可以按照不同业务场景建立不同的虚拟主机,虚拟主机之间是完全独立的,你无法将 vhost1 上的交换器与vhost2 上的队列进行绑定,这可以极大的保证业务之间的隔离性和数据安全,默认的虚拟主机名为 / 。

Broker

简单来说就是消息队列服务器实体。就是指部署MQ的服务器实体

2、docker安装RabbitMQ

拉取RabbitMQ的镜像

bash 复制代码
docker pull rabbitmq:management

运行RabbitMQ

bash 复制代码
docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq rabbitmq:management

访问管理界面

输入 账号:guest 密码:guest

如果访问不了,可以尝试把linux的防火墙关闭试试

3、交换机类型

Direct exchange(直连交换器)

直连交换机是一种带路由功能的交换机,一个队列会和一个交换机绑定(通过binding_key,一个队列与交换机可以有多条binding_key绑定),当消息被发送的时候,需要指定一个routing_key,这个消息被送达交换机的时候,交换机就会拿着routing_key与binding_key相匹配,只要匹配上的都进行发送到相应的queue

当生产者(P)发送消息时 Rotuing key=booking 时,这时候将消息传送给 Exchange,Exchange 获取到生产者发送过来消息后,会根据自身的规则进行与匹配相应的 Queue,这时发现 Queue1 和 Queue2 都符合,就会将消息传送给这两个队列。

如果我们以 Rotuing key=create 和 Rotuing key=confirm 发送消息时,这时消息只会被推送到 Queue2 队列中,其他 Routing Key 的消息将会被丢弃。

Fanout exchange(扇形交换器)

扇型交换机(fanout exchange)将消息路由给绑定到它身上的所有队列,而不理会绑定的路由键。如果 N 个队列绑定到某个扇型交换机上,当有消息发送给此扇型交换机时,交换机会将消息的拷贝分别发送给这所有的 N 个队列。扇型用来交换机处理消息的广播路由(broadcast routing)。

Topic exchange(主题交换器)

直接交换机只能做到routingkey的精确匹配,扇形交换机只能广播到所有queue,那有没有比较折中一点的,可以进行过滤匹配的交换机?主题交换机就是做这个事情的。

对于bindingkey,写匹配的条件:

可以存在两种特殊字符 "*" 与"#",用于做模糊匹配,其中 "*" 用于匹配一个单词,"#"用于匹配多个单词(可以是零个)

对于routingkey,写实际路由:

routing key 为一个句点号 "." 分隔的字符串(我们将被句点号 ". " 分隔开的每一段独立的字符串称为一个单词),如"stock.usd.nyse"、"nyse.vmw"、"quick.orange.rabbit"

当生产者发送消息 Routing Key=F.C.E 的时候,这时候只满足 Queue1,所以会被路由到 Queue 中,如果 Routing Key=A.C.E 这时候会被同是路由到 Queue1 和 Queue2 中,如果 Routing Key=A.F.B 时,这里只会发送一条消息到 Queue2 中。

主题交换机拥有非常广泛的用户案例。无论何时,当一个问题涉及到那些想要有针对性的选择需要接收消息的 多消费者 / 多应用(multiple consumers/applications) 的时候,主题交换机都可以被列入考虑范围。

三、SpringBoot整合RabbitMQ

参考文章

SpringBoot快速整合RabbitMQ实现MQ最基本操作_mq基本操作-CSDN博客

相关推荐
谭震鸿3 小时前
Zookeeper集群搭建Centos环境下
分布式·zookeeper·centos
天冬忘忧8 小时前
Kafka 工作流程解析:从 Broker 工作原理、节点的服役、退役、副本的生成到数据存储与读写优化
大数据·分布式·kafka
IT枫斗者12 小时前
如何解决Java EasyExcel 导出报内存溢出
java·服务器·开发语言·网络·分布式·物联网
求积分不加C12 小时前
Kafka怎么发送JAVA对象并在消费者端解析出JAVA对象--示例
java·分布式·kafka·linq
GDDGHS_13 小时前
“Kafka面试攻略:核心问题与高效回答”
分布式·面试·kafka
bug_null14 小时前
RabbitMQ消息可靠性保证机制4--消费端限流
rabbitmq
꧁薄暮꧂14 小时前
kafka中的数据清理策略
数据库·分布式·kafka
青石路15 小时前
不依赖 Spring,你会如何自实现 RabbitMQ 消息的消费(一)
rabbitmq
hong16168815 小时前
大数据技术Kafka详解:消息队列(Messages Queue)
大数据·分布式·kafka
eternal199516 小时前
优化算法|基于Deep-Q-Network(DQN)的邻域搜索算法求解分布式柔性作业车间调度问题
分布式·算法