【Springcloud】RabbitMQ入门

news2024/9/28 19:21:30

文章目录

  • 一、同步通讯与异步通讯
    • 1、同步调用的优缺点
    • 2、异步调用的优缺点
  • 二、RabbitMQ
    • 1、MQ消息队列
    • 2、RabbitMQ的安装
    • 3、RabbitMQ的结构和概念
    • 4、RabbitMQ的消息模型
    • 5、入门案例

一、同步通讯与异步通讯

同步通讯就像打视频,两边可以实时得到相关信息。异步通讯则像发消息,对方什么时候处理你这个消息不确定。

在这里插入图片描述

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

1、同步调用的优缺点

以购物场景为例,用户支付完成后,正常是要调用订单服务更新订单状态,调用仓储服务等。后来还有可能加短信通知、优惠券、积分功能等等

在这里插入图片描述

微服务间基于Feign的调用就属于同步方式。根据上面的示例,微服务之间同步调用存在的问题有:

在这里插入图片描述
总结就是:

同步调用的优点:
- 时效性较强,可以立即得到结果
同步调用的缺点:
- 耦合度高
- 性能和吞吐能力下降
- 有额外的资源消耗
- 有级联失败问题

2、异步调用的优缺点

异步调用常见实现就是事件驱动模式。如下图,和同步调用不一样的时,当用户支付完成,支付服务将信息传递给Broker以后,由Broker去通知后面的订单服务、发送短信服务等来干活儿,这几个服务什么时候干完活儿,支付服务已经不再关心了。

在这里插入图片描述
异步调用的优点有:

优势一:服务解耦

现在再增加模块,则不用再修改支付服务的代码,而只需在新服务中订阅Broker中的事件即可。不关支付服务什么事,解决了服务和服务的耦合问题。

在这里插入图片描述

某一天要砍掉发短信的需求,如果是同步调用,则要去改支付服务的代码,异步下则只需让短信服务取消订阅Broker即可。

优势二:性能提升,吞吐量提高

不同于同步调用,异步模式下,当支付服务将消息成功发送给broker后,即可返回支付成功。总耗时为支付服务自身时间+发送事件的时间

在这里插入图片描述

优势三:服务没有强依赖,不担心级联失败问题

异步调用下,假设后面某个服务挂了,前面的支付服务也不受影响,因为二者之间没有调用关系,做到了故障隔离。挂了的服务重启后再去Broker拿消息就是了

在这里插入图片描述

优势四:流量削峰

当大量用户请求服务时,Broker就像一个拦在洪水前的大坝,保护着后面的服务不受影响,这些服务仍然按照它们的并发能力从Broker中拿消息并处理请求即可。

在这里插入图片描述

异步通信的优点:

  • 耦合度低
  • 吞吐量提升
  • 故障隔离
  • 流量削峰

异步通信的缺点:

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

最后,实际开发中,到底是同步调用还是异步调用,看具体需要什么,需要信息的时效性,则同步调用,需要的是高并发,则异步调用。

二、RabbitMQ

1、MQ消息队列

上面实现微服务的异步调用,中间最关键的就是Broker。而MQ就是对它的一种实现和落地。

MQ (MessageQueue),中文是消息队列,简单说就是存放消息的队列。

而消息队列的实现产品,主流的有以下四种:

在这里插入图片描述

2、RabbitMQ的安装

RabbitMQ是基于Erlang语言开发的开源消息通信中间件,官网地址:https://www.rabbitmq.com/

在这里插入图片描述
接下来使用docker部署RabbitMQ:

# 拉取镜像
docker pull rabbitmq:3-management
# 或者使用tar镜像包,docker load -i也行
docker run \
  -e RABBITMQ_DEFAULT_USER=root  \
  -e RABBITMQ_DEFAULT_PASS=root123  \
  --name mq  \
  --hostname mql  \
  -p 15672:15672  \
  -p 5672:5672  \
  -d \
  rabbitmq:3-management

–hostname主机名,不做集群部署的话加不加都行。开放的两个端口中,15672是Rabbit MQ的一个可视化管理页面端口,5672是做消息通信的一个端口。

访问虚拟机IP:15672进入控制台

在这里插入图片描述

3、RabbitMQ的结构和概念

在这里插入图片描述

  • publisher:生产者
  • consumer:消费者
  • exchange:交换机,负责将消息路由到队列
  • queue:队列,存储消息
  • virtualHost:虚拟主机,隔离不同租户的exchange、queue、消息的隔离。每个用户应该有一个自己的虚拟主机

4、RabbitMQ的消息模型

RabbitMQ有五种常见的消息模型。可分为这三大类:

➢ 基本消息队列(BasicQueue)

在这里插入图片描述
➢ 工作消息队列(WorkQueue)

在这里插入图片描述
➢ 发布订阅(Publish、Subscribe),又根据交换机类型不同分为三种:

  • Fanout Exchange:广播
    在这里插入图片描述
  • Direct Exchange:路由
    在这里插入图片描述
  • Topic Exchange:主题
    在这里插入图片描述

5、入门案例

接下来以最简单的基本消息队列来做一个演示:

在这里插入图片描述

这里有三个角色:

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

接下来打开一个demo工程:

在这里插入图片描述
其中:

  • mq-demo:父工程,管理项目依赖
  • publisher:消息的发送者
  • consumer:消息的消费者
publisher部分主要为:
- 建立连接
- 创建Channel
- 声明队列
- 发送消息
- 关闭连接和channel

测试代码如下:

public class PublisherTest {
    @Test
    public void testSendMessage() throws IOException, TimeoutException {
        // 1.创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        // 设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
        factory.setHost("192.168.150.101");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("root");
        factory.setPassword("root123");
        // 2.建立连接
        Connection connection = factory.newConnection();

        // 3.创建通道Channel
        Channel channel = connection.createChannel();

        // 4.创建队列
        String queueName = "simple.queue";
        channel.queueDeclare(queueName, false, false, false, null);

        // 5.发送消息
        String message = "hello, rabbitmq!";
        channel.basicPublish("", queueName, null, message.getBytes());
        System.out.println("发送消息成功:【" + message + "】");

        // 6.关闭通道和连接
        channel.close();
        connection.close();

    }
}

此时,查看控制台,可以看到消息发送成功。到此,发送消息的微服务任务已经完成,解耦合的!

在这里插入图片描述

consumer部分主要为:
- 建立连接
- 创建Channel
- 声明队列
- 订阅消息

测试代码为:

public class ConsumerTest {

    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.创建建立连接
        ConnectionFactory factory = new ConnectionFactory();
        // 设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
        factory.setHost("192.168.150.101");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("root");
        factory.setPassword("root123");
        // 2.建立连接
        Connection connection = factory.newConnection();

        // 3.创建通道Channel
        Channel channel = connection.createChannel();

        // 4.创建队列
        String queueName = "simple.queue";
        channel.queueDeclare(queueName, false, false, false, null);

        // 5.订阅消息
        channel.basicConsume(queueName, true, new DefaultConsumer(channel){   //内部类
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body) throws IOException {
                
                // 6.处理消息
                String message = new String(body);  //字节再转成字符串
                System.out.println("接收到消息:【" + message + "】");  //这里写拿到消息后要做的事
            }
        });
        System.out.println("等待接收消息。。。。");
    }
}

此时消息队列中数据没有了:

在这里插入图片描述

为什么生产者创建了队列,但在消费者中还要创建?


因为生产者和消费者所在的服务谁先启动不一定,不在消费者中创建一次的话。如果消费者先启动,则找不到队列。而如果生产者先启动,此时哪怕消费者用有创建队列的代码,也不会去重复创建。

总结:

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

➢ 建立connection
➢ 创建channel
➢ 利用channel声明队列
➢ 利用channel向队列发送消息

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

➢ 建立connection
➢ 创建channel
➢ 利用channel声明队列
➢ 定义consumer的消费行为handleDelivery()
➢ 利用channel将消费者与队列绑定

生产者发消息不用等待消费者,消费者处理消息也不用等待生产者。consumer要定义消费行为,也就是一个回调函数handleDelivery() 。利用通道将消费者和队列绑定后,将来一旦有消息,就会投递给这个回调函数去执行。

在这里插入图片描述
订阅消息也就是把队列和回调函数绑定一下。绑定完成后继续执行,等有消息投递进来了,再回调这个函数来处理。回调函数里写的则是处理消息的逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/586831.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

打开复制过去的virtualbox文件之后,在打开时出现只有logs文件的解决方法

文章目录 前言 问题一 打开方式 注意事项 问题二 解决方法 总结 前言 打开复制过去的virtualbox文件之后,在打开时出现只有logs文件的解决方法 问题一 virtualbox虚拟机拷贝到其他电脑上面如何打开? 打开方式 将 VirtualBox 虚拟机拷贝到其他…

第三章 JVM内存概述

附录:精选面试题 Q:为什么虚拟机必须保证一个类的Clinit( )方法在多线程的情况下被同步加锁 ? A: 因为虚拟机在加载完一个类之后直接把这个类放到本地内存的方法区(也叫原空间)中了,当其他程序再来调这个类…

vue2.0中使用summernote富文本编辑器, 并实现上传图片至七牛

vue2.0中使用summernote富文本编辑器, 并实现上传图片至七牛 ackage.json 文件中添加所需的依赖库,然后执行 npm install 安装这些库 2. 在 src / main.js 文件中导入下列库文件 3. 由于summernote 使用 jQuery 库, 我们在组件里需要导入 jQuery才能使用, 为了方便起见,我们在 …

《深入理解计算机系统(CSAPP)》第7章 链接 - 学习笔记

写在前面的话:此系列文章为笔者学习CSAPP时的个人笔记,分享出来与大家学习交流,目录大体与《深入理解计算机系统》书本一致。因是初次预习时写的笔记,在复习回看时发现部分内容存在一些小问题,因时间紧张来不及再次整理…

chatgpt赋能python:Python中安装nio和ngl

Python中安装nio和ngl 介绍 nio和ngl是Python中用于网络编程和HTTP协议的模块。它们可以帮助开发人员快速地创建网络应用程序和RESTful API。 nio扩展了Python的Socket模块,并提供了一组高级的网络编程接口,比如异步IO和事件驱动编程。ngl则提供了一组…

就业内推 | 国企、运营商有岗,CCNP以上

01 中电鸿信信息科技有限公司 🔷招聘岗位:网络工程师 🔷职责描述: 1.主要负责云网类项目的网络方案规划、评审、集成交付及参照相关集成标准对硬件集成商交付的资源池基础网络进行验收; 2.完成公司交办的其他工作&am…

chatgpt赋能python:Python中如何根据值提取键

Python中如何根据值提取键 在编程中,我们经常需要在Python中查找一个字典中的值,然后返回它的键。这种操作在各种应用程序中经常被使用,例如数据库,社交媒体应用程序或者网上商店。 在Python中,这个过程非常简单&…

chatgpt赋能python:Python中如何优雅地分行

Python中如何优雅地分行 Python是一门优雅而又简洁的编程语言,它没有繁琐的语法规则和冗余的表达式。然而,随着程序规模的增大,代码行数也随之增多。为了使代码更加易读和易维护,良好的代码分行是必不可少的。 在Python中&#…

Python安全和防护:如何保护Python应用程序和用户数据的安全

章节一:引言 在当今数字化时代,数据安全是一个极其重要的话题。随着Python的广泛应用和越来越多的人使用Python构建应用程序,保护Python应用程序和用户数据的安全变得尤为重要。本文将介绍一些关键的Python安全问题,并提供一些保…

如何提高AI绘画的出图质量?

先上几张本人随便跑的图,虽说算不上多惊艳,但也是什么都不设置达不到的效果。文末附上本人常用的一些优质大模型。 本人不喜欢细枝末节讲一堆,以下只说重点,如果有一些名词及操作不明白,可以去查对应资料(应…

移动端布局之流式布局1(百分比布局)

移动端布局之流式布局1 流式布局(百分比布局)基础案例:京东移动端首页搭建相关文件夹结构设置视口标签以及引入初始化样式normalize.css引入我们的css初始化文件与首页css body设置index.css app布局和app内容填充index.htmlindex.css 搜索模…

python+django+vue协同过滤算法的电影推荐评分系统nzf73

用户:登录,注册,修改密码,修改个人信息,电影搜索,电影评分,电影评论, 推荐:个性化推荐电影(协同过滤),热门推荐 管理员:用户管理,电影管理,评论管理 电影是本…

chatgpt赋能python:Python中同一个类中方法互相调用的意义

Python中同一个类中方法互相调用的意义 在Python中,类是一个非常重要的编程概念。类是由属性和方法组成的,其中方法是类中非常重要的部分。在类中的方法中,有时候我们需要调用其他方法。在本文中,我们将讨论Python中同一个类中方…

Leetcode11 盛最多水的容器

Leetcode11 盛最多水的容器 来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/container-with-most-water/description 博主Github:https://github.com/GDUT-Rp/LeetCode 题目: 给定一个长度为 n…

科技创新盛典:全国科技者工作日激荡创新思维

⭐ 全国科技工作者日的由来⭐ 全国科技工作者日LOGO⭐ 科技工作者界定⭐ 历年主题⭐ 2023年全国科技工作者日 今天我要和大家分享一个令人激动和振奋的消息——全国科技者工作日!这是一个特殊的日子,为我们所有投身于科技创新的人们而设立,让…

Linux更改SSH端口,并解决SSHD服务重启失败的问题

环境:Linux Centos 7 1.进入sshd配置文件:vi /etc/ssh/sshd_config 2、找到“#Port 22”这行,删掉注释符#,将端口改为(想要变成的端口号 如:2022): 3.重启sshd服务: sy…

【C++】程序的内存模型 - 内存四区代码区,全局区,栈区,堆区,new运算符

文章目录 1. 程序运行前1.1 代码区1.2 全局区 2. 程序运行后2.1 栈区2.2 堆区 3. new运算符 本阶段开始主要针对C面向对象编程技术,探讨C中的核心和精髓。 C程序在执行时,将内存大方向划分为4个区域: 代码区:存放函数体的二进制…

chatgpt赋能python:Python中拼接字符串的最佳方法

Python中拼接字符串的最佳方法 在Python编程中,拼接字符串是一个非常常见的任务。无论是将多个字符串连接成一个字符串,还是将变量值插入到字符串中,我们都需要拼接字符串。本文将介绍Python中拼接字符串的几种方法,并为你推荐最…

Vue登录界面精美模板分享

文章目录 🐒个人主页🏅Vue项目常用组件模板仓库📖前言:🎀源码如下: 🐒个人主页 🏅Vue项目常用组件模板仓库 📖前言: 本篇博客主要提供vue组件之登陆组件源码…

车辆CAN信号,依据DBC文件解析流程

CAN信号解析流程 1.车辆CAN对应dbc文件 DBC文件是一种用于描述CAN(Controller Area Network)数据通信协议的文件格式,DBC文件中包含了CAN数据的信号定义、编码方式、单位、范围等信息,可以用于解析和生成CAN数据帧。 一个DBC文件…