RabbitMQ的介绍和使用
1.同步通讯和异步通讯
举个例子,同步通讯就像是在打电话,因此它时效性较强,可以立即得到结果,但如果你正在和一个MM打电话,其他MM找你的话,你们之间是不能进行消息的传递和响应的
异步通讯就像是微信,你可以和多个MM进行消息的传递,对方可以立即响应或者有空了在”回“你
同步调用问题
微服务间基于Feign的调用就属于同步方式,存在一些问题。
1.代码耦合:如果后续需要添加业务,需要不断修改支付服务的代码
2.性能下降,吞吐量下降:支付服务一直在等待,订单等服务的响应,cpu资源一直在占用。
3.级联失败:如果服务提供者出现问题,所有调用方都会跟着出问题。
2.异步调用方案
异步调用常见的就是事件驱动模式:Broker是事件代理者,一旦用户支付成功,这就是一个事件,这个事件就会被Broker管理,订单服务、仓储服务、短信服务。就会找Broker,这个叫做订阅事件。一旦用户支付成功之后,Broker就会通知被订阅过事件的服务,支付服务完成事件发布之后,就结束了服务,返回给用户
优点:
解决代码解耦:添加业务时不需要再更改支付服务的代码,支付服务只需要发布事件就行。至于后面的业务支付服务可以不用考虑。
性能提升,吞吐量提供:相比较同步服务,业务处理时间的累加,支付服务还需要等待其他服务完成并响应,通过异步的方式,支付服务发布时间之后就结束服务,无需等待其他服务响应。提升了性能,和吞吐量
服务没有依赖关系,不用担心级联失败问题
流量削峰: 有多个事件发布,可以囤积到broker上,订阅该事件的服务可以按自己的处理能力来稳步进行。broker起到缓冲作用
缺点:
依赖Broker的可靠性、安全性、吞吐能力
架构复杂了,业务没有明显的流程线,不好追踪管理
3.什么是MQ
MQ(MessageQueue),中文是消息队列,字面来看就是存放消息的队列。也就是事件驱动架构中的Broker
常见的MQ
RabbitMQ,适用于中小型企业开发,如果对性能要求比较高的并且需要定制服务的大型企业推荐使用Kafka。下面会介绍RabbitMQ的使用。
4.RabbitMQ概述和安装
RabbitMQ概述
RabbitMQ是基于Erlang语言开发的开源消息通信中间件,官网地址:https://www.rabbitmq.com
RabbitMQ的部署
环境:centos7,docker在线拉取的方式部署。
#拉取RabbitMQ镜像
输入:docker pull rabbitmq:3-management
#设置默认用户名密码并启动容器
docker run --name rabbitmq -e RABBITMQ_DEFAULT_USER=root -e RABBITMQ_DEFAULT_PASS=123 -p 15672:15672 -p 5672:5672 -d rabbitmq:3-management
端口15672是rabbitMQ的ui界面,5672是服务端口
ui界面展示:
RabbitMQ结构和概念
PubLisher是我们的消息(事件)发送者,consumer是消息的消费者,PubLisher将来会把消息发送到我们的exchange(交换机)上,交换机负责路由,并把消息投射到queue(队列),queue负责暂存消息,consumer负责从queue里面获取消息处理消息。
5.RabbitMQ的常见消息模型
一、基本消息队列(BasicQueue)
HelloWorld是最基本的消息队列模型,实现的话,包含三个角色
publisher:消息发布者,将消息发送到队列queue
queue:消息队列,负责接受并缓存消息
consumer:订阅队列,处理队列中的消息
官方提供的编码方式非常麻烦,下面我们介绍学习一下SpringAMQP,它可以大大简化我们消息发送和接收API。
SpringAMQP简介
AMQP:是用于在应用程序或之间传递业务消息的开放标准,该协议与语言的平台无关,更符合微服务中独立性的要求。
Spring AMQP:是基于AMQP协议定义的一套API规范,提供了模板来发送和接收消息,包含两部分,其中spring-amqp是基础抽象,spring-rabbit是底层的默认实现。
利用SpringAMQP实现基础消息队列功能
通过rabbitTemplate提供的convertAndSend就可以实现消息的发送。
引入相关依赖
<dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit</artifactId><scope>test</scope>
</dependency>
publisher(消息发布者)的application.yml的配置
test的测试代码:
@RunWith(SpringRunner.class)
@SpringBootTest
class PublisherApplicationTests {@Autowiredprivate RabbitTemplate rabbitTemplate;@Testvoid contextLoads() {String queuename="simple queue";String message="hello,spring AMQP";rabbitTemplate.convertAndSend(queuename,message);}}
通过rabbitTemplate实现对队列消息的监听
引入依赖
<dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit</artifactId><scope>test</scope>
</dependency>
配置consumer(消息接收者),的application.yml文件
spring:rabbitmq:host: 192.168.10.8 #主机名port: 5672 #端口username: root #用户名password: 123 #密码virtual-host: / #虚拟主机名
监听类的代码
@Component
public class SimpleListener {@RabbitListener(queues = "simple queue")public void ListenSimpleQueue(String msg){System.out.println("消费者接收到simple queue的消息:"+msg);}
}
ps:消息一旦消费就会从队列中删除,RabbitMQ没有消息回溯功能。
二、工作消息队列(WorkQueue)
工作队列的结构如下:
工作消息队列的结构,相比于基础消息队列多了个消费者,因为rabbitMQ阅后即焚的特性这两个消费者属于共同工作的关系,如果有50个消息,他们两个消费者就会一人分一半,也就是一人25条,为啥会多一个消费者?这是因为如果一个消费者每次处理40个消息,但是publisher一次发布50个消息,多出来的消息会存储在queue里面,又因为queue是占用内存的假以时日,内存就会爆满,新的消息就存不进去了,多一个消费者每次就可以处理80条消息,可以有效解决这个问题。
work queue,工作队列,可以提高消费处理速度,避免队列消息堆积。但是这里有一个消息预取机制 ,消费者会提前把消息拿过来,因此消息是平局分配,并不是“能者多劳”的模式,通过设置prefetch的值来实现每次只能获取一条消息,处理完成才能接取下一个消息。实现“能者多劳”的模式。
- 发布订阅(Publish、Subscribe)
基础消息队列和工作消息队列都是一条信息只被一个消费者消费,消费完就删除,显然不能实现我们之前预想的完成支付之后,通知仓储、短信等服务。这就需要我们了解学习发布订阅模式。发布订阅模式与之前案例的区别就是允许同一消息发送给多个消费者,实现方式是加入exchange(交换机),结构如下:
publisher将消息发送给exchange(交换机),交换机把这个消息转发给队列,因此,发布者(publisher)并不需要知到转发给了那个 队列或多个队列,转发给多个队列,这种方式就能实现被多个消费者消费,那么交换机到底是发给一个还是多个呢?这是由交换机类型来决定的。常见的exchange的类型包括:
广播:Fanout
路由:Direct
主题:Topic
注意: exchange负责消息路由,而不是储存,路由失败则消息丢失。
广播-Fanout Exchange
Fanout Exchange 会将接收到的消息路由到每一个绑定的queue。
实现思路:
1.在consumer服务中,利用代码声明队列、交换机、并将两者绑定。
在consumer服务上添加@Configuration注解,并声明FanoutExchange、Queue和关系对象Binding,代码如下:
@Configuration
public class FanoutConfig {//声明交换机对象@Beanpublic FanoutExchange fanoutExchange(){return new FanoutExchange("fanout");}//声明队列1@Beanpublic Queue fanoutqueue1(){return new Queue("fanoutqueue1");}//绑定队列一到交换机@Beanpublic Binding fanoutBinding1(Queue fanoutqueue1,FanoutExchange fanoutExchange){return BindingBuilder.bind(fanoutqueue1).to(fanoutExchange);}//声明队列2@Beanpublic Queue fanoutqueue2(){return new Queue("fanoutqueue2");}//绑定队列二到交换机@Beanpublic Binding fanoutBinding2(Queue fanoutqueue2,FanoutExchange fanoutExchange){return BindingBuilder.bind(fanoutqueue2).to(fanoutExchange);}
}
2.在consumer服务中,编写两个消费者方法,分别监听fanout.queue1和fanout.queue2
@RabbitListener(queues = "fanoutqueue1")
public void ListenSimpleQueue3(String msg) throws InterruptedException {System.out.println("消费者222接收到fanoutqueue1的消息:"+msg);Thread.sleep(100);
}
@RabbitListener(queues = "fanoutqueue2")
public void ListenSimpleQueue4(String msg) throws InterruptedException {System.out.println("消费者222接收到fanoutqueue2的消息:"+msg);Thread.sleep(100);
}
3.在publisher中编写测试方法,向fanout发送消息。
@Test
public void contectFonoutExchange()
{//交换机名称String exchangeName="fanout";//消息内容String message="hello everyone";//发送消息rabbitTemplate.convertAndSend(exchangeName,"",message);
}
路由-DirectExchange
Direct Exchange 会将接收到的消息根据规则路由到指定的Queue,因此称为路由模式(routes)
每一个Queue都与Exchange设置一个BindingKey,一个队列可以绑定多个BindingKey。
发布者发送消息时,指定消息的RoutingKey
Exchange(交换机)将消息路由到Bindingkey与消息RoutingKey一致的队列
实现思路:
1.利用@RabbitListenner声明Exchange、Queue、RountingKey
2.在consumer服务中编写两个消费者方法,分别监听queue1和queue2
在我们的监听类里面增加两个方法,用来声明交换机、队列和RountingKey
//发布订阅DirectExchange
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "queue1"),exchange = @Exchange(name = "direct",type= ExchangeTypes.DIRECT),key = {"red","blue"}
))
public void listenerDirectqueue1(String msg)
{System.out.println("消费者接收到direct.queue1的消息"+msg);
}@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "queue2"),exchange = @Exchange(name = "direct",type= ExchangeTypes.DIRECT),key = {"red","yellow"}
))
public void listenerDirectqueue2(String msg)
{System.out.println("消费者接收到direct.queue2的消息"+msg);
}
3.在publisher中编写测试方法,向Exchange发送消息。
@Test
public void contextDirectExchange()
{String exchangeName="direct";String msgblue="hello blue";String msgRed="hello red";String msgYellow="hello yellow";rabbitTemplate.convertAndSend(exchangeName,"blue",msgblue);
}
@Test
public void contextDirectExchange()
{String exchangeName="direct";String msgblue="hello blue";String msgRed="hello red";String msgYellow="hello yellow";rabbitTemplate.convertAndSend(exchangeName,"red",msgRed);
}
话题-TopicExchange
TopicExchange与DirectExchange类似,区别在于rountingKey必须是多个单词的列表,并且以"."分割。Queue与Exchange指定BindingKey可以使用通配符
#:代表0个或多个单词
*:代表一个单词
我们使用Direct的时候一个队列如果绑定了很多key,会非常麻烦,通配符的引入就把key的绑定简化许多,原来绑定多个key现在只需要绑定一个key。
实现思路:
1.利用@RabbitListenter声明Exchange、Queue、RoutingKey
2.在consumer服务中,编写两个消费者方法,分别监听topic.queue1和topic.queue2
//topic话题
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic.queue1"),exchange = @Exchange(name = "topic",type = ExchangeTypes.TOPIC),key ="china.#"
))
public void listennertopicqueue1(String msg)
{System.out.println("消费者接收到topic.queue1的消息"+msg);
}
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic.queue2"),exchange = @Exchange(name = "topic",type = ExchangeTypes.TOPIC),key ="#.news"
))
public void listennertopicqueue2(String msg)
{System.out.println("消费者接收到topic.queue2的消息"+msg);
}
3.在publisher中编写测试方法,向交换机topic发送消息
@Test
public void contextTopicExchange()
{String exchangeName="topic";String msg="我是懒大王";rabbitTemplate.convertAndSend(exchangeName,"china.news",msg);
}
6.消息转换器
在SpringAMQP的发送方法中,接收消息的类型是Object,也就是说我们可以发送任意对象类型的消息,SpringAMQP会帮我们序列化为字节后发送。
Spring的消息对象处理是由MessageConcerter来处理的,而默认实现是SimpleMessageConverter,基于JDK的ObjectOutputStream完成序列化,这种序列化方式,比较浪费内存资源,如果需要修改,只需要定义一个MessageConverter类型的Bean即可。推荐用JSON方式序列化,步骤如下:
我们在publisher服务引入依赖
我们在publisher服务中声明MessageConverter
相关文章:

RabbitMQ的介绍和使用
1.同步通讯和异步通讯 举个例子,同步通讯就像是在打电话,因此它时效性较强,可以立即得到结果,但如果你正在和一个MM打电话,其他MM找你的话,你们之间是不能进行消息的传递和响应的 异步通讯就像是微信&#…...
前端get请求日期类型参数向后端传参失败
1、背景 get请求,通过url上传参,因此日期类型是string类型数据 2、异常信息 nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.time.LocalDate] for…...

【docker 】 push 镜像提示:denied: requested access to the resource is denied
往 Docker Registry (私服)push 镜像提示:denied: requested access to the resource is denied 镜像push 语法:docker push <registry-host>:<registry-port>/<repository>:<tag> docker push 192.16…...
浏览器各类好用插件使用及常见问题(技巧)总结
目录 Vimium C快捷键问题为什么Vimium C - 全键盘操作浏览器插件在百度页面中, x ,o,f等快捷键不起作用如何使用viminum c插件进行自定义快捷键?vimucm 为什么在浏览器首页时快捷键不起作用? 网页截图问题firefox 网页截图使用 idm问题浏览器点击idm 不下载? 待续、更新中 V…...

Python批量计算多张遥感影像的NDVI
本文介绍基于Python中的gdal模块,批量基于大量多波段遥感影像文件,计算其每1景图像各自的NDVI数值,并将多景结果依次保存为栅格文件的方法。 如下图所示,现在有大量.tif格式的遥感影像文件,其中均含有红光波段与近红外…...

6.k8s中的secrets资源
一、Secret secrets资源,类似于configmap资源,只是secrets资源是用来传递重要的信息的; secret资源就是将value的值使用base64编译后传输,当pod引用secret后,k8s会自动将其base64的编码,反编译回正常的字符…...
git 更换远程仓库地址三种方法总结
git 更换远程仓库地址三种方法总结 一、前言 由于私服的 gitlab 的地址变更,导致部分项目代码提交不上去,需要修改远端仓地址。 其它需要修改远程仓地址的情况如:切换git clone 协议由ssh变为https。 二、环境 windows 10git version 2.3…...

快速找出存(不存在)在某个(或多个)文件的文件夹
首先,需要用到的这个工具: 度娘网盘 提取码:qwu2 蓝奏云 提取码:2r1z 想要找出有下面这个文件存在的文件夹 切换到批量文件复制版块,快捷键Ctrl5 右侧,搜索添加 选定范围,勾选搜索文件夹、包…...

Linux USB转串口设备路径的查找方法
1、USB转串口设备 USB转串口设备是在嵌入式软件开发过程中经常要使用的,常常用于对接各种各样的串口设备。如果一台linux主机上使用多个usb转串口设备时,应用程序中就需要知道自己操作的是哪个串口设备。串口设备在系统上电时,由于驱动加载的…...

【初阶数据结构】单链表之环形链表
目录标题 前言环形链表的约瑟夫问题环形链表环形链表|| 前言 前面我们已经学习了关于单链表的一些基本东西,今天我们来学习单链表的一个拓展——环形链表,我们将用力扣和牛客网上的三道题目来分析讲解环形链表问题。 环形链表的约瑟夫问题 我们首先来看…...
【积分,微分,导数,偏导数公式推导】
1. 积分 积分是微积分的一个分支,用于计算曲边梯形的面积或者变速直线运动的总距离等。积分分为不定积分和定积分。 不定积分:给出一个函数,求出其所有可能的原函数。定积分:计算一个函数在特定区间上的积分。 2. 微分 微分是…...

java:递归实现的案例
//求第20个月兔子的对数 //每个月兔子对数:1,1,2,3,5,8 public class Test {//求第20个月兔子的对数//每个月兔子对数:1,1,2,3,5,8pu…...
Arxml文件解析03- 自动驾驶Radar服务radar_svc.arxml
<AR-PACKAGES><AR-PACKAGE><SHORT-NAME>bosch</SHORT-NAME><AR-PACKAGES>...</AR-PACKAGES>...
Elasticsearch安装步骤
引言 Elasticsearch是一个基于Lucene构建的开源、分布式、RESTful搜索和分析引擎。它设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。Elasticsearch为所有类型的数据提供近乎实时的搜索和分析。无论…...

Windows系统和unbtun系统连接usb 3.0海康可见MVS和红外艾睿相机
一.海康可见USB3.0工业面阵相机 海康usb相机需要去海康官网上下载对应系统的MVS客户端及SDK开发包 海康机器人-机器视觉-下载中心 选择Windows系统和unbtun(我是linux aarch64,所以选择了对应压缩包解压) Windows系统 1.双击安装包进入安装界面&…...

深入Django:用户认证与权限控制实战指南
title: 深入Django:用户认证与权限控制实战指南 date: 2024/5/7 18:50:33 updated: 2024/5/7 18:50:33 categories: 后端开发 tags: AuthDecoratorsPermissionsGuardianRESTAuthSessionMgmtMFA 第1章:入门Django与设置 1.1 Django安装与环境配置 在…...

Kubernetes - Dashboard 配置用户名密码方式登录
Kubernetes - Dashboard 配置用户名密码方式登录 前言: 为了 K8s 集群安全,默认情况下 Dashboard 以 Token的形式登录的,那如果我们想以用户名/密码的方式登录该怎么操作呢?其实只需要我们创建用户并进行 ClusterRoleBinding绑定即…...
AIGC能给人类社会带来哪些变革?
随着人工智能技术的飞速发展,AIGC(人工智能生成内容)正在成为推动社会变革的重要力量。本文将从技术角度出发,探讨AIGC技术如何影响和改变人类生活的各个方面。 一、AIGC技术概述 AIGC,即人工智能生成内容࿰…...

医药垃圾分类管理系统|基于SSM医药垃圾分类管理系统的系统设计与实现(源码+数据库+文档)
医药垃圾分类管理系统 目录 基于SSM医药垃圾分类管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1系统登录模块 2管理员模块实现 3用户模块实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博…...

用vim或gvim编辑程序
vim其实不难使用,学习一下就好了。简单功能很快学会。它有三种模式:命令模式,编辑模式,视模式。打开时在命令模式。在命令模式下按 i 进入编辑模式,在编辑模式下按<Esc>键退出编辑模式。在命令模式按 :wq 保存文…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...