Spring Cloud Stream - 构建高可靠消息驱动与事件溯源架构
一、引言
在分布式系统中,传统的 REST 调用模式往往导致耦合,难以满足高并发和异步解耦的需求。消息驱动架构(EDA, Event-Driven Architecture)通过异步通信、事件溯源等模式,提高了系统的扩展性与可观测性。
作为 Spring Cloud 生态的一部分,Spring Cloud Stream 抽象了不同消息中间件(如 Kafka、RabbitMQ)的底层差异,提供统一的编程模型,从而简化了微服务间的事件交互。本文将结合理论与实例,探讨 Spring Cloud Stream 的核心价值,具体包括:
• 高效解耦:通过声明式通道和 Binder 抽象,屏蔽底层中间件的复杂性。
• 状态可溯:通过事件日志驱动业务状态,确保数据一致性。
• 生产就绪:通过容错机制与治理策略,支持高可靠系统的落地。
二、消息驱动微服务模型
2.1 Spring Cloud Stream 架构与核心组件
Spring Cloud Stream 是 Spring Cloud 生态中消息中间件的抽象层,通过统一的编程模型屏蔽 Kafka、RabbitMQ 等中间件的实现差异,实现跨平台消息交互。
核心组件:
• Binder
作用:对接具体消息中间件(如 Kafka、RabbitMQ),提供统一的 API。
价值:开发者无需关注底层协议(如 AMQP、Kafka Protocol),通过配置切换中间件。
• Binding
作用:定义消息通道与中间件物理目标(如 Topic、Queue)的绑定规则。
配置示例:
spring.cloud.stream.bindings.outputChannel.destination=orders
• Message Channel
编程接口:通过@Input、@Output注解声明输入/输出通道。
示例:
public interface OrderChannels { @Output("order-events") MessageChannel orderOutput();
}
设计原则:
• 开箱即用:自动配置连接工厂、序列化器等基础设施。
• 扩展性:支持自定义 Binder 实现(如阿里云 RocketMQ)。
2.2 完整的消息驱动示例
生产者发送流程
消费者监听流程
完整代码结构参考
生产者项目
├── src/main/java
│ ├── com/example/producer
│ │ ├── MessageProducer.java
│ │ └── MyMessageChannels.java
│ └── resources/application.yml消费者项目
├── src/main/java
│ ├── com/example/consumer
│ │ ├── MessageConsumer.java
│ │ └── MyMessageChannels.java
│ └── resources/application.yml
完整示例步骤如下:
第1步:创建 Spring Boot 项目
使用 Spring Initializr 创建项目,选择依赖:
• 生产者项目:Spring Web,Spring Cloud Stream,Lombok
• 消费者项目:Spring Cloud Stream,Lombok
• 中间件支持:根据实际选择配置RabbitMQ或Kafka,本示例以RabbitMQ为例。
生成项目,下载并解压项目,相关依赖都在pom.xml中。
消费者项目中核心依赖示例:
<dependencies><!-- Web支持(用于创建REST接口) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 消息驱动核心 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-stream</artifactId></dependency><!-- 选择其中一个中间件依赖 --><!-- RabbitMQ --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-stream-binder-rabbit</artifactId></dependency><!-- 或 Kafka --><!--<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-stream-binder-kafka</artifactId></dependency>--><!-- 代码简化工具 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
</dependencies>
第2步:定义消息通道接口(生产者 & 消费者共用)
在两个项目的src/main/java下创建消息通道接口文件:
定义输出通道方法和输入通道方法。
public interface MyMessageChannels {//定义消息发送通道@Output("outputChannel") // 指定通道名称为 "outputChannel"MessageChannel outputChannel(); // 方法名也是 outputChannel(推荐但不强制)//定义消息接收通道@Input("inputChannel") // 指定通道名称为 "inputChannel"SubscribableChannel inputChannel(); // 方法名也是 inputChannel
}
注解解析:
• @Output(“outputChannel”):定义输出通道,用于消息生产者向outputChannel 通道发送消息。
• @Input(“inputChannel”):定于输入通道,用于消息消费者从inputChannel通道读取消息。
注解名称解析:
注解名称”outputChannel “ 与方法名(outputChannel)一致,是最佳实践,代码清晰易读。
如果修改方法名(但保持注解名称不变),代码依然有效。
情况1:通道名称以注解中的值为主,方法名可随意。
@Output("myCustomOutput") // 通道名称是 "myCustomOutput"
MessageChannel anyMethodName(); // 方法名随意
情况2:注解未指定名称,则通道名称默认取方法名(此时方法名必须有意义)。
@Output // 未指定名称,通道名称自动取方法名 "outputChannel"
MessageChannel outputChannel();
配置绑定的关键点
在配置文件(如 application.yml)中,绑定的是 注解中定义的通道名称,而不是方法名。具体可见下文 第5步示例。
第3步:实现消息生产者
在生产者项目中,创建控制器:
// MessageProducer.java
@RestController
@RequiredArgsConstructor
public class MessageProducer {// 自动注入通道private final MyMessageChannels channels;// 处理POST请求:/send?message=内容@PostMapping("/send")public String sendMessage(@RequestParam String message) {// 发送消息到outputChannel:// 1. channels.outputChannel() 获取输出通道对象// 2. MessageBuilder构建消息对象,withPayload设置消息内容// 3. 调用send()将消息发送到消息中间件channels.outputChannel().send(MessageBuilder.withPayload(message).build());//返回响应结果return "Message sent: " + message;}
}
注解解析:
@RestController:相当于@Controller + @ResponseBody。
• 表明该类是一个处理 Web 请求的控制器,其方法的返回数据会直接作为响应内容(非视图页面)。
@RequiredArgsConstructor:Lombok 注解。
• 自动生成构造器,用于注入final修饰的字段(例如:channels)。
代码解析:
• channels.outputChannel().send():将消息发送到outputChannel,RabbitMQ会将其存入主题(Topic)。
• MessageBuilder.withPayload(message).build():创建消息对象,将字符串message作为负载。
第4步:实现消息消费者
在消费者项目中,创建消息监听器:
@Service
@EnableBinding(MyMessageChannels.class) // 绑定消息通道
public class MessageConsumer {@StreamListener("inputChannel")public void handle(String message) {System.out.println("Received: " + message); // 消费并打印消息}
}
解析:
• @EnableBinding(MyMessageChannels.class):声明并绑定应用的消息通道,使 Spring Cloud Stream 自动配置与消息代理(如 Kafka/RabbitMQ)的连接。该注解仅负责通道的注册。
• 消息的接收与处理由@StreamListener或@RabbitListener等注解实现。
• @StreamListener(“inputChannel”):监听inputChannel,当有消息到达时触发handle方法。
第5步:配置绑定(关键步骤)
生产者配置文件
在生产者项目的src/main/resources/application.yml中添加如下配置:
spring:cloud:stream:bindings:outputChannel-out-0: # 对应注解中的名称,@Output("outputChannel")destination: demo-queue # 消息队列名称(RabbitMQ 自动创建)# 如果使用 RabbitMQ,需配置连接信息(默认连本地)rabbit:bindings:outputChannel-out-0:producer:exchangeType: direct # 交换机类型
消费者配置文件
spring:cloud:stream:bindings:inputChannel-in-0: # 对应注解中的名称@Input("inputChannel")destination: demo-queue # 必须与生产者的destination一致group: my-group # 消费者组(RabbitMQ中可选,Kafka必填)# RabbitMQ 连接配置(与生产者一致)rabbit:bindings:inputChannel-in-0:consumer:exchangeType: directdurableSubscription: true # 持久化订阅
第6步:运行与测试
1、 启动 RabbitMQ
本地安装 RabbitMQ或使用 Docker:
docker run -d -p 5672:5672 -p 15672:15672 rabbitmq:management
2、启动生产者应用
• 访问http://localhost:8080/send?message=Hello
• 预期响应:Message sent: Hello
3、启动消费者应用
• 控制台输出:[消费者] 收到消息:Hello
4、验证队列
• 访问RabbitMQ 管理界面:http://localhost:15672
• 查看Queues标签页,确认demo-queue.my-group队列已创建。
• 检查消息是否被消费(队列中的消息数应为 0)。
2.3 常见问题自查表
三、事件溯源与消息驱动的架构融合
3.1 事件溯源(Event Sourcing)模型
事件溯源是一种以不可变事件流为核心的数据持久化模式。所有系统状态变更均以事件(Event)形式按顺序记录在事件日志(Event Log)中,而非直接修改当前状态。每个事件代表一次原子性操作(如订单创建、账户扣款),通过事件回放可重建任意时间点的系统状态。
核心特性:
• 不可变性:事件一旦存储,不可修改或删除。
• 顺序性:事件按时间顺序持久化,形成完整的操作历史。
• 唯一事实源:系统的当前状态完全由事件日志推导得出。
类比:
• 传统数据库:直接覆盖银行账户余额(如余额从 1000 → 800,无法追溯原因)。
• 事件溯源:记录每笔交易事件(如“存款 +200”“转账 -400”),通过事件回放计算当前余额(1000 + 200 - 400 = 800)。
3.2 核心优势与应用场景
3.3 事件溯源与CQRS的协同设计
CQRS(命令查询职责分离)
核心思想:将系统的写操作(Command)与读操作(Query)分离,独立优化。
与事件溯源的协同
• 写模型(Command Side)
职责:生成事件并持久化到事件日志(如 Kafka)。
示例:创建订单时发布OrderCreatedEvent,而非直接更新数据库。
• 读模型(Query Side)
职责:从优化的读存储(如 Redis、Elasticsearch)获取数据。
示例:查询订单状态时直接从缓存读取,避免复杂的 JOIN 查询。
技术价值
• 性能优化:读写分离避免数据库锁竞争,提升吞吐量。
• 架构灵活性:读模型可针对业务需求独立扩展(如全文检索、聚合统计)。
3.4 Spring Cloud Stream 在事件驱动架构中的实践
核心作用:
作为事件驱动架构的传输层,Spring Cloud Stream 实现以下关键能力:
能力1:事件传输管道(事件分发与路由)
生产者:通过@Output通道发布事件,推送事件至消息代理(如 Kafka)。
消费者:通过@Input通道订阅事件,支持条件路由(如基于消息头过滤)。
示例场景:订单服务发布OrderCreatedEvent,库存服务、支付服务分别订阅并处理。
能力2:读写分离(CQRS)实现
写模型:生成事件并持久化至事件日志(如 Kafka)。
@RestController
public class OrderController { @PostMapping("/orders") public void createOrder() { channels.orderOutput().send(MessageBuilder.withPayload(event).build()); }
}
读模型:监听事件更新物化视图(如 Redis 缓存)。
@StreamListener("order-events")
public void updateOrderView(OrderCreatedEvent event) { redisTemplate.opsForValue().set(event.getOrderId(), event);
}
能力3:可靠性保障
• 顺序性:通过分区键(如orderId)保证同一实体事件顺序处理。
• 幂等性:结合 Redis 防重机制(见 4.2 节)。
• 容错:集成死信队列(DLQ)隔离异常消息(见 4.1 节)。
3.5 事件存储选型与全链路协作
事件存储模式选择
从事件生成到存储到消费的完整协作过程
sequenceDiagramparticipant CommandService as 命令服务(写模型)participant Kafka as 消息代理(Kafka)participant EventStore as 事件存储(数据库)participant QueryService as 查询服务(读模型)participant ReadDB as 读数据库(Redis)CommandService->>Kafka: 发送OrderCreatedEventKafka->>EventStore: 持久化事件日志Kafka->>QueryService: 推送事件QueryService->>ReadDB: 更新读模型(物化视图)QueryService-->>Client: 响应查询请求
核心角色:
• 命令服务(生产者):生成事件并发送到消息代理。
• 消息代理(如 Kafka):作为事件传输通道,负责分发事件。
• 事件存储(如 MongoDB):持久化事件日志,支持回放与查询。
• 查询服务(消费者):监听事件并更新读模型(如 Redis 缓存)。
3.6 事件溯源完整示例 (订单系统为例)
1)定义事件对象(核心数据结构)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderCreatedEvent {private String orderId; // 订单唯一标识private String product; // 商品名称private int quantity; // 购买数量
}
解析:
• OrderCreatedEvent:订单创建事件,包含orderId、product、quantity。
• @Data:Lombok 注解,自动生成类的所有 getter、setter等 方法。
• @AllArgsConstructor:Lombok 注解,自动生成一个包含所有字段的构造器。
• @NoArgsConstructor:Lombok 注解,自动生成一个无参构造器。
2)事件生产者(写模型:生成事件)
相关 MyMessageChannels 定义参见第二章2.2示例代码。
@RestController
@RequiredArgsConstructor
public class OrderController {private final MyMessageChannels channels; // 消息通道接口// 创建订单并发送事件@PostMapping("/createOrder")public String createOrder(@RequestParam String product, @RequestParam int quantity) {OrderCreatedEvent event = new OrderCreatedEvent(UUID.randomUUID().toString(), // 生成唯一订单IDproduct, quantity);// 发送事件到消息通道channels.outputChannel().send(MessageBuilder.withPayload(event).build());return "Order Created: " + event;}
}
解析:
• 生产者通过 HTTP 接口接收请求,构造OrderCreatedEvent事件,并发送到 Kafka 事件流(outputChannel)进行异步处理。
3)事件存储(持久化事件日志)
事件消费者(Event Store Service)
@EnableBinding(MyMessageChannels.class) // 绑定消息通道
public class EventStore {@StreamListener("inputChannel")public void storeEvent(OrderCreatedEvent event) {System.out.println("Storing Event: " + event);saveEventToDatabase(event); // 模拟事件存储}private void saveEventToDatabase(OrderCreatedEvent event) {// 实际场景:事件应存入数据库(如MySQL、MongoDB)}
}
解析:
• 消费者监听消息通道inputChannel的OrderCreatedEvent并存储,实现事件溯源。
• 事件存入数据库(如 MySQL、MongoDB),以支持历史回放和查询。
4)事件查询(读模型)
CQRS 模式下,读模型典型实现:
@RestController
@RequiredArgsConstructor
public class OrderQueryController {private final OrderRepository orderRepository; // 读数据库(如Redis)// 查询订单信息@GetMapping("/orders/{orderId}")public OrderView getOrder(@PathVariable String orderId) {return orderRepository.findById(orderId).orElseThrow(() -> new OrderNotFoundException("Order Not Found"));}
}
解析:
• OrderView存储在读数据库(如 Redis/Elasticsearch),保证高效查询。
• 采用事件驱动更新,每次OrderCreatedEvent发生时,通过监听事件更新OrderView读模型(如订单创建后更新 Redis 缓存)。
3.7 常见问题解答
Q1:事件存储和传统数据库有什么区别?
• 事件存储:仅追加(append-only)不可修改的事件日志,记录“发生了什么”。
• 传统数据库:直接修改当前状态,记录“现在是什么”。
Q2:CQRS 会增加系统复杂度吗?
• 初期:需要维护读写两套逻辑,有一定学习成本。
• 长期:提升扩展性和性能,适合高并发场景。
Q3:如何保证事件顺序?
• Kafka:通过分区键(如订单 ID)确保同一实体的事件顺序处理。
• 数据库:使用递增版本号或时间戳排序。
总结
事件溯源与消息驱动架构,通过不可变事件流与读写分离重塑了系统设计。
1.事件溯源:以事件日志为唯一事实源,支持历史回溯与状态重建,保障数据可靠性与审计能力。
2.CQRS协同:解耦命令与查询,写模型生成事件流,读模型通过缓存或搜索引擎优化响应效率。
3.消息驱动:基于Spring Cloud Stream实现异步事件传输,服务间解耦,适配高并发与分布式场景。
核心价值
• 技术侧:提升吞吐量、扩展性与容错能力。
• 业务侧:满足高频交易(如电商、金融)的合规需求,支持复杂业务链路追踪。
适用场景:适用于需高可靠性、实时响应及跨服务协作的系统,如:订单管理、实时计费等。
四、生产级消息治理
4.1 死信队列(DLQ)容错机制
死信队列(Dead Letter Queue, DLQ)
死信队列是消息系统中用于存储无法正常消费的消息的特殊队列。当消息因异常(如处理失败、超时、格式错误)无法被消费者正确处理时,系统自动将其转移到 DLQ,避免消息丢失或无限重试阻塞系统。
1.核心作用
• 容错处理:隔离异常消息,防止主业务队列被“毒丸消息”(Poison Pill)阻塞。
• 问题排查:集中存储失败消息,便于后续人工或自动分析原因。
• 重试机制:支持手动或自动从 DLQ 重新投递消息到主队列进行重试。
2.配置示例
在消费者应用程序的application.yml 中配置,定义消费失败的信息处理方法。
spring: cloud: stream: bindings: inputChannel: consumer: enable-dlq: true # 启用死信队列 dlq-name: my-dlq # 指定 DLQ 名称
解析:
• enable-dlq: true:开启 DLQ 功能,默认将失败消息发送到名为.dlq的队列。
• dlq-name: my-dlq:指定 DLQ 名称,覆盖默认命名规则。
3.应用场景
4.注意事项
• 监控 DLQ 堆积:需集成监控工具(如 Prometheus)告警 DLQ 消息量,避免积压。
• 死信处理策略:
• 人工介入:分析日志,修复代码后重投递。
• 自动重试:配置规则(如延迟重试、错误类型过滤)。
• 结合重试机制:设置合理的重试次数(如 3 次)后再进入 DLQ,减少无效处理。
总结
死信队列是消息系统的“安全网”,通过隔离异常消息保障系统健壮性,是生产环境中不可或缺的容错机制。
4.2 幂等性设计(基于 Redis)
通过 Redis 原子操作实现消息消费的幂等性,确保消息仅被处理一次,避免重复消费导致的数据不一致问题。
1.代码示例
@Component
@RequiredArgsConstructor
public class IdempotentConsumer { private final StringRedisTemplate redisTemplate; @StreamListener("inputChannel") public void processEvent(OrderCreatedEvent event) { // 生成唯一事件标识(基于业务唯一键,如订单ID) String eventId = "event:" + event.getOrderId(); // 原子性操作:尝试将事件ID存入Redis(仅当Key不存在时成功) Boolean isNew = redisTemplate.opsForValue() .setIfAbsent(eventId, "processed", Duration.ofMinutes(10)); if (Boolean.TRUE.equals(isNew)) { // 首次处理事件(执行业务逻辑) System.out.println("Processing event: " + event); } else { // 重复事件,跳过处理(记录日志或告警) System.out.println("Duplicate event ignored: " + event); } }
}
核心设计解析:
2.生产级优化建议
异常处理:
• Redis 操作失败:捕获RedisConnectionFailureException,结合重试机制或死信队列(DLQ)处理。
• 业务逻辑异常:删除 Redis Key 并重试,或标记为需人工干预。
性能优化:
• 集群模式:使用 Redis Cluster 提升可用性与扩展性。
• 本地缓存:结合本地缓存(如 Caffeine)减少 Redis 访问频率。
监控与告警:
• Redis Key 堆积:监控 Key 数量与内存占用,设置阈值告警。
• 重复事件频率:统计重复事件日志,分析系统瓶颈或攻击行为。
3.适用场景
• 支付回调:防止重复扣款或到账。
• 订单状态更新:避免多次触发发货、库存扣减。
• 事件溯源:确保事件回放时数据一致性。
总结
通过 Redis 的原子操作与唯一键设计,实现轻量级分布式幂等性控制。此方案兼顾简洁性与可靠性,适用于多数高并发场景,是消息驱动架构中保障数据一致性的核心手段之一。
4.3 监控与告警
指标采集:集成Prometheus监控消息吞吐量、延迟与错误率。
可视化看板:通过Grafana展示实时数据,设置阈值触发告警(如 DLQ 堆积超限)。
五、总结
5.1 核心重点
• 消息驱动架构:@Input/@Output 定义通道,Binder 抽象层简化消息传递与异步解耦。
• 事件溯源与 CQRS:事件日志驱动状态回溯,读写分离优化性能,确保一致性。
• 生产级治理:死信队列容错、幂等性防重、监控告警保障稳定性。
相关文章:
Spring Cloud Stream - 构建高可靠消息驱动与事件溯源架构
一、引言 在分布式系统中,传统的 REST 调用模式往往导致耦合,难以满足高并发和异步解耦的需求。消息驱动架构(EDA, Event-Driven Architecture)通过异步通信、事件溯源等模式,提高了系统的扩展性与可观测性。 作为 S…...
电脑如何录屏
以下是电脑录屏的常用方法总结,涵盖系统自带工具、第三方软件及进阶功能,结合不同场景需求推荐最佳方案: 一、系统自带工具 Xbox Game Bar(Windows 10/11) 操作步骤:按 WinG 打开游戏栏 → 点击录制按钮&am…...
【微知】plantuml在泳道图中如何将多个泳道框起来分组并且设置颜色?(box “浏览器“ #LightGreen endbox)
泳道分组并且着色 分组用 box和endbox ,颜色用#xxx,标注用"xxx" box "浏览器" #LightGreen participant "浏览器1" as Browser participant "浏览器2" as Browser2 endboxparticipant "服务端" as …...
c++ 中的可变参数模板与折叠表达式
c 11 引入了可变参数模板,c 17 引入了折叠表达式,比 c 语言的可变参数更加简洁灵活。这篇博客总结了一些例子。 …(省略号)用于可变参数(Variadic Arguments),它可以放在模板参数 或 函数参数的…...
websocket学习手册及python实现简单的聊天室
概述 WebSocket 是一种网络通信协议,允许在单个 TCP 连接上进行全双工通信。它最核心的优势就在于实现了持久连接,实现了实时的数据传输。HTTP 协议有一个很大的缺点,通信只能由客户端发起,服务器返回响应后连接就会关闭…...
论文阅读:2023-arxiv Can AI-Generated Text be Reliably Detected?
总目录 大模型安全相关研究:https://blog.csdn.net/WhiffeYF/article/details/142132328 文章目录 Abstract(摘要)1 Introduction(引言)Conclusion(结论) Can AI-Generated Text be Reliably D…...
Mock接口编写教程-axios-mock-adapter(React)
Mock模拟接口编写教程 直接在前端实现接口模拟 1.第一步 设置模拟接口 // mock.ts import axios from axios import MockAdapter from axios-mock-adapter// 创建一个模拟适配器 const mock new MockAdapter(axios)// 设置模拟接口 export const setupMock () > {mock.…...
react(一):特点-基本使用-JSX语法
初识React React是一个用于构建用户界面的 JavaScript 库,由 Facebook 开发和维护。 官网文档:React 官方中文文档 特点 1.声明式编程 2.组件化开发 3.多平台适配 开发依赖 开发React必须依赖三个库: 1.react:包含react所必…...
golang函数与方法的区别
1.调用方式的区别 函数的调用方式:函数名(参数...) 方法的调用方式: 变量.方法名(参数...) 2.函数的使用 package mainimport "fmt" //函数参数为值类型,调用的时候只能传递值类型数据&#…...
解决 openeuler 系统 docker 下载慢,docker 镜像加速
一、步骤说明 1. 编辑 Docker 配置文件 Docker 的镜像源配置文件路径为 /etc/docker/daemon.json。如果该文件不存在,则需要先创建目录和文件。 # 创建目录(如果不存在) sudo mkdir -p /etc/docker# 编辑配置文件(使用 nano 或…...
Android ARouter的详细使用指南
Android ARouter的详细使用指南。我需要先确定用户的基础,可能他们已经有Android开发经验,但对ARouter不太熟悉。首先,我应该介绍ARouter是什么,解决什么问题,比如模块化中的页面跳转问题。然后,需要分步骤…...
PosterRender 实现微信下程序 分享商品生成海报
PosterRender 是什么 PosterRender 是一种专注于生成高质量海报图像的技术或工具,常用于生成静态图片,特别是适合用于营销、宣传和展示的图形设计。它通常用于在服务端或客户端渲染复杂的图像,包括文字、图形、图标、背景等,生成…...
电机控制常见面试问题(十五)
文章目录 一、电机气隙二、电气时间三.电机三环控制详解四.驱动板跳线意义五.电机开环自检 一、电机气隙 电机气隙是定子和转子之间的空隙,防止钉子转子运转时物理接触,此外,气隙是磁路的重要环节,磁场需通过气隙传递能量&#x…...
基于云漂移优化(Cloud Drift Optimization,CDO)算法的多个无人机协同路径规划(可以自定义无人机数量及起始点),MATLAB代码
一、云漂移优化算法 云漂移优化(Cloud Drift Optimization,CDO)算法是2025年提出的一种受自然现象启发的元启发式算法,它模拟云在大气中漂移的动态行为来解决复杂的优化问题。云在大气中受到各种大气力的影响,其粒子的…...
【第9章】亿级电商平台订单系统-整体技术架构设计
1-1 本章导学 课程主题:系统蓝图描绘与整体技术架构设计核心学习内容: ▶️ 订单系统的整体技术架构设计 ▶️ 架构设计核心方法论与实践应用本章核心内容架构 1. 技术预研 架构设计的基础支撑环节关键技术可行性分析与选型依据2. 整体技术架构设计方法与步骤 结构化设计方法…...
harmonyOS NEXT开发与前端开发深度对比分析
文章目录 1. 技术体系概览1.1 技术栈对比1.2 生态对比 2. 开发范式比较2.1 鸿蒙开发范式2.2 前端开发范式 3. 框架特性对比3.1 鸿蒙 Next 框架特性3.2 前端框架特性 4. 性能优化对比4.1 鸿蒙性能优化4.2 前端性能优化 5. 开发工具对比5.1 鸿蒙开发工具5.2 前端开发工具 6. 学习…...
详细介绍GetDlgItem()
书籍:《Visual C 2017从入门到精通》的2.3.8 Win32控件编程 环境:visual studio 2022 内容:【例2.31】在模态对话框上可视化创建树形控件 说明:以下内容大部分来自腾讯元宝。 GetDlgItem() 是 Windows API 中用于获取对话框或父…...
MCU的应用场景:从智能家居到工业控制
MCU的应用场景非常广泛,主要包括以下几个方面: 1. 智能家居 智能照明:通过MCU控制LED灯的亮度和颜色。 智能安防:在安防系统中,MCU用于控制传感器和报警器。 2. 工业控制 PLC(可编程逻辑控制器&…...
docker的使用
时间:2025.3.17 一、当我们想要运行一个容器时,不是在containers处,而是需要在images处找对应容器的镜像 操作步骤: 1.找容器镜像 2.找到容器镜像,通过pull下载到当前主机中 3.下载成功后进行运行 4.运行时的容器镜像…...
Redis hyperloglog学习
背景知识 【伯努利试验】: 【伯努利试验】是一个概率论中的概念,指在相同的条件下重复进行n次独立的试验,每次试验只有两种可能的结果,且这两种结果发生的概率是固定的 抛硬币作为伯努利试验:在抛硬币时,我…...
鸿蒙开发:什么是ArkTs?
前言 本文基于Api13。 一句话解读:ArkTs(方舟编程语言)是目前HarmonyOs应用开发的主力语言。 用官方的话解读,它是一种为构建高性能应用而设计的编程语言;看到以Ts结尾,想必大家应该很容易想到TypeScript&a…...
ArcGIS Pro中加载在线地图的详细指南
在现代制图领域,ArcGIS Pro已成为专业人士的重要工具。它不仅功能强大,而且操作简便,为用户提供了丰富的地图数据资源和灵活的地图加载方式。其中,加载在线地图是ArcGIS Pro的一大特色功能,能够帮助用户快速获取全球范…...
《C++ Primer》学习笔记(四)
第四部分:高级主题 1.tuple 是类似pair的模板。每个pair 的成员类型都不相同,但每个 pair 都恰好有两个成员。每个确定的tuple 类型的成员数目是固定的,但一个 tuple 可以有任意数量的成员。tuple支持的操作如下图: 只有两个 tup…...
CVPR2025自动驾驶端到端前沿论文汇总
自动驾驶 文章目录 自动驾驶前言自动驾驶的轨迹预测论文端到端自动驾驶论文 前言 汇总CVPR2025自动驾驶前沿论文 自动驾驶的轨迹预测论文 Leveraging SD Map to Augment HD Map-based Trajectory PredictionModeSeq: Taming Sparse Multimodal Motion Prediction with Seque…...
使用 jQuery 实现子窗口获取父窗口的值,或者父窗口获取子窗口的值时
HTML 父子窗口通信指南 一、基础概念 在Web开发中,父子窗口通信是一个常见的需求。这通常发生在以下场景: 主页面(父窗口)打开新窗口(子窗口)弹出窗口需要与主页面交互多窗口之间需要数据传递 二、jQue…...
AndroidStudio下载安装,环境部署以及常见问题解决教程(亲测)
AndroidStudio下载安装,环境部署以及常见问题解决!!! 文章目录 前言 一、Android Studio 下载与安装 1.1 系统要求 1.2 下载 Android Studio 1.3 安装 Android Studio Windows 系统 1.4 初始配置 二、环境部署 2.1 安装 …...
ruoyi-vue部署2
3.Node.js 3.1.什么是Node.js 在 Node.js 之前,JavaScript 只能运行在浏览器中,作为网页脚本使用,为网页添加一些特效,或者和服务器进行通信。有了 Node.js 以后,JavaScript 就可以脱离浏览器,像其它编程…...
Flutter项目升级Xcode 16.2之后编译问题
最近好久没升级Xcode了,升级了一下最新的16.2之后。发现Flutter项目在iOS设备上运行不起来了。报错: 查了许多网友也遇到了,其中一个解决方案:https://stackoverflow.com/questions/79118572/xcode-16-and-ios-18-project-not-com…...
Mermaid 子图 + 拖拽缩放:让流程图支持无限细节展示
在技术文档、项目管理和可视化分析中,流程图是传递复杂逻辑的核心工具。传统流程图往往静态且难以适应细节展示,而 Mermaid 与 svg-pan-zoom 的结合,则为这一痛点提供了完美解决方案。本文将深入解析如何通过 Mermaid 的子图(subg…...
前沿科技一览未来发展趋势
生物技术能帮环境。比如用它处理污染物。科学家发现一些细菌能吃掉油污。这些细菌能被用来清理漏油事故。比如1989年埃克森瓦尔迪兹号漏油事件中人们就用类似方法减少污染。 还有些植物能吸收土壤里的重金属。种植这种植物能让受污染的土地变干净。这种方法在矿区周围特别有用…...
Linux---sqlite3数据库
一、数据库分类 1. 按数据关系分类 类型特点代表产品关系型数据库- 使用 SQL(结构化查询语言)<br>- 数据以行列形式存储,支持事务和复杂查询MySQL、Oracle、SQLite非关系型数据库- 无固定表结构(如键值对、文档、图&#…...
侯捷 C++ 课程学习笔记:进阶语法之lambda表达式(二)
侯捷 C 课程学习笔记:进阶语法之lambda表达式(二) 一、捕获范围界定 1. 局部变量与函数参数 非静态局部变量:Lambda 所在作用域内定义的局部变量(如函数内部的 int x)会被完整复制其当前值。捕获后外部变…...
python爬虫Scrapy(6)之增量式
增量式 爬虫应用场景分类 通用爬虫聚焦爬虫功能爬虫分布式爬虫增量式: 用来监测网站数据更新的情况(爬取网站最新更新出来的数据)。只是一种程序设计的思路,使用什么技术都是可以实现的。核心: 去重。 使用一个记录表来…...
oracle删除表中重复数据
需求: 删除wfd_procs_nodes_rwk表中,huser_id、dnode_id、rwk_name字段值相同的记录,如果有多条,只保留一条。 SQL: DELETE FROM wfd_procs_nodes_rwk t WHERE t.rowid > (SELECT MIN(t1.rowid)FROM wfd_procs_n…...
动作捕捉手套如何让虚拟现实人机交互 “触手可及”?
在虚拟与现实逐渐交融的当下,动作捕捉技术正以前所未有的速度革新着多个领域。 动作捕捉技术,简称“动捕”,已经从早期的影视特效制作,逐步拓展到游戏开发、虚拟现实、机器人控制等多个领域。 而mHandPrO数据手套作为这一领域的…...
【大模型基础_毛玉仁】2.3 基于 Encoder-only 架构的大语言模型
更多内容:XiaoJ的知识星球 目录 2.3 基于Encoder-only 架构的大语言模型2.3.1 Encoder-only 架构2.3.2 BERT 语言模型1)BERT 模型结构2)BERT 预训练方式3)BERT 下游任务 2.3.3 BERT 衍生语言模型1)RoBERTa 语言模型2&a…...
C# ManualResetEvent的高级用法
一、ManualResetEvent 的核心作用 ManualResetEvent 是 C# 中用于 线程同步 的类(位于 System.Threading 命名空间),通过信号机制控制线程的等待与执行。其核心功能包括: 阻塞线程:调用 WaitOne() 的线程会等…...
Language Models are Few-Shot Learners,GPT-3详细讲解
GPT的训练范式:预训练Fine-Tuning GPT2的训练范式:预训练Prompt predict (zero-shot learning) GPT3的训练范式:预训练Prompt predict (few-shot learning) GPT2的性能太差,新意高&…...
js 给元素添加点击事件的方法
在 JavaScript 里,为元素添加点击事件有多种方法,下面为你介绍三种常见的方式。 1. 使用内联事件处理程序 你可以在 HTML 标签里直接使用 onclick 属性添加点击事件。示例如下: <!DOCTYPE html> <html lang"en"><…...
Linux环境使用jmeter做性能测试
一、安装JDK,版本jdk1.8 1、下载压缩包到/jdk目录下解压 cd /jdk tar -zxvf jdk-8u241-linux-64.tar.gz 2、配置环境变量 在profile文件中末尾新增信息如下所示 vim /etc/profile export JAVA_HOME/usr/local/java/jdk/jdk1.8.0_221 export PATH$PATH:$JAVA_HOM…...
联想台式电脑启动项没有U盘
开机按F12,进入启动设备菜单,发现这里没有识别到插在主机的U盘? 解决方法 1、选上图的Enter Setup或者开机按F2,进入BIOS设置 选择Startup -> Primary Boot Sequence 2、选中“Excludeed from boot order”中U盘所在的一行 …...
单片机开发资源分析的实战——以STM32F103C8T6为例子的单片机资源分析
目录 第一点:为什么叫STM32F103C8T6 从资源手册拿到我们的对STM32F103C8T6的资源描述 第二件事情,关心我们的GPIO引脚输出 第三件事情:去找对应外设的说明部分 前言 本文章隶属于项目: Charliechen114514/BetterATK: This is…...
Error response from daemon: Get “https://registry-1.docker.io/v2/“: net/http: request canceled while
英俊潇洒很有才,美丽端庄又大方的人已经点赞收藏+关注了 文章目录 1.ubuntu解决方案2.Windows的解决办法(有威劈恩好搞)3.其他报错json格式错误下载的镜像有问题 最后 1.ubuntu解决方案 报错如图:timeout Error response from da…...
yolo模型学习笔记——1——物体检测评估指标
1.置信度 表示模型预测的边界框中存在目标物体的概率以及反应预测框和真实框的定位质量 2.阈值 (1)定义 决定一个预测框是否被视为为正类的关键参数,通过调整不同的阈值,获得不同的精度和召回率。yolo模型会为每个预测框生成一个置信度分数,…...
Elasticsearch 滚动索引(Rollover Index)详解
文章目录 1、滚动索引的作用2、滚动索引的用法2.1 核心概念2.2 实现步骤 3、适用场景4、与其他技术的结合使用5、案例:日志数据的滚动索引5.1 场景描述5.2 实现步骤 6、示例:结合索引生命周期管理(ILM)6.1 场景描述6.2 实现步骤 7…...
保持docker内容器一直运行
首先:确保Docker服务配置为开机自启,这样当虚拟机启动时,Docker也会启动,并按照设定的重启策略自动启动相关容器。 sudo systemctl enable docker 创建容器时: 当你使用docker run命令启动容器时,可以添…...
ChatBI 的技术演进与实践挑战:衡石科技如何通过 DeepSeek 实现商业落地
随着人工智能技术的快速发展,ChatBI(基于自然语言交互的商业智能)逐渐成为企业数据分析领域的热门话题。作为 BI(商业智能)领域的新形态,ChatBI 通过自然语言处理(NLP)技术ÿ…...
python-leetcode 55.子集
题目: 给定一个数组nums,数组中的元素互不相同,返回该数组所有可能子集(幂集) 解集不能包含重复的子集,可以按任意顺序返回解集 方法一:迭代法实现子集枚举 记原序列中元素的总数为 n,原序列…...
在LORA训练中,LORA模型的矩阵的行列是多少
在LORA训练中,LORA模型的矩阵的行列是多少: W n e w = W + α r B A W_{new}=W + \frac{\alpha}{r}BA...
冒泡排序:古老算法中的智慧启示
在计算机科学浩瀚的星空中,排序算法犹如璀璨的星辰,而冒泡排序恰似其中最朴实无华的一颗。这个诞生于计算机发展初期的经典算法,以其简单直观的逻辑原理,成为每个程序员启蒙阶段必经的试炼场。当我们凝视这个看似笨拙的排序方法时…...