【Rabbitmq篇】高级特性----事务,消息分发
目录
事务
消息分发
应用场景
1. 限流
2.负载均衡
事务
RabbitMQ是基于AMQP协议实现的,该协议实现了事务机制,因此RabbitMQ也支持事务机制.SpringAMQP也提供了对事务相关的操作.RabbitMQ事务允许开发者确保消息的发送和接收是原子性的,要么全部成功,要么全部失败.
何为原子性(面试重点)?
例如: 当A向B转账1000元,会经历俩个步骤
1.A 向 B 转账 1000元 A的账号将会减去1000元
2.B将会收到1000元 B的账号将会增加1000元
可是,如果遇到极端情况,当A向B转账1000元时,A-1000元已完成,这个时候系统出现故障,导致A-1000 但是B却没有接收到 那么1000元将无缘无故丢失了 ,肯定不会允许这种事情发生,不然谁还敢转账。
此时就是将1操作和2操作绑定在一起,要么同时完成,要么一个都不执行
当出现1执行失败的时候,将1操作进行“回滚”,回到原来的状态,就当一切都没发生过
接下来实现rabbitmq的事务
声明队列:
//事务public static final String TRANS_QUEUE = "trans_queue";@Bean("transQueue")public Queue transQueue() {return QueueBuilder.durable(Constants.TRANS_QUEUE).build();}
配置事务管理器:
@Beanpublic RabbitTransactionManager rabbitTransactionManager(ConnectionFactory connectionFactory) {return new RabbitTransactionManager(connectionFactory);}@Bean("transRabbitTemple")public RabbitTemplate transRabbitTemple(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);//开启事务rabbitTemplate.setChannelTransacted(true);return rabbitTemplate;}
生产者代码编写:
@RequestMapping("/trans")public String trans() {System.out.println("trans test...");transRabbitTemplate1.convertAndSend(Constants.TRANS_EXCHANGE, "trans", "trans test 1...");int num = 5/0;transRabbitTemplate1.convertAndSend(Constants.TRANS_EXCHANGE, "trans", "trans test 2...");return "消息发送成功";}
测试:
1)不带 @Transactional 带异常的发送 看看会发生什么?
此时只有发送的第一条消息,紧接着发生了异常导致第二条消息未发送成功
2) 带 @Transactional 带异常的发送 看看会发生什么?
@Transactional@RequestMapping("/trans")public String trans() {System.out.println("trans test...");transRabbitTemplate1.convertAndSend(Constants.TRANS_EXCHANGE, "trans", "trans test 1...");int num = 5/0;transRabbitTemplate1.convertAndSend(Constants.TRANS_EXCHANGE, "trans", "trans test 2...");return "消息发送成功";}
此时发生异常 本来发送了一条消息 但有异常,进行了回滚,当做没发生
也证明了我们事务的可靠性
3)带 @Transactional 不带异常的发送 看看会发生什么?
@Transactional@RequestMapping("/trans")public String trans() {System.out.println("trans test...");transRabbitTemplate1.convertAndSend(Constants.TRANS_EXCHANGE, "trans", "trans test 1...");
// int num = 5/0;transRabbitTemplate1.convertAndSend(Constants.TRANS_EXCHANGE, "trans", "trans test 2...");return "消息发送成功";}
此结果一切正常
消息分发
RabbitMQ队列拥有多个消费者时,队列会把收到的消息分派给不同的消费者.每条消息只会发送给订阅列表里的⼀个消费者.这种方式⾮常适合扩展,如果现在负载加重,那么只需要创建更多的消费者来消费处理消息即可.
默认情况下,RabbitMQ是以轮询的方法进行分发的,而不管消费者是否已经消费并已经确认了消息.这种方式是不太合理的,试想⼀下,如果某些消费者消费速度慢,而某些消费者消费速度快,就可能会导致某些消费者消息积压,某些消费者空闲,进而应用整体的吞吐量下降.这样A都做完了10个任务,B还在写第一个任务,这样将会大大影响效率,从而导致整个的效率下降
如何处理呢我们可以使用前面章节讲到的channel.basicQos(intprefetchCount)方法,来限制当前信道上的消费者所能保持的最大未确认消息的数量
比如:消费端调用了channelbasicQos(1),
此时A接收1条信息,并且消费1条 B同时也接收1条信息 但是它效率比较慢 所有它还在消费 而A处理完1条消息又接着处理第二条消息,属于多劳多得,并不会因为B影响整体的效率
应用场景
1. 限流
如下使用场景:
订单系统每秒最多处理5000请求,正常情况下,订单系统可以正常满足需求
但是在秒杀时间点,请求瞬间增多,每秒1万个请求,如果这些请求全部通过MQ发送到订单系统,无疑会把订单系统压垮.RabbitMQ提供了限流机制,可以控制消费端⼀次只拉取N个请求
通过设置prefetchCount参数,同时也必须要设置消息应答方式为手动应答
prefetchCount:控制消费者从队列中预取(prefetch)消息的数量,以此来实现流控制和负载均衡.
1) 配置prefetch参数,设置应答方式为手动应答
2) 配置交换机,队列
package com.bite.extensions.config;import com.bite.extensions.constant.Constants;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class QosConfig {@Bean("qosQueue")public Queue qosQueue() {return QueueBuilder.durable(Constants.QOS_QUEUE).build();}@Bean("qosExchange")public DirectExchange qosExchange() {return ExchangeBuilder.directExchange(Constants.QOS_EXCHANGE).build();}@Bean("qosBinding")public Binding qosBinding(@Qualifier("qosQueue") Queue queue, @Qualifier("qosExchange") DirectExchange directExchange) {return BindingBuilder.bind(queue).to(directExchange).with("qos");}
}
3) 生产者
@RequestMapping("/qos")public String qos() {System.out.println("qos test...");for (int i = 0; i < 15; i++) {rabbitTemplate.convertAndSend(Constants.QOS_EXCHANGE, "qos", "qos test i..."+i);}return "消息发送成功";}
4)消费者
package com.bite.extensions.listener;import com.bite.extensions.constant.Constants;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;@Component
public class QosListener {@RabbitListener(queues = Constants.QOS_QUEUE)public void handleMessage(Message message, Channel channel) throws Exception {//消费者逻辑long deliverTag = message.getMessageProperties().getDeliveryTag();try {System.out.printf("[qos.queue]接收到信息: %s, deliveryTag: %d\n",new String(message.getBody(),"UTF-8"),deliverTag);
/* //业务逻辑处理System.out.println("业务逻辑处理!");//肯定确认channel.basicAck(deliverTag,false);*/} catch (Exception e) {//否定确认channel.basicNack(deliverTag,false,true);//requeue为false,则变成死信队列}}
}
5)测试1 未设置肯定确认情况
此时将会只接收到5条,并且会阻塞住,达到一个限流的状态
测试2
把 prefetch: 5 注掉 再观看结果
此时将会一次性把队列的消息全部发送,并且全部消费
2.负载均衡
如下图,在有两个消费者的情况下,⼀个消费者处理任务非常快,另⼀个非常慢,就会造成⼀个消费者会⼀直很忙,而另⼀个消费者很闲.这是因为RabbitMQ只是在消息进入队列时分派消息.它不考虑消费者未确认消息的数量.
我们可以使用设置prefetch=1的⽅式,告诉RabbitMQ⼀次只给⼀个消费者⼀条消息,也就是说,在处理并确认前⼀条消息之前,不要向该消费者发送新消息.相反,它会将它分派给下⼀个不忙的消费者.
消费者:
package com.bite.extensions.listener;import com.bite.extensions.constant.Constants;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;@Component
public class QosListener {@RabbitListener(queues = Constants.QOS_QUEUE)public void handleMessage(Message message, Channel channel) throws Exception {//消费者逻辑long deliverTag = message.getMessageProperties().getDeliveryTag();try {System.out.printf("第一个消费者 接收到信息: %s, deliveryTag: %d\n",new String(message.getBody(),"UTF-8"),deliverTag);Thread.sleep(3000);channel.basicAck(deliverTag,false);} catch (Exception e) {//否定确认channel.basicNack(deliverTag,false,true);//requeue为false,则变成死信队列}}@RabbitListener(queues = Constants.QOS_QUEUE)public void handleMessage2(Message message, Channel channel) throws Exception {//消费者逻辑long deliverTag = message.getMessageProperties().getDeliveryTag();try {System.out.printf("第二个消费者 接收到信息: %s, deliveryTag: %d\n",new String(message.getBody(),"UTF-8"),deliverTag);Thread.sleep(1000);channel.basicAck(deliverTag,false);} catch (Exception e) {//否定确认channel.basicNack(deliverTag,false,true);//requeue为false,则变成死信队列}}
}
结果:
这里可以看出每个消费者以不同的速度完成某项任务 以防止一个消费者未完成等很久的情况
结语: 写博客不仅仅是为了分享学习经历,同时这也有利于我巩固知识点,总结该知识点,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进。同时也希望读者们不吝啬你们的点赞+收藏+关注,你们的鼓励是我创作的最大动力!
相关文章:
【Rabbitmq篇】高级特性----事务,消息分发
目录 事务 消息分发 应用场景 1. 限流 2.负载均衡 事务 RabbitMQ是基于AMQP协议实现的,该协议实现了事务机制,因此RabbitMQ也支持事务机制.SpringAMQP也提供了对事务相关的操作.RabbitMQ事务允许开发者确保消息的发送和接收是原子性的,要么全部成功,要么全部失败. 何为原…...
Python进程和线程适用场景
在选择使用 进程(Process)和 线程(Thread)时,通常取决于任务的类型、程序的需求以及硬件资源的限制。进程和线程各自有不同的特点,适用于不同的场景。下面是关于进程和线程的一些常见应用场景和选择指导&am…...
flutter开发环境—Windows
一、简介 我们使用最新版的flutter版本安装。 参考链接 名称地址官方网站https://flutter.dev/官方中文网站文档 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter软件下载路径https://docs.flutter.dev/release/archive?tabwindows 二、操作流程 2.1 下载软件 点…...
展示和添加篮球队信息--laravel与elementplus
之前使用laravel与inertia来做过一样的功能,感觉不满意,因此再结合elementplus重做一遍,先展示下重做后的效果。重写后的代码相比之下比较优雅。 球队首页 球队添加页 球员首页 很明显的改变,我新增了侧栏菜单来控制局部模块(这里是指NBABasketba…...
写一份客服网络安全意识培训PPT
一、为什么要对客服人员定期进行网络安全培训呢? 人员组成复杂:企业既有自由人员又有采购的外包公司客服,为了节约成本可能外包占大多数,这必然加强了人群的流动性所以往往得不到系统的培训。人员素质参差不齐:因为工…...
具体的技术和工具在县级融媒体建设3.0中有哪些应用?
以下是结合数据来看县级融媒体建设3.0的一些情况: 技术应用方面 大数据:人民网舆情数据中心执行主任董盟君提到,通过大数据分析可让融媒体单位快速关注聚焦点,实现智能策划、智能推送、智能传播,推动媒体传播影响力提…...
【uniapp】轮播图
前言 Uniapp的swiper组件是一个滑块视图容器组件,可以在其中放置多个轮播图或滑动卡片。它是基于微信小程序的swiper组件进行封装,可以在不同的平台上使用,如微信小程序、H5、App等。 效果图 前端代码 swiper组件 <template><vi…...
Rust编程语言代码详细运行、编译方法
以下是针对不同类型的 Rust 代码(以常见的命令行程序为例)详细的运行方法: 前提条件 在运行 Rust 代码之前,确保你已经在系统上安装了 Rust 编程语言环境。如果尚未安装,可以通过以下步骤进行安装: 访问…...
node.js基础学习-http模块-JSONP跨域传值(四)
前言 JSONP(JSON with Padding)是一种用于跨域数据传输的技术。在浏览器的同源策略限制下,一般情况下,JavaScript 不能直接从不同域的服务器获取数据。JSONP 通过利用 <script> 标签的跨域特性来绕过这个限制。 它本质上是一…...
Unity高效编程经验50条分享
1.避免频繁创建临时对象 错误写法:obj.transform.position pos;这种写法会在Lua中频繁返回transform对象导致gc正确写法:创建一个静态方法来设置位置,例如 class LuaUtil { static void SetPos(GameObject obj, float x, float y, float z)…...
TypeScript 泛型
在 TypeScript 中,泛型是一种强大的工具,它允许你在定义函数、类、接口或类型别名时不指定具体的类型。这意味着你可以为这些实体创建可重用的组件,这些组件可以在不同的类型上以一致的方式工作。今天,我们将深入探讨 TypeScript …...
【Java从入门到放弃 之 条件判断与循环】
条件判断与循环 条件判断if 语句if-else 语句if-else 嵌套语句switch 语句 循环for 循环while 循环do-while 循环break 和 continuebreak 关键字continue 关键字总结 条件判断 条件判断用于根据不同的条件执行不同的代码块。Java 中常用的条件判断语句有 if、if-else 和 switc…...
Ubuntu20.04安装kalibr
文章目录 环境配置安装wxPython下载编译测试报错1问题描述问题分析问题解决 参考 环境配置 Ubuntu20.04,python3.8.10,boost自带的1.71 sudo apt update sudo apt-get install python3-setuptools python3-rosinstall ipython3 libeigen3-dev libboost…...
Flink 任务启动脚本-V2(包括ck启动)
#!/bin/bash#crontab时设置,如果依赖其他环境变量配置,可以在脚本执行一下环境变量脚本 source /etc/profile# 进入脚本目录 curdirdirname "$0" curdircd "$curdir"; pwd echo "进入启动脚本目录 $curdir"# 定义应用程序…...
扫雷-完整源码(C语言实现)
云边有个稻草人-CSDN博客 在学完C语言函数之后,我们就有能力去实现简易版扫雷游戏了(成就感满满),下面是扫雷游戏的源码,快试一试效果如何吧! 在test.c里面进行扫雷游戏的测试,game.h和game.c…...
python -从文件夹批量提取pdf文章的第n页,并存储起来
python -从文件夹批量提取pdf文章的第n页,并存储起来 废话不多说,看下面代码 讲解一下下面代码 reader PyPDF2.PdfReader (file) 将文件转化为PdfReader 对象,方便使用内置方法。 first_page reader.pages[0] 提取第一页 writer PyPDF…...
R Excel 文件操作指南
R Excel 文件操作指南 概述 R 语言是一种强大的统计分析工具,广泛用于数据分析和可视化。在实际应用中,经常需要将 R 语言与 Excel 文件结合使用,以便处理和分析数据。本指南将介绍如何在 R 中读取、写入和操作 Excel 文件。 准备工作 在…...
RabbitMQ 安装延迟队列插件 rabbitmq_delayed_message_exchange
前言: RabbitMQ 延迟队列插件(rabbitmq_delayed_message_exchange)是一个社区开发的插件,它为 RabbitMQ 添加了支持延迟消息的功能。通过这个插件,用户可以创建一种特殊的交换机类型 x-delayed-message,该…...
fatal error in include chain (rtthread.h):rtconfig.h file not found
项目搜索这个文件 rtconfig 找到后将其复制粘贴到 你的目录\Keil\ARM\ARMCC\include 应该还有cJSON,rtthread.h和 等也复制粘贴下...
Java 反射(Reflection)
Java 反射(Reflection) Java 反射(Reflection)是一个强大的特性,它允许程序在运行时查询、访问和修改类、接口、字段和方法的信息。反射提供了一种动态地操作类的能力,这在很多框架和库中被广泛使用&#…...
Python爬取机车网车型数据并存入Mysql数据库
结果展示(文末附完整代码): 一、引言 在当今数字化时代,数据对于各个领域的重要性不言而喻。对于机车行业而言,获取丰富的机车品牌、车型及详细信息数据,能够为市场分析、消费者研究等提供有力支持。本文将…...
fpga 时序分析基础
目录 触发器的动态参数 同步时序电路分析 1. 时钟脉冲的特性 2. 同步时序电路分析 Timing Analyzer的应用 异步时序与亚稳态问题 时序分析就是对时序电路进行时序检查,通过分析电路中所有寄存器之间的路径延迟以检查电路的传输延迟是否会导致触发器的建立时间…...
python学习——二维列表的列表生成式
二维列表的列表生成式允许你生成一个列表,其中每个元素本身也是一个列表。这在处理矩阵或表格数据时非常有用。 以下是如何使用列表生成式来创建二维列表的示例: 文章目录 基本语法示例1. 创建一个 3x3 的单位矩阵2. 创建一个 4x4 的乘法表3. 创建一个 …...
【错误❌】——槽函数定义好但未初始化
public slots:void onClose(); 初始化即可成功:...
OpenCV相机标定与3D重建(6)将3D物体点投影到2D图像平面上函数projectPoints()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::fisheye::projectPoints 是 OpenCV 库中用于鱼眼镜头模型的函数,它将3D物体点投影到2D图像平面上。这个函数对于模拟或者理解鱼眼…...
【Linux】剧幕中的灵魂更迭:探索Shell下的程序替换
🎬 个人主页:谁在夜里看海. 📖 个人专栏:《C系列》《Linux系列》《算法系列》 ⛰️ 一念既出,万山无阻 目录 📖一、进程程序替换 1.替换的演示 ❓替换与执行流 ❓程序替换≠进程替换 2.替换的原理 …...
38 基于单片机的宠物喂食(ESP8266、红外、电机)
目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52单片机,采用L298N驱动连接P2.3和P2.4口进行电机驱动, 然后串口连接P3.0和P3.1模拟ESP8266, 红外传感器连接ADC0832数模转换器连接单片机的P1.0~P1.…...
Unity中的数学应用 之 角色移动中单位化向量的妙用 (小学难度)
最近准备从简单到困难跟几个教程用以加强自己的业务能力,相信很多小伙伴都做过胡闹厨房这一个案例,其实这个案例比较初级,但是也包含了很多平常可能注意不到小细节,所以我就以它为举例,拓展其中的数学知识 CodeMonkey教…...
设置ip和代理DNS的WindowsBat脚本怎么写?
今天分享一个我们在工作时,常见的在Windows中通过批处理脚本(.bat 文件)来设置IP地址、代理以及DNS 相关配置的示例,大家可以根据实际需求进行修改调整。 一、设置静态IP地址脚本示例 以下脚本用于设置本地连接(你可…...
字符串分割转换(Java Python JS C++ C )
题目描述 给定一个非空字符串S,其被N个‘-’分隔成N+1的子串,给定正整数K,要求除第一个子串外,其余的子串每K个字符组成新的子串,并用‘-’分隔。 对于新组成的每一个子串,如果它含有的小写字母比大写字母多,则将这个子串的所有大写字母转换为小写字母; 反之,如果它…...
2345网址导航高级版/长沙网站seo分析
设计模式简介 设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错…...
做网站主要是做什么/搜索引擎优化的基础是什么
在API网关开放API服务后,如何保障服务的稳定性,怎么能够实时监控API的情况?及时处理API服务异常,是API开放者关注的重点。本文将主要介绍API网关提供的API监控报警功能,通过简单的配置,即可帮助您实现API的…...
徐州做网站的哪个好/公司网站设计模板
阅读文本大概需要 3 分钟。清楚地认识自己最近几天朋友圈被程序员因同事没写代码注释而惨遭枪击,刷屏了,好几个技术圈的大号都转发了,并且都是 10w 的阅读量。那篇英文原文根本没有提及动机是因为没写代码注释,全是作者自己的猜想…...
设计官网收费标准/南京seo排名扣费
题库来源:安全生产模拟考试一点通公众号小程序 2022年制冷与空调设备运行操作操作证考试题库系制冷与空调设备运行操作考题高频考题覆盖!2022制冷与空调设备运行操作考试模拟100题及在线模拟考试根据制冷与空调设备运行操作考试大纲。制冷与空调设备运行…...
c 做网站怎么连接到别的网页/石家庄高级seo经理
实现同时运行多个线程工作,主要通过信号量的设置,但还是在一个CPU上执行,具体要实现的例子可以放在函数里执行,实现单核多并发,还等待什么...... #!/usr/bin/env python # -*- coding: utf-8 -*- import threading import time import random…...
长沙做网站建设公司哪家好/新闻稿营销
还记得2010年的时候,那个时候移动互联网时代刚刚兴起,很多以前做java的,也就是做J2EE的人(当时J2EE是红海),抓住了这个机会进行的转型,然后得到红利,甚至实现了人生的转变࿰…...