当前位置: 首页 > news >正文

RabbitMQ——消息的可靠性处理

1.业务分析

        在业务的开发中,我们通常将业务的非核心业务交给MQ来处理,比如支付,在支付过后,我们需要扣减余额,修改支付单状态,修改订单状态,发送短信提醒用户,给用户增加积分等等(可能真是场景并非这么简单,这里举个例子),在这套业务中,修改订单状态,发送短信提醒用户,给用户增加积分这三个业务在特定场景下并非是核心业务,所以把他放在MQ消息队列中进行处理,在非核心业务执行的时候,可能出现多个问题,导致数据不一致,比如用户买了东西,发现自己的钱已经扣了,但是页面显示的还是未支付状态,这种情况就非常严重了,造成这个现象的原因可能有多种,比如,网络丢包,发布消息者挂了,MQ挂了,消费者挂了等等,可能有硬件层面,也可能有软件层面,甚至是网络层面,对于这一系列问题,我们应该尽量的保证消息的可靠性,让数据一致性得到保证,接下来,从三个方面进行分析,以及提出解决方案,不过具体还是得看业务需求,是否需要数据的强一致性。

2.发送者的可靠性

        2-1:发送者重连

        消息的发布有三个角色,发布者,MQ,消费者,在发消息的时候需要和MQ进行连接,这个连接时一个网络连接,如果因为网络问题,消息发送失败,可能会导致数据不一致产生。

解决方案:在发布者的application.yaml中配置

spring:rabbitmq:connection-timeout: 1s # 设置MQ的连接超时时间template:retry:enabled: true # 开启超时重试机制initial-interval: 1000ms # 失败后的初始等待时间multiplier: 1 # 失败后下次的等待时长倍数,下次等待时长 = initial-interval * multiplier,如果是2,第一此初始化1秒,2秒,4秒,以此类推max-attempts: 3 # 最大重试次数

        注意:当网络不稳定的时候,利用重试机制可以有效提高消息发送的成功率。不过SpringAMQP提供的重试机制是阻塞式的重试,也就是说多次重试等待的过程中,当前线程是被阻塞的,会影响业务性能。如果对于业务性能有要求,建议禁用重试机制。如果一定要使用,请合理配置等待时长和重试次数,当然也可以考虑使用异步线程来执行发送消息的代码。

        2-2:发送者确认机制

SpringAMQP提供了Publisher Confirm和Publisher Return两种确认机制。开启确机制认后,当发送者发送消息给MQ后,MQ会返回确认结果给发送者,发送者再证实这个返回结果。返回的结果有以下几种情况:

  • 消息投递到了MQ,但是路由失败。此时会通过PublisherReturn返回路由异常原因,然后返回ACK,告知投递成功
  • 临时消息投递到了MQ,并且入队成功,返回ACK,告知投递成功
  • 持久消息投递到了MQ,并且入队完成持久化,返回ACK,告知投递成功
  • 其它情况都会返回NACK,告知投递失败

92c4e225b2cc46f1bddcb507065bc3c8.png

返回ACK不需要重发,NACK需要重发

在publisher模块的application.yaml中添加配置:

spring:rabbitmq:publisher-confirm-type: correlated # 开启publisher confirm机制,并设置confirm类型publisher-returns: true # 开启publisher return机制

这里 publisher-confirm-type 有三种模式可选:

  • none : 关闭confirm机制
  • simple:同步阻塞等待MQ的回执
  • correlated:MQ异步回调返回回执

一般推荐使用 correlated,回调机制。

每个RabbitTemplate只能配置一个ReturnCallback,因此我们可以在配置类中统一设置。我们在publisher模块定义一个配置类:

@Configuration
@RequiredArgsConstructor
@Slf4j
public class MqConfig {private final RabbitTemplate rabbitTemplate;@PostConstructpublic void init(){rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {@Overridepublic void returnedMessage(ReturnedMessage returnedMessage) {log.error("触发returnCallback");log.debug("exchange:{}",returnedMessage.getExchange());log.debug("message:{}",returnedMessage.getMessage());log.debug("routingKey:{}",returnedMessage.getRoutingKey());log.debug("replyCode:{}",returnedMessage.getReplyCode());log.debug("replyText:{}",returnedMessage.getReplyText());}});}
}

由于每个消息发送时的处理逻辑不一定相同,因此ConfirmCallback需要在每次发消息时定义。具体来说,是在调用RabbitTemplate中的convertAndSend方法时,多传递一个参数:

@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "simple2.queue"),exchange = @Exchange(name = "simple2.direct"),key = "simple2"))public void testPublisherConfirmRule() {CorrelationData cd = new CorrelationData(UUID.randomUUID().toString());cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {@Overridepublic void onFailure(Throwable ex) {// Future发生异常时的处理逻辑,基本不会触发log.error("Future发生异常时的处理逻辑", ex);}@Overridepublic void onSuccess(CorrelationData.Confirm result) {if (result.isAck()){log.debug("发送消息成功,收到ACK!");}else {log.error("发送消息失败,收到NACK!");//TODO: 重发消息}}});//交换机名称String exchange = "simple2.direct";//消息String message = "hello mq";//发送消息rabbitTemplate.convertAndSend(exchange, "simple2", message, cd);}

3.MQ的可靠性

        在默认情况下,RabbitMQ会将接受到的消息保存在内存中以降低消息收发的延迟。这样会导致两个问题:

  • 一旦MQ宕机,内存中的消息会丢失
  • 内存空间有限,当消费者故障或处理过慢时,会导致消息积压,引发MQ阻塞

方案一:数据持久化

数据持久化包括三个方面:交换机持久化,队列持久化,消息持久化

SpringAMQP默认生成的交换机和队列以及发消息都是持久化的

方案二:lazy queue(既能保证并发能力,又不用写内存)

        从RabbitMQ的3.6.0版本开始,就增加了LazyQueue的概念,也就是惰性队列。惰性队列的特征如下:

  • 接收到消息后直接存入磁盘,不再存储到内存
  • 消费者要消费消息时才会从磁盘中读取并加载到内存(可以提前缓存部分消息到内存,最多2048条)在3.12版本后,所有队列都是LazyQueue模式,无法更改。

那如何把queue变成lazy queue,可以基于声明bean的形式,也可以通过注解的方式

@Bean
public Queue lazyQueue(){return QueueBuilder.durable("lazy.queue").lazy() // 开启Lazy模式.build();
}
@RabbitListener(queuesToDeclare = @Queue(name = "lazy.queue",durable = "true",arguments = @Argument(name = "x-queue-mode", value = "lazy") //这两个是固定的
))
public void listenLazyQueue(String msg){log.info("接收到 lazy.queue的消息:{}", msg);
}

开启持久化和生产者确认时,RabbitMQ只有在消息持久化完成后才会给生产者返回ACK回执

4.消费者的可靠性

        4-1:消费者确认机制

        消费者确认机制时为了确认消费者是否成功处理消息。当消费者处理消息结束后,应该向RabbitMQ发送一个回执,告知RabbitMQ自己消息的处理状态。状态有三种:

  • ack:成功的处理了消息,RabbitMQ队列中删除这个消息
  • nack:消息处理失败,RabbitMQ就会再次给消费者投递消息,持续投递
  • reject:消息处理失败,RabbitMQ队列中删除这个消息(一般是消息内容有问题,所以拒绝)

0bdc481054844c36b234f5020190e542.png

        SpringAMQP已经实现了消息确认功能。并允许我们通过配置文件选择ACK处理方式,有三种方式:

  • none:不处理。即消息投递给消费者后立刻ack,消息会立刻从MQ删除。非常不安全,不建议使用
  • manual:手动模式。需要自己在业务代码中调用api,发送ack或reject,存在业务入侵,但更灵活
  • auto:自动模式。SpringAMQP利用AOP对我们的消息处理逻辑做了环绕增强,当业务正常执行时则自动返回ack.当业务出现异常时,根据异常判断返回不同结果:
  1. 如果是业务异常,会自动返回nack
  2. 如果是消息处理或校验异常,自动返回reject

需要配置在消费的application.yaml中

spring:rabbitmq:listener:simple:acknowledge-mode: auto # 自动ack

4-2:失败重试机制

        SpringAMQP提供了消费者失败重试机制,在消费者出现异常时利用本地重试,而不是无限的requeue到mq。通过在消费者的application.yaml文件中添加配置来开启重试机制:

spring:rabbitmq:listener:  # 这里注意区别,发布者有个失败重连机制和这个配置很像simple:retry:enabled: true # 开启消费者失败重试initial-interval: 1000ms # 初识的失败等待时长为1秒multiplier: 1 # 失败的等待时长倍数,下次等待时长 = multiplier * last-intervalmax-attempts: 3 # 最大重试次数stateless: true # true无状态;false有状态。如果业务中包含事务,这里改为false

        在开启重试模式后,重试次数耗尽,如果消息依然失败,则需要有MessageRecoverer接口来处理,它包含三种不同的实现:

  • RejectAndDontRequeueRecoverer:重试耗尽后,直接reject,丢弃消息。默认是这种方式
  • ImmediateRequeueMessageRecoverer:重试耗尽后,返回nack,消息重新入队
  • RepublishMessageRecoverer:重试耗尽后,将失败消息投递到指定的交换机

第三种示例图

1d0061a9a9c04b3dae1fbf6915904e7c.png

1)在consumer服务中定义处理失败消息的交换机和队列

@Bean
public DirectExchange errorMessageExchange(){return new DirectExchange("error.direct");
}
@Bean
public Queue errorQueue(){return new Queue("error.queue", true);
}
@Bean
public Binding errorBinding(Queue errorQueue, DirectExchange errorMessageExchange){return BindingBuilder.bind(errorQueue).to(errorMessageExchange).with("error");
}

2)定义一个RepublishMessageRecoverer,关联队列和交换机

@Bean
public MessageRecoverer republishMessageRecoverer(RabbitTemplate rabbitTemplate){return new RepublishMessageRecoverer(rabbitTemplate, "error.direct", "error");
}

完整代码:

@Configuration
@ConditionalOnProperty(name = "spring.rabbitmq.listener.simple.retry.enabled", havingValue = "true")
public class ErrorMessageConfig {@Beanpublic DirectExchange errorMessageExchange(){return new DirectExchange("error.direct");}@Beanpublic Queue errorQueue(){return new Queue("error.queue", true);}@Beanpublic Binding errorBinding(Queue errorQueue, DirectExchange errorMessageExchange){return BindingBuilder.bind(errorQueue).to(errorMessageExchange).with("error");}@Beanpublic MessageRecoverer republishMessageRecoverer(RabbitTemplate rabbitTemplate){return new RepublishMessageRecoverer(rabbitTemplate, "error.direct", "error"); //第二个参数是routingKey}
}

4-3:幂等性业务

        在程序开发中,是指同一个业务,执行一次或多次对业务状态的运行是一致的。

 

        如果网络问题出现故障,有可能出现把一个业务做了多次,比如扣减库存,总不能扣减两次吧,于是可以采取对每一个消息指定一个消息id,id值唯一,然后执行完这个消息后,把这个消息id存到数据库里,然后每次执行消息的时候,可以去数据库查一下有没有这个消息,如果有,就代表这个消息之前执行过了,于是就不对这个消息做处理。

        在做注册消息转换器为bean的时候,可以设置消息的id,然后我们接受消息的时候用Message来接就可以

@Bean
public MessageConverter messageConverter(){// 1.定义消息转换器Jackson2JsonMessageConverter jjmc = new Jackson2JsonMessageConverter();// 2.配置自动创建消息id,用于识别不同消息,也可以在业务中基于ID判断是否是重复消息jjmc.setCreateMessageIds(true);return jjmc;
}

        用Message接,然后message.getMessageProperties().getMessageId() 获取id,那这个id做业务判断就可以了。

以上是对于非幂等业务的一种方案,但明显这种方案不太好。影响mq性能。

另一种就是基于具体业务逻辑来进行判断来实现业务的幂等,比如我在一个业务执行前,先判断这个业务的一个状态,如果状态以及修改过了,我直接不做处理就行了,如果没有,我在进行修改。

5.延迟消息

        5-1:死信交换机

当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter):

  • 消费者使用basic.rejectbasic.nack声明消费失败,并且消息的requeue参数设置为false

  • 消息是一个过期消息,超时无人消费

  • 要投递的队列消息满了,无法投递

        如果一个队列中的消息已经成为死信,并且这个队列通过dead-letter-exchange属性指定了一个交换机,那么队列中的死信就会投递到这个交换机中,而这个交换机就称为死信交换机(Dead Letter Exchange)。而此时加入有队列与死信交换机绑定,则最终死信就会被投递到这个队列中。

5ec9b7a546924919b0d7ac7fca942f88.png

死信交换机有什么作用呢?

  1. 收集那些因处理失败而被拒绝的消息

  2. 收集那些因队列满了而被拒绝的消息

  3. 收集因TTL(有效期)到期的消息

声明正常队列和正常交换机和的时候使用bean方式,因为正常队列要指定死信交换机,

 @Beanpublic Queue normalQueue(){return QueueBuilder.durable("normal.queue").deadLetterExchange("dlx.direct").build();}

发送者示例代码:给正常队列设置一个TTL,如果时间到了,把消息给死信交换机,模拟延迟消息

rabbitTemplate.convertAndSend("normal.direct", "hi", "hello", new MessagePostProcessor() {@Overridepublic Message postProcessMessage(Message message) throws AmqpException {message.getMessageProperties().setExpiration("1000000"); return message;}});

5-2:延迟消息插件

先去社区下载 https://blog.rabbitmq.com/posts/2015/04/scheduling-messages-with-rabbitmq

去查看RabbitMQ的插件目录对应的数据卷。

docker volume inspect mq-plugins

然后进入插件那么目录

docker exec -it mq rabbitmq-plugins enable rabbitmq_delayed_message_exchange

这样插件就装好了

然后声明一个延迟交换机,基于注解方式

@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "delay.queue", durable = "true"),exchange = @Exchange(name = "delay.direct", delayed = "true"),key = "delay"
))
public void listenDelayMessage(String msg){log.info("接收到delay.queue的延迟消息:{}", msg);
}

基于bean方式

@Bean
public DirectExchange delayExchange(){return ExchangeBuilder.directExchange("delay.direct") // 指定交换机类型和名称.delayed() // 设置delay的属性为true.durable(true) // 持久化.build();
}

发送延迟消息:

@Test
void testPublisherDelayMessage() {// 1.创建消息String message = "hello, delayed message";// 2.发送消息,利用消息后置处理器添加消息头rabbitTemplate.convertAndSend("delay.direct", "delay", message, new MessagePostProcessor() {@Overridepublic Message postProcessMessage(Message message) throws AmqpException {// 添加延迟消息属性message.getMessageProperties().setDelay(5000);return message;}});
}

注意:

延迟消息插件内部会维护一个本地数据库表,同时使用Elang Timers功能实现计时。如果消息的延迟时间设置较长,可能会导致堆积的延迟消息非常多,会带来较大的CPU开销,同时延迟消息的时间会存在误差。

因此,不建议设置延迟时间过长的延迟消息

 

相关文章:

RabbitMQ——消息的可靠性处理

1.业务分析 在业务的开发中&#xff0c;我们通常将业务的非核心业务交给MQ来处理&#xff0c;比如支付&#xff0c;在支付过后&#xff0c;我们需要扣减余额&#xff0c;修改支付单状态&#xff0c;修改订单状态&#xff0c;发送短信提醒用户&#xff0c;给用户增加积分等等&am…...

babylon.js-1:入门篇

最近项目中使用到了 Babylon.js 这门技术&#xff0c;从今天开始&#xff0c;抽取自己写的比较好的拿出来&#xff0c;作为分享案例&#xff1a; 记录学习成果通过笔记的方式记录技术积累方便工作中查找翻阅实现案例 是什么 Babylon.js是一个基于WebGL的开源3D渲染引擎&…...

VS Code调整字体大小

##在工程目录底下.vscode/settings.json添加设置参数 {"editor.fontSize": 15,"window.zoomLevel": 1.5 }...

Python基础语句教学

Python是一种高级的编程语言&#xff0c;由Guido van Rossum于1991年创建。它以简单易读的语法和强大的功能而闻名&#xff0c;被广泛用于科学计算、Web开发、数据分析等领域。 Python的应用领域广泛&#xff0c;可以用于开发桌面应用程序、Web应用、游戏、数据分析、人工智能等…...

ansible 配置

目录 1.集群自动化维护工具 ansible 2.ansible管理架构 3.安装ansible 4.Iventory主机模式 5.通过ping验证 6.ansible常用模块 7.命令行模块 7.1command模块 7.2shell模块 7.3scripts模块 7.4file模块 7.5copy模块​ 7.6yum模块 1.集群自动化维护工具 ansibl…...

堆排序算法详解:原理与Python实现

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storm…...

[论文阅读] ChartInstruct: Instruction Tuning for Chart Comprehension and Reasoning

原文链接&#xff1a;http://arxiv.org/abs/2403.09028 源码链接&#xff1a;https://github.com/vis-nlp/ChartInstruct 启发&#xff1a;本文构建的instruction-tuning数据集以及使用该数据集对模型进行微调的过程都值得学习。 Abstract 研究对象&#xff1a;图表 研究…...

基于springboot+vue学生宿舍管理系统设计与实现

博主介绍&#xff1a;专注于Java vue .net php phython 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟 我的博客空间发布了1000毕设题目 方便大家学习使用 感兴趣的…...

【Android】模糊搜索与数据处理

【Android】模糊搜索与数据处理 本篇博客主要以根据输入内容动态获取城市为例进行讲解。 获取城市 这一部分主要是根据输入的信息去动态获取城市信息 首先定义了一个名为 NetUtil 的类&#xff0c;主要用于通过 HTTP 请求获取城市信息。 public class NetUtil {private stat…...

机器学习-KNN

KNN&#xff1a;K最邻近算法&#xff08;K-Nearest Neighbor,KNN&#xff09; 用特征空间中距离待分类对象的最近的K个样例点的类别来预测。 投票法&#xff1a;K 个样例的对数类别。 k1:最近邻分类 k 通常是奇数&#xff08;因为我们根据这个K数据判断类别&#xff0c;如果…...

python 安装包 site-packages

1. site-packages 文件夹的位置 当我们通过 pip 或其他方式安装一个 Python 包时&#xff0c;这些包的文件就会被复制到 site-packages 文件夹下。 site-packages 文件夹通常位于 Python 的安装目录下的 Lib 文件夹内。具体的路径会根据你使用的操作系统和 Python 版本的不同而…...

大数据-151 Apache Druid 集群模式 配置启动【上篇】 超详细!

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…...

CentOS8.5.2111(3)实验之DHCP服务器架设

一、实验目标 1&#xff0e;掌握DHCP服务器的主配置文件各项申明参数及操作及其含义 2. 具备DHCP 服务器、中继服务器的配置能力 3. 具备测试客户端正常获取服务器分配地址的能力 4. 具备DHCP服务器故障排除能力 二、实训原理/流程 &#xff08;一&#xff09;项目背景 …...

机器学习(4):机器学习项目步骤(一)——定义问题

1. 机器学习项目的五大步骤 定义问题 收集数据和预处理 选择算法和确定模型 训练拟合模型 评估优化模型性能 2. 定义问题的主要任务 刨析业务场景&#xff0c;设定清晰目标&#xff0c;同时还要确定当前问题属于哪一种机器学习类型。 3. “易速鲜花”项目案例 项目任务&a…...

C#中Socket通信常用的方法

创建Socket 在C#中创建一个Socket对象的基本步骤如下&#xff1a; 引入命名空间&#xff1a; 首先&#xff0c;确保你的文件顶部包含了以下命名空间的引用&#xff1a; using System.Net; using System.Net.Sockets; 创建Socket实例&#xff1a; 你可以创建一个Socket实例&am…...

【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯&#xff0c;你们的点赞收藏是我前进最大的动力&#xff01;&#xff01;希望本文内容能够帮助到你&#xff01; 目录 一&#xff1a;单例模式&#xff08;singleton&#xff09; 1&#xff1a;概念 二&#xff1a;“饿汉模…...

huggingface实现中文文本分类

目录 1 自定义数据集 2 分词 2.1 重写collate_fn方法 3 用BertModel加载预训练模型 4 模型试算 5 定义下游任务 6 训练 7 测试 #导包 import torch from datasets import load_from_disk #用于加载本地磁盘的datasets文件 1 自定义数据集 #自定义数据集 #…...

基于python+控制台+txt文档实现学生成绩管理系统(含课程实训报告)

目录 第一章 需求分析 第二章 系统设计 2.1 系统功能结构 2.1.1 学生信息管理系统的七大模块 2.1.2 系统业务流程 2.2 系统开发必备环境 第三章 主函数设计 3.1 主函数界面运行效果图 3.2 主函数的业务流程 3.3 函数设计 第四章 详细设计及实现 4.1 学生信息录入模块的设计与实…...

Spring Boot 整合MyBatis-Plus 实现多层次树结构的异步加载功能

文章目录 1&#xff0c;前言2&#xff0c;什么是多层次树结构&#xff1f;3&#xff0c;异步加载的意义4&#xff0c;技术选型与实现思路5&#xff0c;具体案例5.1&#xff0c;项目结构5.2&#xff0c;项目配置&#xff08;pom.xml&#xff09;5.3&#xff0c;配置文件&#xf…...

网络工程师指南:防火墙配置与管理命令大全,零基础入门到精通,收藏这一篇就够了

本指南详细介绍了防火墙的配置与管理命令&#xff0c;涵盖了防火墙的工作原理、常见配置命令、安全策略与访问控制、日志管理与故障排查&#xff0c;并通过实战案例展示了如何有效防御网络攻击。通过学习本指南&#xff0c;网络工程师能够系统掌握防火墙的配置与管理技能&#…...

语音合成的性能巅峰:深度拆解 supertonic,构建极速、私有化的端侧多语言 TTS

发布日期&#xff1a; 2026-05-14标签&#xff1a; #TTS #ONNX #端侧AI #边缘计算 #supertonic #多语言语音合成一、 引言在实时交互应用中&#xff0c;语音合成&#xff08;TTS&#xff09;的延迟往往是决定用户体验的生死线。依赖云端 API 不仅面临网络波动的风险&#xff0c…...

Cursor Pro破解工具:5步实现永久免费使用的终极指南

Cursor Pro破解工具&#xff1a;5步实现永久免费使用的终极指南 【免费下载链接】cursor-free-vip [Support 0.45]&#xff08;Multi Language 多语言&#xff09;自动注册 Cursor Ai &#xff0c;自动重置机器ID &#xff0c; 免费升级使用Pro 功能: Youve reached your trial…...

如何通过Whisky在macOS上实现Windows程序无缝运行?4步技术实践指南

如何通过Whisky在macOS上实现Windows程序无缝运行&#xff1f;4步技术实践指南 【免费下载链接】Whisky A modern Wine wrapper for macOS built with SwiftUI 项目地址: https://gitcode.com/gh_mirrors/wh/Whisky 对于macOS开发者而言&#xff0c;运行Windows专用软件…...

耳机选购指南:从音质佩戴到无线降噪,构建你的场景化耳机衣橱

1. 耳机选购的底层逻辑&#xff1a;从“听个响”到“场景化生存”我家里有个抽屉&#xff0c;专门用来放耳机&#xff0c;数了数&#xff0c;不下十几副。从最早那副压箱底的Koss头戴式&#xff0c;到如今几乎长在耳朵上的AirPods Pro&#xff0c;每一副都对应着我生活里一个特…...

Claude推理接口低延迟优化秘技:FastAPI异步中间件+缓存穿透防护+请求批处理(仅限内部团队泄露版)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;Claude推理接口低延迟优化秘技&#xff1a;FastAPI异步中间件缓存穿透防护请求批处理&#xff08;仅限内部团队泄露版&#xff09; 核心瓶颈定位 Claude官方API在高并发场景下常出现P99延迟飙升至1.2…...

网盘下载提速终极指南:9大平台直链获取工具完整教程

网盘下载提速终极指南&#xff1a;9大平台直链获取工具完整教程 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云…...

收藏 | 从零开始学大模型:6个月完整开发路线图(附免费资源)

本文提供一份从Python基础到企业级大模型应用开发的6-8个月学习路线图&#xff0c;涵盖API调用、提示词工程、RAG知识库问答、Agent智能体开发及模型微调部署。结合近百份招聘需求及专家建议&#xff0c;适合初学者快速构建AI技能体系&#xff0c;附有前沿拓展方向与免费学习资…...

智能算法车队换道决策与轨迹规划【附仿真】

✨ 长期致力于车队换道、支持向量机、决策树、换道决策、多目标优化研究工作&#xff0c;擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流&#xff0c;点击《获取方式》 &#xff08;1&#xff09;NGSIM数据清洗与特征重构&#xf…...

从洗衣机到无人机:拆解霍尔传感器在BLDC电机中的“交通指挥”角色

从洗衣机到无人机&#xff1a;霍尔传感器如何成为BLDC电机的隐形指挥家 当清晨的洗衣机开始轻柔转动&#xff0c;或是无人机在天空划出精准轨迹时&#xff0c;很少有人会注意到这些设备内部藏着一个精密的"交通指挥系统"。这个系统的核心不是红绿灯&#xff0c;而是一…...

GeoJSON.io:3分钟创建专业地图,地理数据可视化从未如此简单

GeoJSON.io&#xff1a;3分钟创建专业地图&#xff0c;地理数据可视化从未如此简单 【免费下载链接】geojson.io A quick, simple tool for creating, viewing, and sharing spatial data 项目地址: https://gitcode.com/gh_mirrors/ge/geojson.io 你是否曾经需要在地图…...