上篇文章:

RabbitMQ—消息可靠性保证https://blog.csdn.net/sniper_fandc/article/details/149311576?fromshare=blogdetail&sharetype=blogdetail&sharerId=149311576&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link

目录

1 TTL

1.1 介绍

1.2 消息TTL

1.3 队列TTL

2 死信队列

2.1 介绍

2.2 案例演示

2.2.1 消息超过TTL

2.2.2 手动确认拒绝重新入队

2.2.3 队列满了

2.3 总结

3 延迟队列

3.1 介绍

3.2 实现

3.3 延迟队列插件

3.3.1 RabbitMQ Delayed Message Plugin插件安装

3.3.2 插件使用

3.3.3 案例演示

3.4 总结


1 TTL

1.1 介绍

        TTL表示过期时间,RabbitMQ提供对消息设置TTL和对队列设置TTL两种方式:

        如果对队列设置TTL,就表示队列中的消息都是该TTL过期。

        如果同时设置消息和队列的TTL,那么取两者较小值为TTL的时间。

        TTL的应用场景还是比较广泛的,比如订单系统和支付系统通过RabbitMQ通信,订单具有超时时间,超时未支付就会取消订单,此时订单就可以设置TTL。

1.2 消息TTL

        队列、交换机名称和声明:

public class RabbitMQConnection {public static final String TTL_QUEUE = "ttl.queue";public static final String TTL_EXCHANGE = "ttl.exchange";}
@Configurationpublic class RabbitMQConfig {@Bean("ttlQueue")public Queue ttlQueue(){return QueueBuilder.durable(RabbitMQConnection.TTL_QUEUE).build();}@Bean("ttlExchange")public DirectExchange ttlExchange(){return ExchangeBuilder.directExchange(RabbitMQConnection.TTL_EXCHANGE).durable(true).build();}@Bean("ttlQueueBinding")public Binding ttlQueueBinding(@Qualifier("ttlExchange") DirectExchange directExchange, @Qualifier("ttlQueue") Queue queue){return BindingBuilder.bind(queue).to(directExchange).with("ttl");}}

        生产者:

@RestController@RequestMapping("/producer")public class ProducerController {@Resource(name = "rabbitTemplate")private RabbitTemplate rabbitTemplate;@RequestMapping("ttl")public String ttl(){MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {@Overridepublic Message postProcessMessage(Message message) throws AmqpException {message.getMessageProperties().setExpiration("10000");return message;}};rabbitTemplate.convertAndSend(RabbitMQConnection.TTL_EXCHANGE, "ttl","Hello SpringBoot RabbitMQ",messagePostProcessor);return "发送成功";}}

        设置消息TTL主要是在MessagePostProcessor类中为消息setExpiration()设置过期时间,单位为ms,接受类型为String。设置10s过期时间,观察结果:

1.3 队列TTL

        队列、交换机名称和声明:

public class RabbitMQConnection {public static final String TTL_QUEUE = "ttl.queue";public static final String TTL_QUEUE2 = "ttl.queue2";public static final String TTL_EXCHANGE = "ttl.exchange";}
@Configurationpublic class RabbitMQConfig {@Bean("ttlQueue")public Queue ttlQueue(){return QueueBuilder.durable(RabbitMQConnection.TTL_QUEUE).build();}@Bean("ttlQueue2")public Queue ttlQueue2(){return QueueBuilder.durable(RabbitMQConnection.TTL_QUEUE2).ttl(20000).build();}@Bean("ttlExchange")public DirectExchange ttlExchange(){return ExchangeBuilder.directExchange(RabbitMQConnection.TTL_EXCHANGE).durable(true).build();}@Bean("ttlQueueBinding")public Binding ttlQueueBinding(@Qualifier("ttlExchange") DirectExchange directExchange, @Qualifier("ttlQueue") Queue queue){return BindingBuilder.bind(queue).to(directExchange).with("ttl");}@Bean("ttlQueueBinding2")public Binding ttlQueueBinding2(@Qualifier("ttlExchange") DirectExchange directExchange, @Qualifier("ttlQueue2") Queue queue){return BindingBuilder.bind(queue).to(directExchange).with("ttl");}}

        生产者:

@RestController@RequestMapping("/producer")public class ProducerController {@Resource(name = "rabbitTemplate")private RabbitTemplate rabbitTemplate;@RequestMapping("ttl")public String ttl(){rabbitTemplate.convertAndSend(RabbitMQConnection.TTL_EXCHANGE, "ttl","Hello SpringBoot RabbitMQ");return "发送成功";}}

        设置队列过期时间是在声明队列的时候,使用ttl()方法进行设置,单位ms。设置20s队列过期时间,观察结果:

        注意:队列TTL和消息TTL的区别。队列TTL:一旦消息过期,会立即删除消息。消息TTL:消息过期也不会立即从队列中删除,而是等待消息即将被投递到消费者之间再判断是否过期(是否删除)。

        为什么有这样的区别?队列TTL:因为队列的先进先出特性,先进队列的一定先到期,因此只需要定期从队头判断是否过期,过期即连续删除。消息TTL:由于每个消息的TTL都不一样,因此如果要实时判断消息是否过期就需要不断扫描全队列(开销大),因此采用惰性删除即消息即将被投递到消费者之间再判断是否过期。

        上述区别会产生一个现象,在队列TTL中,连续发送的消息(认为是在同一时刻)在超过过期时间后所有消息都会消失。而在消息TTL中,连续发送过期时间长和过期时间短的消息,即使过期时间短的消息已经过期,只要过期时间长的消息还未过期,过期时间短的消息仍然会在队列中。

2 死信队列

2.1 介绍

        当消息因为某些原因,无法再被消费者消费,就变成死信(Dead Letter)。死信就会进入死信交换机(DLX,Dead Letter Exchange),由死信交换机路由到死信队列(DLQ,Dead Letter Queue)。死信队列的消息也可以被消费者消费:

        消息变成死信有如下三种原因:

        1.消息确认机制采用手动确认,并调用basicReject()或basicNack(),requeue==false。由于拒绝重新入队,因此消息变为死信。

        2.消息超过过期时间TTL,超过过期时间的消息无法再被消费,也就变成死信。

        3.队列满了,队列有长度限制,超出队列长度的消息就会变为死信。

2.2 案例演示

2.2.1 消息超过TTL

        队列、交换机名称和声明:

public class RabbitMQConnection {public static final String NORMAL_QUEUE = "normal.queue";public static final String NORMAL_EXCHANGE = "normal.exchange";public static final String DL_QUEUE = "dl.queue";public static final String DL_EXCHANGE = "dl.exchange";}
@Configurationpublic class RabbitMQConfig {//正常队列正常交换机和死信队列死信交换机的声明和绑定@Bean("normalQueue")public Queue normalQueue(){return QueueBuilder.durable(RabbitMQConnection.NORMAL_QUEUE).deadLetterExchange(RabbitMQConnection.DL_EXCHANGE)//绑定死信交换机.deadLetterRoutingKey("dl")//死信携带的routingKey.ttl(10000)//制造死信条件(消息过期).build();}@Bean("normalExchange")public DirectExchange normalExchange(){return ExchangeBuilder.directExchange(RabbitMQConnection.NORMAL_EXCHANGE).durable(true).build();}@Bean("normalQueueBinding")public Binding normalQueueBinding(@Qualifier("normalExchange") DirectExchange directExchange, @Qualifier("normalQueue") Queue queue){return BindingBuilder.bind(queue).to(directExchange).with("normal");}@Bean("dlQueue")public Queue dlQueue(){return QueueBuilder.durable(RabbitMQConnection.DL_QUEUE).build();}@Bean("dlExchange")public DirectExchange dlExchange(){return ExchangeBuilder.directExchange(RabbitMQConnection.DL_EXCHANGE).durable(true).build();}@Bean("dlQueueBinding")public Binding dlQueueBinding(@Qualifier("dlExchange") DirectExchange directExchange, @Qualifier("dlQueue") Queue queue){return BindingBuilder.bind(queue).to(directExchange).with("dl");}}

        生产者:

@RestController@RequestMapping("/producer")public class ProducerController {@Resource(name = "rabbitTemplate")private RabbitTemplate rabbitTemplate;@RequestMapping("dl")public String dl(){rabbitTemplate.convertAndSend(RabbitMQConnection.NORMAL_EXCHANGE, "normal","Hello SpringBoot RabbitMQ");return "发送成功";}}

        运行代码可以发现,创建了两个队列normal.queue和dl.queue,normal.queue的TTL表示设置队列过期时间,DLX表示该队列绑定了死信交换机,DLK则是该队列消息过期时变成死信发送给死信交换机携带了routingKey。

        刚开始生产者给normal.queue发送消息,10s后队列消息过期变为死信,就被发送到死信交换机,死信交换机将死信路由到dl.queue死信队列。

2.2.2 手动确认拒绝重新入队

        添加消费者代码(监听正常队列和死信队列),构造拒绝重新入队的死信条件(需要提前开启manual级别):

@Componentpublic class DlListener {@RabbitListener(queues = RabbitMQConnection.NORMAL_QUEUE)public void queueListener1(Message message, Channel channel) throws IOException {long deliveryTag = message.getMessageProperties().getDeliveryTag();try {System.out.printf("listener [" + RabbitMQConnection.NORMAL_QUEUE + "]收到消息:%s, deliveryTag:%d \n",new String(message.getBody(), "UTF-8"),deliveryTag);int num = 1 / 0;System.out.println("消息处理完成");channel.basicAck(deliveryTag, false);} catch (Exception e) {System.out.println("消息处理发生异常,拒绝重新入队");channel.basicNack(deliveryTag, false, false);}}@RabbitListener(queues = RabbitMQConnection.DL_QUEUE)public void queueListener2(Message message, Channel channel) throws IOException {long deliveryTag = message.getMessageProperties().getDeliveryTag();System.out.printf("listener [" + RabbitMQConnection.DL_QUEUE + "]收到消息:%s, deliveryTag:%d \n",new String(message.getBody(), "UTF-8"),deliveryTag);System.out.println("listener [" + RabbitMQConnection.DL_QUEUE + "]消息处理完成");channel.basicAck(deliveryTag, false);}}

        运行代码可以发现,当正常队列的消息被消费者1处理时发生异常,由于选择拒绝重新入队,因此消息变为死信进入死信队列,然后就被消费者2监听到并处理了消息。

2.2.3 队列满了

        修改队列声明,添加最大长度属性(需要先停止服务器并提前在管理界面删除已经存在的队列):

    @Bean("normalQueue")public Queue normalQueue(){return QueueBuilder.durable(RabbitMQConnection.NORMAL_QUEUE).deadLetterExchange(RabbitMQConnection.DL_EXCHANGE)//绑定死信交换机.deadLetterRoutingKey("dl")//死信携带的routingKey.ttl(10000)//制造死信条件(消息过期).maxLength(10).build();}

        生产者连续发送20条消息:

    @RequestMapping("dl")public String dl() {for (int i = 0; i < 20; i++) {rabbitTemplate.convertAndSend(RabbitMQConnection.NORMAL_EXCHANGE, "normal", "Hello SpringBoot RabbitMQ");}return "发送成功";}

        移除消费者,观察管理界面的队列消息变化情况:

        可以发现normal.queue添加了Lim属性表示队列最大长度。由于队长为10,因此发送20条消息后10条直接变为死信进入死信队列。而10秒TTL后所有消息都过期,变为死信又进入死信队列。

2.3 总结

        死信和死信队列:死信是指无法被消费者处理或消费的消息,死信队列就是存储死信的队列。

        死信产生原因:1.消息处理发生异常,手动确认返回Nack时选择拒绝重新入队的策略。2.消息TTL过期。3.队列满了。

        死信队列应用场景:比如订单系统和支付系统,订单消息存储在消息队列中,如果消息不能正确被支付系统处理,为了保证消息可靠性选择手动确认并重新入队,就会导致订单系统反复处理失败这条消息,其它消费无法得到处理(消息积压)。此时就可以利用死信队列,把处理失败的消息不让重新入队,而是存入死信队列,让其它专门处理死信的消费者进行消费(支付失败的订单发送工单专门交给人工处理)。

        还有就是订单超时,那订单系统的订单的状态就需要修改(待支付变为订单超时),就可以把超时的订单存到死信队列,让支付系统的其它消费者消费,支付系统通过给订单系统发送消息来告知订单状态的改变。

3 延迟队列

3.1 介绍

        消息发送后,让消费者等待一段时间再允许从队列中获取消息,这样的队列就是延迟队列。

        延迟队列的作用类似于定时器,只是定时器往往工作在同一个服务场景,而延迟队列可以工作在分布式场景。常见应用场景如下:

        1.预约服务:在景区预约平台或线上会议室预约后,往往都会把消息延迟到景区开门或会议开始前再通知提醒。

        2.智能家居:用户在下班前就通过手机或远程遥控来控制家里的用电系统、空调、热水器等在用户快到家前就开始工作,这时控制指令就会延迟推送,待到达指定时间时再发送到家居的控制系统。

3.2 实现

        RabbitMQ并没有直接提供延迟队列,延迟队列的实现可以使用TTL+死信队列来实现。

        具体方案如下:

        Queue是设置了TTL,需要延迟通知的消费者监听死信队列,当发送消息到Queue,假设延迟10s通知,那TTL就是10s。10s后消息变为死信,转发到死信队列,此时消费者就可以获取到延迟10s的消息进行消费了。

        具体代码在死信队列已经实现,不再演示。

3.3 延迟队列插件

        上述实现方式存在一个问题,如果设置的不是队列的TTL,而是消息的TTL,各种消息TTL不一致,就会出现无法按特定时间延迟的结果。

        比如消息1TTL为10s,消息2TTL为30s,消息2先发送,消息1后发送。由于消息2在队头,因此RabbitMQ就会反复扫描队头判断是否过期,只有队头判断过期后才会再判断消息1,因此消息1本来要延迟10s,结果却被迫延迟30s后再被消费。

        要解决这个问题,RabbitMQ提供了一个插件专门用来提供延迟队列功能。

3.3.1 RabbitMQ Delayed Message Plugin插件安装

        首先前往插件的github地址:

https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/

        点击右侧的Releases:

        找到和RabbitMQ匹配的版本下载.ez文件:

        根据不同的操作系统寻找不同的安装路径,把下载的插件复制到该目录里(如果没有该目录,手动创建):

        注意:如果是docker,则使用如下命令:docker cp 宿主机文件 容器名称或ID:容器目录。

3.3.2 插件使用

        查看插件:rabbitmq-plugins list

        启动插件:rabbitmq-plugins enable rabbitmq_delayed_message_exchange

        重启服务:service rabbitmq-server restart

3.3.3 案例演示

        队列交换机名称和声明:

public class RabbitMQConnection {public static final String DELAY_QUEUE = "delay.queue";public static final String DELAY_EXCHANGE = "delay.exchange";}
@Configurationpublic class RabbitMQConfig {@Bean("delayQueue")public Queue delayQueue(){return QueueBuilder.durable(RabbitMQConnection.DELAY_QUEUE).build();}@Bean("delayExchange")public DirectExchange delayExchange(){return ExchangeBuilder.directExchange(RabbitMQConnection.DELAY_EXCHANGE).durable(true).delayed().build();}@Bean("delayQueueBinding")public Binding delayQueueBinding(@Qualifier("delayExchange") DirectExchange directExchange, @Qualifier("delayQueue") Queue queue){return BindingBuilder.bind(queue).to(directExchange).with("delay");}}

        声明交换机时,注意使用delayed()来声明这是延迟交换机。这也就意味着延迟队列插件的延迟原理不是放到队列中延迟一定时间在消费,而是消息在交换机上延迟一定时间再把消息路由到队列

        生产者代码:

@RestController@RequestMapping("/producer")public class ProducerController {@Resource(name = "rabbitTemplate")private RabbitTemplate rabbitTemplate;@RequestMapping("delay")public String delay() {MessagePostProcessor messagePostProcessor1 = new MessagePostProcessor() {@Overridepublic Message postProcessMessage(Message message) throws AmqpException {message.getMessageProperties().setDelay(30000);//延迟30sreturn message;}};MessagePostProcessor messagePostProcessor2 = new MessagePostProcessor() {@Overridepublic Message postProcessMessage(Message message) throws AmqpException {message.getMessageProperties().setDelay(10000);//延迟10sreturn message;}};rabbitTemplate.convertAndSend(RabbitMQConnection.DELAY_EXCHANGE, "delay", "Hello SpringBoot RabbitMQ",messagePostProcessor1);rabbitTemplate.convertAndSend(RabbitMQConnection.DELAY_EXCHANGE, "delay", "Hello SpringBoot RabbitMQ",messagePostProcessor2);System.out.println("消息发送成功,当前时间:"+new Date());return "发送成功";}}

        消费者代码:

@Componentpublic class DelayListener {@RabbitListener(queues = RabbitMQConnection.DELAY_QUEUE)public void queueListener2(Message message, Channel channel) throws IOException {System.out.printf("listener [" + RabbitMQConnection.DELAY_QUEUE + "]收到消息:%s, 时间:%s \n",new String(message.getBody(), "UTF-8"), new Date());}}

        可以发现使用延迟队列插件,即使先发送延时时间长的消息,消息处理也不会乱序。运行结果如下:

3.4 总结

        延迟队列概念:消息需要经过一定时间的延迟后在发送给消费者进行消费,存储这样的消息的队列就是延迟队列。

        应用场景:比如订单超时支付自动取消,订单系统下单时设置延迟时间,并将订单消息投递到RabbitMQ中,消息超时则把订单消息发送给消费者(订单系统的订单状态处理模块),订单系统根据是否收到支付系统支付成功的消息或超时订单来修改订单状态(成功支付或超时未支付)。

        还有就是用户发起退款服务,退款信息消息设置延迟24小时并发送给RabbitMQ,当24小时内商家未退款,则退款信息消息自动发送给退款系统的消费者服务,由它们判断是否需要退款(避免重复退款)。

        实现方法以及优缺点对比:

        1.死信队列+TTL,优点:灵活实现不需要插件;缺点:存在消息顺序性问题,需要增加代码逻辑来实现(需要额外的死信交换机和死信队列),增加系统复杂性。

        2.延迟插件,优点:可以直接使用延迟队列,简化延迟消息的实现逻辑,同时没有消息顺序性问题;缺点:需要特定的插件,并且插件还得注意版本问题。

下篇文章:

RabbitMQ—事务与消息分发https://blog.csdn.net/sniper_fandc/article/details/149312189?fromshare=blogdetail&sharetype=blogdetail&sharerId=149312189&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LVS 集群技术详解与实战部署

目录 引言 一、实验环境准备 二、理论基础&#xff1a;集群与 LVS 核心原理 2.1 集群与分布式 2.2 LVS 核心原理 LVS 的 4 种工作模式 LVS 调度算法 三、LVS 部署工具&#xff1a;ipvsadm 命令详解 四、实战案例&#xff1a;LVS 部署详解 案例 1&#xff1a;NAT 模式…

前端vue3获取excel二进制流在页面展示

excel二进制流在页面展示安装xlsx在页面中定义一个div来展示html数据定义二进制流请求接口拿到数据并展示安装xlsx npm install xlsx import * as XLSX from xlsx;在页面中定义一个div来展示html数据 <div class"file-input" id"file-input" v-html&qu…

android 信息验证动画效果

layout_check_pro <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:id"id/parent"android:layout_width"wrap_content"android:layout_…

【iOS】继承链

文章目录前言什么是继承链OC中的根类关于NSProxy关键作用1.方法查找与动态绑定2. 消息转发3. **类型判断与多态**继承链的底层实现元类的继承链总结前言 在objective-c中&#xff0c;继承链是类与类之间通过父类&#xff08;Superclass&#xff09;关系形成的一层层继承结构&am…

论文阅读:Instruct BLIP (2023.5)

文章目录InstructBLIP&#xff1a;迈向通用视觉语言模型的指令微调研究总结一、研究背景与目标二、核心方法数据构建与划分模型架构训练策略三、实验结果零样本性能消融实验下游任务微调定性分析可视化结果展示四、结论与贡献InstructBLIP&#xff1a;迈向通用视觉语言模型的指…

Elasticsearch+Logstash+Filebeat+Kibana部署【7.1.1版本】

目录 一、准备阶段 二、实验阶段 1.配置kibana主机 2.配置elasticsearch主机 3.配置logstash主机 4.配置/etc/filebeat/filebeat.yml 三、验证 1.开启Filebeat 2.在logstash查看 3.浏览器访问kibana 一、准备阶段 1.准备四台主机kibana、es、logstash、filebeat 2.在…

Vue开发前端报错:‘vue-cli-service‘ 不是内部或外部命令解决方案

1.Bug: 最近调试一个现有的Vue前端代码&#xff0c;发现如下错误&#xff1a; vue-cli-service’ 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 2.Bug原因&#xff1a; 导入的工程缺少依赖包&#xff1a;即缺少node_modules文件夹 3.解决方案&#xff1…

AI生态,钉钉再「出招」

如果说之前钉钉的AI生态加持更多的围绕资源和商业的底层助力&#xff0c;那么如今这种加持则是向更深层次进化&#xff0c;即真正的AI模型训练能力加持&#xff0c;为垂类大模型创业者提供全方位的助力&#xff0c;提高创业成功率和模型产品商业化确定性。作者|皮爷出品|产业家…

XSS GAME靶场

要求用户不参与&#xff0c;触发alert(1337) 目录 Ma Spaghet! Jefff Ugandan Knuckles Ricardo Milos Ah Thats Hawt Ligma Mafia Ok, Boomer Exmaple 1 - Create Example 2 - Overwrite Example 3 - Overwrite2 toString Ma Spaghet! <h2 id"spaghet&qu…

Unity学习笔记(五)——3DRPG游戏(2)

添加更多的敌人 编辑EnemyController&#xff0c;解决报错导致敌人无法注册观察者模式&#xff0c;从而无法执行敌人庆祝动画 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public enum EnemyStatus { GUARD,PATROL…

2025测绘程序设计国赛实战:一轮终章 | 单向后方交会C#实现

前言本文是小编对六道国赛试题中的最后一个试题&#xff0c;单向后方交会的一篇学习日志。本文的整体架构&#xff0c;依旧首先拿训练数据跟大家介绍本题涉及到的数据的属性含义&#xff0c;涉及到算法的原理、执行流程和终极目的。然后附上小编用C#来实现的程序&#xff0c;从…

基于Echarts的气象数据可视化网站系统的设计与实现(Python版)

本系统旨在构建一个基于Echarts的气象数据可视化系统&#xff0c;本系统能够从中国天气网爬取实时天气数据&#xff0c;并进行存储、分析和可视化展示。用户可以通过网页界面查看不同地区的天气情况&#xff0c;以及历史天气数据的变化趋势。 技术栈&#xff1a;Python语言、My…

HarmonyOS 启动提速秘籍:懒加载全链路实战解析

摘要 随着移动应用功能越来越复杂、界面越来越丰富&#xff0c;应用启动慢、内存占用高等问题也越来越普遍。特别是在 HarmonyOS NEXT 应用开发中&#xff0c;如果不加优化&#xff0c;用户打开页面时可能要等好几秒&#xff0c;体验就很差了。 懒加载&#xff08;Lazy Loading…

全新安装Proxmox VE启动时卡在Loading initial ramdisk

原因&#xff1a; 使用了Ventoy启动盘装载 Proxmox ISO 文件安装。 要用Ventoy优盘启动&#xff0c;选择Advance Option里的Rescue Boot&#xff0c; 修改文件/etc/default/grub.d/installer.cfg&#xff0c;删除rdinit/vtoy/vtoy运行 update-grub 更新grub配置&#xff0c;重启…

【Java项目安全基石】登录认证实战:Session/Token/JWT用户校验机制深度解析

目录 1.前言 2.正文 2.1Cookie—Session机制 2.1.1核心原理图解&#xff1a; 2.1.2四步核心流程&#xff1a; 2.1.3存储架构对比 2.1.4集群部署方案&#xff08;Spring Session Redis&#xff09; 2.2Token令牌 2.2.1核心原理图解&#xff1a; 2.2.2四步核心流程&am…

融合优势:SIP 广播对讲联动华为会议 全场景沟通响应提速​

SIP 广播对讲与华为视频会议融合解决方案&#xff0c;是基于 SIP 协议将广播对讲系统与华为视频会议系统进行整合&#xff0c;实现通信资源共享与业务流程联动&#xff0c;可提升应急响应效率与沟通协作能力。融合原理&#xff1a;SIP 是一种基于文本的应用层协议&#xff0c;具…

Milvus Dify 学习笔记

目录 docker方式&#xff1a; 模式一&#xff1a;Milvus Lite linux docker方式&#xff1a; 下载yml文件&#xff0c; https://github.com/milvus-io/milvus/releases docker启动&#xff1a; docker compose up -d from pymilvus import connections connections.conne…

汽车ECU控制器通信架构

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

【Linux】基本指令(入门篇)(上)

目录 前言 1.目录操作指令 1.1指令 1.2理论 1.2.1文件 1.2.2目录与路径 2.文件操作指令 2.1指令 2.2理论 2.2.1输出与输入 2.2.2一切皆文件 前言 这是Linux学习下的第一篇文章&#xff0c;后续Linux的学习也会持续更新分享。 Linux的基本指令是使用Linux操作系统的基础…

正向代理与反向代理理解

问&#xff1a; 应用a请求ng&#xff0c;然后ng根据不同请求路径将请求转发到不同的服务器&#xff0c;对于应用a来说这个ng是正向代理角色还是反向代理呢&#xff1f; 答&#xff1a; 在这个场景中&#xff0c;Nginx 扮演的是反向代理的角色&#xff0c;而不是正向代理。以下是…