RabbitMQ入门小结

2022-11-07 13:34:37 浏览数 (1)

目录

1.初识MQ

1.1.同步和异步通讯

1.1.1 同步调用的问题

1.1.2 异步通讯

1.2 什么是MQ

2、RabbitMQ快速入门

2.1 安装RabbitMQ

2.1.1 单机部署

2.2 RabbitMQ的结构和概念

2.2 常见消息模型

2.3 入门案例

2.3.1 导入demo工程

2.3.2 publisher

2.3.3 consumer

2.4 总结


1.初识MQ

1.1.同步和异步通讯

微服务间通讯有同步和异步两种方式: 同步通讯:就像打电话,需要实时响应。 异步通讯:就像发微信,你给别人发了条消息,别人可能没看到,也可能压根不想理你, 难么你就收不到消息,如果她哪天给你回复了,你就收到了。这种通讯时效性不太好,你不能立即得到回复

既然异步通讯这么差,为什么还要用这种,那是因为它有自己的一些长处,同步通讯,像打电话,你正在跟一个妹子打电话,现在又有两个妹子给你打来电话,抱歉打不通,因为你只能同一时刻和一个妹子聊天。

但是微信聊天不一样啊,你发消息,不管是2个妹子还是3个妹子你都可以同时聊,所以异步通讯就是时间管理大师的必备技能啊。

小结:

两种方式各有优劣,打电话可以立即得到响应,但是你却不能跟多个人同时通话。发送微信可以同时与多个人收发信息,但是往往响应会有延迟。

1.1.1 同步调用的问题

微服务间基于Feign的调用就属于同步方式,存在一些问题。

小结:

同步调用的优点:

  • 时效性较强,可以立即得到结果

同步调用的问题:

  • 耦合度高
  • 性能和吞吐能力下降
  • 有额外的资源消耗
  • 有级联失败问题

1.1.2 异步通讯

异步调用则可以避免上述问题:

异步调用常见实现就是事件驱动模式,什么是事件驱动呢?我们看一个案例。

用户支付时,肯定会调用我们的支付服务,而我们的支付服务完成支付以后,就需要订单服务,仓储服务,短信服务各自完成自己的业务。

但是我们是事件驱动模式,不能由支付服务来调用这三个服务,那怎么办呢?所以引入了一个东西叫做Broker(事件代理者)。

 什么是事件代理?代理什么事件?在我们这个业务当中,一旦有人支付成功就是一个事件,那么这个事件将来自然就交给了我们的broker 去管理,那订单服务仓储服务和短信服务就会去找broker 呀,说大哥将来真有人支付了,你得通知我们一下啊,这就叫做事件订阅。

  那好了,一旦完成订阅,将来支付服务发现有人支付成功发布一个事件出去说,我这有人支付了订单是1001。

 那broker 就会拿起大喇叭通知这三个服务订单支付了。

这三个服务就去完成各自任务。、

在事件模式中,支付服务是事件发布者(publisher),在支付完成后只需要发布一个支付成功的事件(event),事件中带上订单id。

订单服务和物流服务是事件订阅者(Consumer),订阅支付成功的事件,监听到事件后完成自己业务即可。

为了解除事件发布者与订阅者之间的耦合,两者并不是直接通信,而是有一个中间人(Broker)。发布者发布事件到Broker,不关心谁来订阅事件。订阅者从Broker订阅事件,不关心谁发来的消息。

Broker 是一个像数据 总线一样的东西,所有的服务要接收数据和发送数据都发到这个总线上,这个总线就像协议一样,让服务间的通讯变得标准和可控。

小结 好处:

  • 吞吐量提升:无需等待订阅者处理完成,响应更快速
  • 故障隔离:服务没有直接调用,不存在级联失败问题
  • 调用间没有阻塞,不会造成无效的资源占用
  • 耦合度极低,每个服务都可以灵活插拔,可替换
  • 流量削峰:不管发布事件的流量波动多大,都由Broker接收,订阅者可以按照自己的速度去处理事件

缺点:

  • 架构复杂了,业务没有明显的流程线,不好管理
  • 需要依赖于Broker的可靠、安全、性能

1.2 什么是MQ

MQ (MessageQueue),中文是消息队列,字面来看就是存放消息的队列。也就是事件驱动架构中的Broker。

比较常见的MQ实现:

  • ActiveMQ
  • RabbitMQ
  • RocketMQ
  • Kafka

几种常见MQ的对比:

追求可用性:Kafka、 RocketMQ 、RabbitMQ

追求可靠性:RabbitMQ、RocketMQ

追求吞吐能力:RocketMQ、Kafka

追求消息低延迟:RabbitMQ、Kafka

2、RabbitMQ快速入门

RabbitMQ概述 RabbitMQ是基于Erlang语言开发的开源消息通信中间件,官网地址:Messaging that just works — RabbitMQ

2.1 安装RabbitMQ

2.1.1 单机部署

1、下载镜像

代码语言:javascript复制
docker pull rabbitmq:3-management

2、安装MQ

代码语言:javascript复制
docker run 
 -e RABBITMQ_DEFAULT_USER=jie 
 -e RABBITMQ_DEFAULT_PASS=123456 
 --name mq 
 --hostname mq1 
 -p 15672:15672 
 -p 5672:5672 
 -d 
 rabbitmq:3-management

命令解读 -e RABBITMQ_DEFAULT_USER:环境变量,用户名 -e RABBITMQ_DEFAULT_PASS:环境变量,密码 -- name:起个名字 --hostname:主机名 -p:端口映射,第一个是管理平台的端口,第二个是消息通信端口 -d:后台运行 rabbitmq:镜像名称

3、浏览器访问(如果防火墙未关闭,记得开启端口号)

2.2 RabbitMQ的结构和概念

RabbitMQ中的几个概念: Channels:操作MQ的工具 ​ Exchanges:路由消息到队列中 ​ Queues:缓存消息 ​ virtual host:虚拟主机,是对queue、exchange等资源的逻辑分组

RabbitMQ中的一些角色:

  • publisher:生产者
  • consumer:消费者
  • exchange个:交换机,负责消息路由
  • queue:队列,存储消息
  • virtualHost:虚拟主机,隔离不同租户的exchange、queue、消息的隔离

2.2 常见消息模型

MQ的官方文档中给出了5个MQ的Demo示例 RabbitMQ Tutorials — RabbitMQ ,对应了几种不同的用法:

2.3 入门案例

简单队列模式的模型图:

官方的HelloWorld是基于最基础的消息队列模型来实现的,只包括三个角色:

  • publisher:消息发布者,将消息发送到队列queue
  • queue:消息队列,负责接受并缓存消息
  • consumer:订阅队列,处理队列中的消息

2.3.1 导入demo工程

码云提供了一个Demo工程,mq-demo:

mq-demo: CSDN案例

导入后可以看到结构如下:

包括三部分:

  • mq-demo:父工程,管理项目依赖
  • publisher:消息的发送者
  • consumer:消息的消费者

2.3.2 publisher

我们进入 PublisherTest,在ConnectionFactory factory = new ConnectionFactory();打一个断点,用Debug运行,进入断点。

1、在这里我们要做的第一件是就是创建ConnectionFactory(连接工厂),你要向MQ发送消息,就要建立连接,而建立连接就要用到连接工厂。

 2、 创建好连接工厂,设置地址信息,就是MQ的地址信息。记得改成你的IP地址。还有端口号、主机名、vhost、用户名、密码

 3、到这,连接工厂准备好了,参数也准备好了,接下来就是建立连接了

 这行代码走完,我们回到浏览器看一眼。

发现这里建立起连接了,说明有一个人已经连上来了,谁呢?就是我们的代码

已经成功的连上来了,我们回到代码区。

 这行代码就是在创建我们的代码通道,我们往下走,通道已经创建,我们去浏览器看一下。

通道有了,就可以基于通道向队列当中发送消息了。

4、创建队列

 我们再看看浏览器。

这样子就完成了队列的创建,有了队列,下一步生产者就可以向队列发送消息了。

5、发送消息

  6、关闭通道和连接

 我们回到浏览器看看

我们就会发现里面有一条消息了,我们点击Name进去看看。

点击Get messages ,我们可以看一下消息。

我们在第六步的时候,已经关闭通道和连接了,那我们的发送者已经结束了,连接都断开了,也就是说,我发完了,我的事也就没了,我不用管谁收到了没有,这就是解除耦合。

那谁来结束呢?消费者,consumer。

2.3.3 consumer

我们进入 ConsumerTest,ConsumerTest的代码跟PublisherTest非常的像,在ConnectionFactory factory = new ConnectionFactory();打一个断点,用Debug运行,进入断点。

前面的操作都是一样的,我们直接看创建队列。

为什么又要创建一次队列?PublisherTest不是已经创建过了嘛。

这是因为生产者和消费者和消费者的启动顺序是不确定的,万一是消费者先启动了,

我想来找这个队列不存在怎么办?所以为了避免这个问题的发生,所以生产者和消费者都要各自去创建队列。

那么我们再执行这个代码它会不会再生成一个队列呢?我们去浏览器看一下。

答案是没有,我们这个代码重复执行不要紧,这是一个保险措施。

往下走。

 basicConsume(消费),消费一条消息,这里采用了一个匿名内部类的方法,里面还重写了一个方法handleDelivery,顾名思义,处理头例的消息。利用channel将消费者与队列绑定,我们再往下走。

 控制台就打印了生产者发送的消息,我们再看浏览器。

发现这块的消息也没了,也就是说,一旦消费,消息会立即删除。

2.4 总结

基本消息队列的消息发送流程:

  1. 建立connection
  2. 创建channel
  3. 利用channel声明队列
  4. 利用channel向队列发送消息

基本消息队列的消息接收流程:

  1. 建立connection
  2. 创建channel
  3. 利用channel声明队列
  4. 定义consumer的消费行为handleDelivery()
  5. 利用channel将消费者与队列绑定

0 人点赞