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

MessageQueue --- RabbitMQ

MessageQueue --- RabbitMQ

  • RabbitMQ Intro
  • RabbitMQ 核心概念
  • RabbitMQ 分发类型
  • Dead letter (死信)
  • 保证消息的可靠传递

RabbitMQ Intro

  • 2007年发布,是一个在AMQP(高级消息队列协议)基础上完成的,可复用的企业消息系统,是当前最主流的消息中间件之一。
  • 低延迟:RabbitMQ 提供了低延迟的消息传递,可以在毫秒级别内将消息从生产者传递到消费者。
  • 高吞吐量:RabbitMQ 能够处理大量的消息并实现高吞吐量。它使用多线程和预取机制来提高消息处理的效率。
  • 可扩展性:RabbitMQ 可以通过水平扩展来处理更多的消息流量。可以通过添加更多的节点、使用集群和队列分区等方式来扩展 RabbitMQ。
  • 持久化支持:RabbitMQ 支持将消息和队列持久化到磁盘,以确保消息的可靠性和持久性。这意味着即使在 RabbitMQ 重启后,消息仍然可以保留,不会丢失。
  • 多种消息传递模式:RabbitMQ 支持多种消息传递模式,如点对点、发布/订阅和请求/响应等。这使得 RabbitMQ 在各种场景下都能够灵活应用。
  • 负载均衡:RabbitMQ 提供了负载均衡机制,可以将消息均衡地分发给多个消费者,以实现更好的资源利用和处理能力。
  • 可靠性保证:通过使用确认机制、持久化和事务等特性,RabbitMQ 提供了可靠性保证,确保消息的可靠传递和处理。

RabbitMQ 核心概念

在这里插入图片描述
消息的路由过程如下:

  • 生产者发布消息时,将消息和指定的 Routing Key 一起发送到交换机。
  • 交换机根据 Binding Key 和 Routing Key 的匹配规则,将消息路由到一个或多个绑定的队列。
  • 绑定 Key 和 Routing Key 的匹配规则可以根据交换机的类型而有所不同。
  • 在直接交换机(Direct Exchange)中,Binding Key 必须与 Routing Key 完全匹配。
  • 在主题交换机(Topic Exchange)中,Binding Key 与 Routing Key 使用通配符进行模式匹配。
  • 在扇形交换机(Fanout Exchange)中,Binding Key 不起作用,消息会被广播到所有绑定的队列。
  • Routing Key(路由键):
  • Routing Key 是在消息发布时与消息一起发送的属性。
  • 在发布消息时,生产者可以指定一个 Routing Key,用于描述消息的特性或目标。
  • Routing Key 可以是任意的字符串,通常是由一些特定的标识符或关键词组成,以便用于消息的过滤和路由。
  • Binding Key(绑定键):
  • Binding Key 是用于绑定队列和交换机的属性。
  • 在 RabbitMQ 中,通过创建绑定(Binding)将队列和交换机关联起来,以便消息能够正确地路由到队列。
  • 绑定是基于 Binding Key 进行的,它定义了交换机将消息路由到哪些队列。
  • Binding Key 可以是一个或多个单词组成的字符串,也可以是符号“#”和“*”的组合,用于匹配 Routing Key。

名词解释:

  • 生产者(Producer):发送消息的应用。
  • 消费者(Consumer):接收消息的应用。
  • 队列(Queue):存储消息的缓存。
  • 消息(Message):由生产者通过RabbitMQ发送给消费者的信息。
  • 连接(Connection):连接RabbitMQ和应用服务器的TCP连接。
  • 信道(Channel):连接里的一个虚拟通道,通过消息队列发送或者接收消息时,都是通过信道进行的。
  • 交换机(Exchange):交换机负责从生产者那里接收消息,并根据交换类型分发到对应的消息队列里。
  • 代理(Broker):接收和分发消息的应用,RabbitMQ Server就是Message Broker。
  • 虚拟主机(Virtual host):出于多租户和安全因素设计的,把AMQP的基本组件划分到一个虚拟的分组中,类似于网络中的namespace概念。当多个不同的用户使用同一个RabbitMQ server提供的服务时,可以划分出多个vhost,每个用户在自己的vhost创建exchange/queue 等.
  • Example:每个环境配置一个virtual host

RabbitMQ 分发类型

Direct Exchange

  • Direct exchange使用完全匹配的方式进行消息路由
  • 当一个消息发送到Direct exchange时,它会将消息的路由键与绑定到交换机上的队列的绑定键(binding key)进行比较。如果路由键与某个队列的绑定键完全匹配,那么该消息将被路由到该队列

在这里插入图片描述

  • exchange :pdf_events
    Queue A:create_pdf_queue
    交换机(pdf_events)和队列 A(create_pdf_queue)之间的绑定键:pdf_create
  • exchange :pdf_events
    Queue B:pdf_log_queue
    交换机(pdf_events)和队列 B(pdf_log_queue)之间的绑定键:pdf_log
  • 示例:
  • 例如,一个带有routing key为 pdf_log 的消息被发送到交换机 pdf_events
  • 该消息会被路由到 pdf_log_queue,因为routing key(pdf_log)与binding key(pdf_log)匹配
  • 如果消息的路由键与任何绑定键都不匹配,那么该消息将被丢弃。

Topic Exchange

  • 在 Topic Exchange 中,消息的路由键和绑定键都使用通配符来进行匹配。路由键是消息的属性,而绑定键是在创建绑定时指定的。通配符可以帮助实现更灵活的消息路由,使得消息可以根据特定的模式进行匹配和分发。
  • 通配符符号:
  • *(星号):表示匹配一个单词(单词由点号分隔)
  • #(井号):表示匹配零个或多个单词(单词由点号分隔)

在这里插入图片描述

  • Consumer A is interested in all the agreements in Berlin.
  • Exchange: agreements
  • Queue A name: berlin_agreements
  • Binding key: agreements.eu.berlin.#
  • Example of message routing key that matches:
  • agreements.eu.berlin
  • agreements.eu.berlin.store
  • Consumer B is interested in all the agreements.
  • Exchange: agreements
  • Queue B name: all_agreements
  • Binding key: agreements.#
  • Example of message routing key that matches:
  • agreements.eu.berlin
  • agreements.us
  • Consumer C is interested in all agreements for European head stores.
  • Exchange: agreements
  • Queue C name: store_agreements
  • binding key: agreements.eu.*.store
  • Example of message routing keys that will match:
  • agreements.eu.berlin.store
  • agreements.eu.stockholm.store

Fanout exchange

  • Fanout Exchange(广播交换机)是 RabbitMQ 中的一种交换机类型。它的工作原理是将消息广播到与之绑定的所有队列,无论绑定键的匹配情况如何。
  • Fanout Exchange 不关心消息的路由键,它会简单地将收到的消息复制并发送到所有与之绑定的队列

在这里插入图片描述

Header exchange

  • Header Exchange(头交换机)是 RabbitMQ 中的一种交换机类型。它使用消息的头部属性(Header)来匹配与之绑定的队列,而不依赖于路由键或绑定键。
  • 在 Header Exchange 中,消息的头部属性是消息的一部分,它包含了一组键值对,用于描述消息的特征和属性。与其他类型的交换机不同,Header Exchange 不关心消息的路由键,而是根据消息头部属性的匹配情况来确定消息的路由。
  • 绑定到 Header Exchange 的队列可以定义一个或多个匹配规则,这些规则由键值对的匹配条件组成。当消息的头部属性与队列的匹配规则完全匹配时,消息会被路由到对应的队列。

在这里插入图片描述

  • Message 1 is published to the exchange with header arguments (key = value): “format = pdf”, “type = report”.
  • Message 1 is delivered to Queue A because all key/value pairs match, and Queue B since “format = pdf” is a match (binding rule set to “x-match =any”).
  • Message 2 is published to the exchange with header arguments of (key = value): “format = pdf”.
  • Message 2 is only delivered to Queue B. Because the binding of Queue A requires both “format = pdf” and “type = report” while Queue B is configured to match any key-value pair (x-match = any) as long as either “format = pdf” or “type = log” is present.
  • Message 3 is published to the exchange with header arguments of (key = value): “format = zip”, “type = log”.
  • Message 3 is delivered to Queue B since its binding indicates that it accepts messages with the key-value pair “type = log”, it doesn’t mind that “format = zip” since “x-match = any”.
  • Queue C doesn’t receive any of the messages since its binding is configured to match all of the headers (“x-match = all”) with “format = zip”, “type = pdf”. No message in this example lives up to these criterias.
  • It’s worth noting that in a header exchange, the actual order of the key-value pairs in the message is irrelevant.

配置RabbitMQ 示例代码

import com.rabbitmq.client.*;import java.io.IOException;
import java.nio.charset.StandardCharsets;public class DirectExchangeExample {private static final String EXCHANGE_NAME = "direct_logs";private static final String QUEUE_NAME = "my_queue";private static final String ROUTING_KEY = "info";public static void main(String[] args) throws Exception {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");try (Connection connection = factory.newConnection();Channel channel = connection.createChannel()) {// 声明一个 Direct Exchangechannel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);// 声明一个队列channel.queueDeclare(QUEUE_NAME, false, false, false, null);// 绑定队列到 Direct Exchange,并指定绑定键channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY);// 定义消息处理函数DeliverCallback deliverCallback = (consumerTag, delivery) -> {String message = new String(delivery.getBody(), StandardCharsets.UTF_8);System.out.println("Received message: " + message);};// 消费消息channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});System.out.println("Press any key to exit.");System.in.read();}}
}

Dead letter (死信)

  • 死信(Dead Letter)是指在消息队列中无法被正常消费和处理的消息。当消息满足一定的条件时,它们可以被标记为死信并被发送到专门的死信队列中,以便进一步处理或分析
  • 死信来源
  • 消息 TTL 过期
  • 队列达到最大长度(队列满了,无法再添加数据到 mq 中)
  • 消息被拒绝(basic.reject 或 basic.nack)并且 requeue=false(不再重新入队)
  • 死信队列(Dead Letter Queue)是一个特殊的队列,用于接收死信消息。一旦消息被发送到死信队列,就可以根据需要进行进一步的处理,例如重新投递、持久化、记录日志或者进行分析。
  • 使用死信机制的好处包括:
  • 错误处理:当消息无法被正常处理时,可以将其发送到死信队列,以便进一步处理错误情况,例如记录日志或者通知管理员。
  • 重试机制:如果消息在一定时间内未能被消费成功,可以将其发送到死信队列,并设置重试策略,例如延时重试或者指数退避重试。
  • 延迟消息:通过结合延迟队列和死信队列,可以实现延迟消息的功能。当消息的延迟时间到达时,将其发送到死信队列,然后再从死信队列中重新投递到目标队列,实现延迟消息的效果。

在这里插入图片描述

import com.rabbitmq.client.*;import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;public class DeadLetterExample {private static final String EXCHANGE_NAME = "normal_exchange";private static final String QUEUE_NAME = "normal_queue";private static final String DLX_EXCHANGE_NAME = "dlx_exchange";private static final String DLX_QUEUE_NAME = "dlx_queue";private static final String DLX_ROUTING_KEY = "dlx_routing_key";public static void main(String[] args) throws Exception {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");try (Connection connection = factory.newConnection();Channel channel = connection.createChannel()) {// 创建普通交换机和队列channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);channel.queueDeclare(QUEUE_NAME, false, false, false, null);channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");// 创建死信交换机和队列channel.exchangeDeclare(DLX_EXCHANGE_NAME, BuiltinExchangeType.DIRECT);channel.queueDeclare(DLX_QUEUE_NAME, false, false, false, null);channel.queueBind(DLX_QUEUE_NAME, DLX_EXCHANGE_NAME, DLX_ROUTING_KEY);// 设置普通队列的死信参数Map<String, Object> arguments = new HashMap<>();arguments.put("x-dead-letter-exchange", DLX_EXCHANGE_NAME);arguments.put("x-dead-letter-routing-key", DLX_ROUTING_KEY);channel.queueDeclare(QUEUE_NAME, false, false, false, arguments);// 定义消息处理函数DeliverCallback deliverCallback = (consumerTag, delivery) -> {String message = new String(delivery.getBody(), StandardCharsets.UTF_8);System.out.println("Received message: " + message);// 手动确认消息channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);};// 消费消息channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> {});System.out.println("Press any key to exit.");System.in.read();}}
}

保证消息的可靠传递

要确保消息的可靠传递,可以采取以下几个步骤:

  • 持久化消息:将消息和队列都设置为持久化。这样,在 RabbitMQ 重启后,持久化的队列和消息会被恢复,避免消息丢失。可以在消息的发布端设置消息的持久化属性,以及在队列声明时设置队列的持久化属性。
  • 使用确认机制(Acknowledgement):在消费者处理消息后,发送确认消息给 RabbitMQ,告知消息已经成功处理。RabbitMQ 收到确认后才会将消息从队列中删除,确保消息不会丢失。确认机制可以通过在消费者端手动发送确认消息(basicAck)或使用自动确认模式(autoAck)来实现。
  • 使用发布者确认(Publisher Confirms):在消息的发布端启用发布者确认模式。通过将 confirm.select 设置为 true,可以让发布者等待 RabbitMQ 发送确认消息,表示消息已经成功到达交换机。如果没有收到确认消息,发布者可以选择重新发送消息,确保消息的可靠传递。
  • 设置合适的消息 TTL(Time-to-Live):可以为消息设置 TTL,即消息的存活时间。如果消息在指定的时间内没有被消费,RabbitMQ 可以将其标记为过期并进行相应的处理,例如发送到死信队列或丢弃。
  • 使用事务(Transactions):可以通过开启事务来确保消息的可靠传递。在事务中,可以将消息的发布和确认操作包裹在一个事务中,如果事务提交成功,表示消息已经成功到达 RabbitMQ,否则可以进行回滚。
  • 备份交换机(Alternate Exchange):可以配置备份交换机,当消息无法路由到指定的交换机时,它将被发送到备份交换机,从而避免消息丢失。
  • 监控和错误处理:建立监控机制,定期检查消息队列的状态,以及消费者的消费情况。在出现错误或异常情况时,根据具体情况进行错误处理,例如重试发送消息、记录日志、发送警报等。

发布者确认机制Example

import com.rabbitmq.client.*;import java.io.IOException;
import java.util.concurrent.TimeoutException;public class ReliableMessagingExample {private static final String QUEUE_NAME = "my_queue";private static final String EXCHANGE_NAME = "my_exchange";private static final String ROUTING_KEY = "my_routing_key";public static void main(String[] args) throws IOException, TimeoutException {// 创建连接和信道ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");Connection connection = factory.newConnection();Channel channel = connection.createChannel();// 声明队列和交换机channel.queueDeclare(QUEUE_NAME, true, false, false, null);channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY);// 启用发布者确认模式channel.confirmSelect();// 添加发布者确认监听器channel.addConfirmListener(new ConfirmListener() {@Overridepublic void handleAck(long deliveryTag, boolean multiple) throws IOException {System.out.println("Message confirmed, delivery tag: " + deliveryTag);}@Overridepublic void handleNack(long deliveryTag, boolean multiple) throws IOException {System.out.println("Message not confirmed, delivery tag: " + deliveryTag);// 可以在这里进行相应的处理,例如重新发送消息}});// 发布消息String message = "Hello, RabbitMQ!";channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());try {// 等待发布者确认channel.waitForConfirmsOrDie();} catch (InterruptedException e) {// 可以在这里进行相应的处理,例如重新发送消息e.printStackTrace();}// 关闭信道和连接channel.close();connection.close();}
}

事务保证消息可靠性Example

import com.rabbitmq.client.*;import java.io.IOException;
import java.util.concurrent.TimeoutException;public class ReliableMessagingExample {private static final String QUEUE_NAME = "my_queue";private static final String EXCHANGE_NAME = "my_exchange";private static final String ROUTING_KEY = "my_routing_key";public static void main(String[] args) throws IOException, TimeoutException {// 创建连接和信道ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");Connection connection = factory.newConnection();Channel channel = connection.createChannel();try {// 开启事务channel.txSelect();// 声明队列和交换机channel.queueDeclare(QUEUE_NAME, true, false, false, null);channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY);// 发布消息String message = "Hello, RabbitMQ!";channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());// 提交事务channel.txCommit();System.out.println("Transaction committed successfully.");} catch (IOException e) {// 发生异常,回滚事务channel.txRollback();System.out.println("Transaction rolled back due to an exception.");e.printStackTrace();} finally {// 关闭信道和连接channel.close();connection.close();}}
}

相关文章:

MessageQueue --- RabbitMQ

MessageQueue --- RabbitMQ RabbitMQ IntroRabbitMQ 核心概念RabbitMQ 分发类型Dead letter (死信)保证消息的可靠传递 RabbitMQ Intro 2007年发布&#xff0c;是一个在AMQP&#xff08;高级消息队列协议&#xff09;基础上完成的&#xff0c;可复用的企业消息系统&#xff0c;…...

WordPress作者页面链接的用户名自动变成16位字符串串插件Smart User Slug Hider

WordPress默认的作者页面URL链接地址格式为“你的域名/author/admin”&#xff0c;其中admin就是你的用户名&#xff0c;这样的话就会暴露我们的用户名。 为了解决这个问题&#xff0c;前面boke112百科跟大家分享了『如何将WordPress作者存档链接中的用户名改为昵称或ID』一文…...

Nvidia 携手 RTX 推出的本地运行 AI 聊天机器人

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

年假作业day2

1.打印字母图形 #include<stdio.h> #include<string.h> int main(int argc, const char *argv[]) { int i,j; char k; for(i1;i<7;i) { for(j1;j<i;j) { printf("%c",_); } for(j0,…...

HTML-多媒体嵌入-MDN文档学习笔记

HTML-多媒体与嵌入 查看更多学习笔记&#xff1a;GitHub&#xff1a;LoveEmiliaForever MDN中文官网 HTML-中的图片 将图片放入网页 可以使用<img/>来将图片嵌入网页&#xff0c;它是一个空元素&#xff0c;最少只需src属性即可工作 <img src"图片链接"…...

openJudge | 距离排序 C语言

总时间限制: 1000ms 内存限制: 65536kB 描述 给出三维空间中的n个点&#xff08;不超过10个&#xff09;,求出n个点两两之间的距离,并按距离由大到小依次输出两个点的坐标及它们之间的距离。 输入 输入包括两行&#xff0c;第一行包含一个整数n表示点的个数&#xff0c;第二…...

【教程】MySQL数据库学习笔记(三)——数据定义语言DDL(持续更新)

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【MySQL数据库学习】系列文章 第一章 《认识与环境搭建》 第二章 《数据类型》 第三章 《数据定义语言DDL》 文章目录 【MyS…...

[leetcode]买卖股票的最佳时机 (动态规划)

121. 买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从…...

隐函数的求导【高数笔记】

1. 什么是隐函数&#xff1f; 2. 隐函数的做题步骤&#xff1f; 3. 隐函数中的复合函数求解法&#xff0c;与求导中复合函数求解法有什么不同&#xff1f; 4. 隐函数求导的过程中需要注意什么&#xff1f;...

SG3225EEN晶体振荡器规格书

SG3225EEN 晶振是EPSON/爱普生的一款额定频率25 MHz至500 MHz的石英晶体振荡器&#xff0c;6脚贴片&#xff0c;LV-PECL输出&#xff0c;3225封装常规有源晶振&#xff0c;具有小尺寸&#xff0c;轻薄型&#xff0c;高稳定性&#xff0c;低相位抖动&#xff0c;低电源电压&…...

ESP8266 常用AT指令

一、ESP8266的AT指令要点、常见错误 AT指令要大写;以"\r\n"作结尾;串口通信&#xff0c;115200-None-8-1;支持2.4G频段&#xff0c;不支持5G频段 &#xff08;如果用手机创建热点&#xff0c;注意选择2.4G&#xff09;不支持中文的wifi名称工作模式&#xff0c;上电…...

esbuild 构建工具为什么很快?

esbuild 构建工具之所以很快&#xff0c;主要有以下几个原因&#xff1a; Go语言编写&#xff1a;esbuild 是用 Go 语言编写的&#xff0c;Go 语言以其高效的并发模型和编译速度而闻名。与一些其他构建工具相比&#xff0c;Go 语言在并发处理和内存管理方面表现出色&#xff0c…...

解决vscode报错,在赋值前使用了变量“XXX“

问题&#xff1a;如图所示 解决方法&#xff1a; 法一&#xff1a; 补全函数使其完整 法二&#xff1a; 使用断言...

python自动定时任务schedule库的使用方法

当你需要在 Python 中定期执行任务时&#xff0c;schedule 库是一个非常实用的工具。它可以帮助你自动化定时任务。以下是一些使用示例&#xff1a; 基本使用&#xff1a; import schedule import timedef job():print("Im working...")schedule.every(10).minutes.d…...

用机器学习方法重构期货商品板块

用机器学习方法重构期货商品板块 阿岛格 参考专栏:低门槛搭建个人量化平台 https://www.zhihu.com/column/c_1441014235068944386 摘 要 金融市场商品期货的板块分类,通常根据不同交易所、监管机构和证券商标准,按照期货标的属性、或产业链关系等进行分类,各自分类略有差…...

51单片机项目(29)——基于51单片机的避障跟随小车

1.功能设计 按键模式&#xff1a;按下按键&#xff0c;小车可以前后左右地运动 自动模式&#xff1a;根据红外传感器的状态&#xff0c;自行决定运动状态。检测到前方有物体时&#xff0c;车子移动&#xff0c;起到一个跟随的效果。 演示视频如下&#xff1a; 51单片机智能避障…...

人工智能学习与实训笔记(六):百度飞桨套件使用方法

目录 八、百度飞桨套件使用 8.1 飞桨预训练模型套件PaddleHub 8.1.1 一些本机CPU可运行的飞桨预训练简单模型&#xff08;亲测可用&#xff09; 8.1.1.1 人脸检测模型 8.1.1.2 中文分词模型 8.1.2 预训练模型Fine-tune 8.2 飞桨开发套件 8.2.1 PaddleSeg - 图像分割 8…...

Linux第一个小程序-进度条

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、回车和换行 二、行缓冲区概念 三、倒计时 四、进度条代码 版本一&#xff1a; ​编辑 版本二&#xff1a; 总结 前言 世上有两种耀眼的光芒&#xff0c;一…...

YoloV8改进策略:Block改进|Mamba-UNet改进YoloV8,打造全新的Yolo-Mamba网络

摘要 本文尝试使用Mamba的VSSBlock替换YoloV8的Bottleneck,打造最新的Yolo-Mamba网络。 论文:《Mamba-UNet:用于医学图像分割的类似UNet的纯视觉Mamba网络》 在医学图像分析的最新进展中,卷积神经网络(CNN)和视觉转换器(ViT)都取得了显著的基准成绩。前者通过其卷积…...

数据分析基础之《pandas(8)—综合案例》

一、需求 1、现在我们有一组从2006年到2016年1000部最流行的电影数据 数据来源&#xff1a;https://www.kaggle.com/damianpanek/sunday-eda/data 2、问题1 想知道这些电影数据中评分的平均分&#xff0c;导演的人数等信息&#xff0c;我们应该怎么获取&#xff1f; 3、问题…...

锁的艺术:深入浅出讲解乐观锁与悲观锁

在多线程和分布式系统中&#xff0c;数据一致性是一个核心问题。锁机制作为解决并发冲突的重要手段&#xff0c;被广泛应用于各种场景。乐观锁和悲观锁是两种常见的锁策略&#xff0c;它们在设计理念、实现方式和适用场景上各有特点。本文将深入探讨乐观锁和悲观锁的原理、实现…...

PL/SQLDeveloper中数值类型字段查询后显示为科学计数法的处理方式

PL/SQLDeveloper中数值类型字段查询后显示为科学计数法的处理方式 文章目录 PL/SQLDeveloper中数值类型字段查询后显示为科学计数法的处理方式1. 查询效果2. 处理方式3. 再次查询 1. 查询效果 2. 处理方式 3. 再次查询...

数据库同步是什么意思?数据库架构有哪些?

目录 一、数据库同步是什么 &#xff08;一&#xff09;基本概念 &#xff08;二&#xff09;数据库同步的类型 &#xff08;三&#xff09;数据库同步的实现方式 二、数据库架构的类型 &#xff08;一&#xff09;单机架构 &#xff08;二&#xff09;主从复制架构 &a…...

鸿蒙图片缓存(一)

移动端开发过程中图片缓存功能是必备&#xff0c;iOS和安卓都有相关工具库&#xff0c;鸿蒙系统组件本身也自带缓存功能&#xff0c;但是遇到复杂得逻辑功能还是需要封装图片缓存工具。 系统组件Image 1. Image的缓存策略 Image模块提供了三级Cache机制&#xff0c;解码后内…...

“一代更比一代强”:现代 RAG 架构的演进之路

编者按&#xff1a; 我们今天为大家带来的文章&#xff0c;作者的观点是&#xff1a;RAG 技术的演进是一个从简单到复杂、从 Naive 到 Agentic 的系统性优化过程&#xff0c;每一次优化都是在试图解决无数企业落地大语言模型应用时出现的痛点问题。 文章首先剖析 Naive RAG 的基…...

JVM 内存溢出 详解

内存溢出 内存溢出指的是内存中某一块区域的使用量超过了允许使用的最大值&#xff0c;从而使用内存时因空间不足而失败&#xff0c;虚拟机一般会抛出指定的错误。 在Java虚拟机中&#xff0c;只有程序计数器不会出现内存溢出的情况&#xff0c;因为每个线程的程序计数器只保…...

场景题-3

如何实现一个消息队列 拆解分析主流的几种消息队列 1、基本架构 生产者Producer、消费者Consumer、Broker&#xff1a;生产者发送消息&#xff0c;消费者接受消息&#xff0c;Broker是服务端&#xff0c;处理消息的存储、备份、删除和消费关系的维护。 主题和分区&#xff…...

固态继电器与驱动隔离器:电力系统的守护者

在电力系统中&#xff0c; 固态继电器合驱动隔离器像两位“电力守护神”&#xff0c;默默地确保电力设备的安全与稳定运行。它们通过高效、可靠的性能&#xff0c;保障了电力设备在各种环境下的正常工作。 固态继电器是电力控制中的关键组成部分&#xff0c;利用半导体器件来实…...

11.MySQL事务管理详解

MySQL事务管理详解 文章目录 MySQL事务管理 事务的概念 事务的版本支持 事务的提交方式 事务的相关演示 事务的隔离级别 查看与设置隔离级别 读未提交&#xff08;Read Uncommitted&#xff09; 读提交&#xff08;Read Committed&#xff09; 可重复读&#xff08;Repeatabl…...

Google机器学习实践指南(机器学习模型泛化能力)

&#x1f525; Google机器学习(14)-机器学习模型泛化能力解析 Google机器学习(14)-机器学习模型泛化原理与优化&#xff08;约10分钟&#xff09; 一、泛化问题引入 ▲ 模型表现对比&#xff1a; 假设森林中树木健康状况预测模型&#xff1a; 图1&#xff1a;初始模型表现 …...