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:事件日志驱动状态回溯,读写分离优化性能,确保一致性。

• 生产级治理:死信队列容错、幂等性防重、监控告警保障稳定性。

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

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

相关文章

Houdini制作非均匀细分的柱体

近期看见一非均匀细分的做法&#xff0c;觉得不错将其拆开以笔记分享。效果如下&#xff1a; 1.创建Geometry节点&#xff0c;并在该节点内部创建line节点样条线&#xff0c;设置合适长度并添加resample节点。 2.此时若无法看见顶点与顶点编号显示&#xff0c;可按快捷键D&am…

C# Unity 唐老狮 No.10 模拟面试题

本文章不作任何商业用途 仅作学习与交流 安利唐老狮与其他老师合作的网站,内有大量免费资源和优质付费资源,我入门就是看唐老师的课程 打好坚实的基础非常非常重要: Unity课程 - 游习堂 - 唐老狮创立的游戏开发在线学习平台 - Powered By EduSoho C# 1. 内存中&#xff0c;堆和…

Nuxt2 vue 给特定的页面 body 设置 background 不影响其他页面

首先认识一下 BODY_ATTRS 他可以在页面单独设置 head () {return {bodyAttrs: {form: form-body}};},设置完效果是只有这个页面会加上 接下来在APP.vue中添加样式

拥抱健康养生,开启活力生活

在快节奏的现代社会&#xff0c;健康养生不再是一句口号&#xff0c;而是我们对高品质生活的追求。它贯穿于日常的点点滴滴&#xff0c;对我们的身心状态有着深远影响。 饮食养生是基础。秉持均衡原则&#xff0c;每日的餐盘应是色彩斑斓的。新鲜蔬菜富含维生素与膳食纤维&…

Excel(函数篇):COUNTIF与CONUTIFS函数、SUMIF与SUMIFS函数、ROUND函数、MATCH与INDEX函数、混合引用与条件格式

目录 COUNTIF和COUNTIFS函数COUNTIF函数COUNTIFS函数SUMIF和SUMIFS函数SUMIF函数SUMIFS函数SUMIFS函数与控件实现动态年月汇总ROUND、ROUNDUP、ROUNDDOWN函数单元格混合引用条件格式与公式,标记整行数据MATCH和INDEX函数COUNTIF和COUNTIFS函数 COUNTIF函数 统计下“苏州”出现…

深入了解Linux —— git三板斧

版本控制器git 为了我们方便管理不同版本的文件&#xff0c;就有了版本控制器&#xff1b; 所谓的版本控制器&#xff0c;就是能够了解到一个文件的历史记录&#xff08;修改记录&#xff09;&#xff1b;简单来说就是记录每一次的改动和版本迭代的一个管理系统&#xff0c;同…

笔记本电脑关不了机是怎么回事 这有解决方法

在快节奏的现代生活中&#xff0c;笔记本电脑已成为我们工作、学习和娱乐的得力助手。在使用电脑的过程中&#xff0c;笔记本电脑突然关不了机了&#xff0c;怎么回事&#xff1f;下面驱动人生就来讲一讲笔记本电脑不能正常关机的解决方法&#xff0c;有需要的可以来看看。 一、…

Unity打包的WebGL包打不开问题解决方案,以及WebGL包嵌入至Vue2中的步骤

问题描述 在做项目时&#xff0c;需要将Unity做出的场景与Vue2结合&#xff0c;遇到了一些问题&#xff0c;在网上搜了很多解决方案&#xff0c;最终根据下面这篇博客的内容成功解决。解决方案 https://blog.csdn.net/m0_56308072/article/details/135502566注意事项 &#xff…

TW-SOA中的ASE:建模和实验

----翻译自G. Talli , M.J. Adams于2003年发表的论文 摘要 我们提出了一个行波半导体光放大器 &#xff08;TW-SOA&#xff09; 中放大自发辐射 &#xff08;ASE&#xff09; 的模型。所提出的模型考虑了整个 ASE 频谱的传播&#xff0c;还考虑了信号和 ASE 引起的饱和效应。使…

AI编程方法案例:PageRank算法实现

一、算法简单说明 PageRank算法是一种常见的网络权值迭代算法&#xff0c;主要用于诸如互联网网页的质量测度。基本计算原理是根据网页自身的链出将原始权值进行扩散&#xff0c;并通过多轮迭代获得稳定的收敛值来表征网页自身的最终权值。基本计算公式为&#xff1a; 其中R(u…

基于香橙派 KunpengPro学习CANN(3)——pytorch 模型迁移

通用模型迁移适配可以分为四个阶段&#xff1a;迁移分析、迁移适配、精度调试与性能调优。 迁移分析 迁移支持度分析&#xff1a; 准备NPU环境&#xff0c;获取模型的源码、权重和数据集等文件&#xff1b;使用迁移分析工具采集目标网络中的模型/算子清单&#xff0c;识别第三方…

Docker和containerd之概览(Overview of Docker and Containerd)

Docker和containerd之概览 容器本质上就是一个进程。 Namespace是一种逻辑分组机制&#xff0c;允许您将集群资源划分为独立的虚拟环境。每个 Namespace 为资源提供了一个范围&#xff0c;使得不同的团队、应用程序或环境可以在同一集群中共存&#xff0c;而不会相互干扰。 C…

使用OBS进行webRTC推流参考

参考腾讯云官方文档&#xff1a; 云直播 OBS WebRTC 推流_腾讯云 说明非常详细&#xff0c;分为通过WHIP和OBS插件的形式进行推流。 注意&#xff1a;通过OBS插件的形式进行推流需要使用较低的版本&#xff0c;文档里有说明&#xff0c;需要仔细阅读。

荣耀手机卸载应用商店、快应用中心等系统自带的

1.下载abd ADB Download - Get the latest version of ADB and fastboot 2.手机打开开发者选项 3.手机接电脑打开USB调试 4.下载MT管理器查看系统包名 D:\1.LFD\ADB\platform-tools-latest-windows\platform-tools>adb shell adb.exe: no devices/emulators found 这边是…

奇安信全流量(天眼)面试题

一、全流量设备&#xff08;天眼&#xff09;的部署架构 天眼系统采用旁路部署模式&#xff0c;通过流量镜像实现非侵入式监测&#xff0c;核心组件包括流量传感器、分析平台和文件威胁鉴定器&#xff0c;具体部署架构如下&#xff1a; 传感器部署 关键节点覆盖&#xff1a;在…

angular中的路由传参

目录 一、矩阵参数 一、矩阵参数 在angular中传参时可以使用矩阵参数&#xff0c;即直接通过变量值的形式在地址中体现&#xff0c;但需要注意参数的使用范围为当前路径段&#xff0c;而不是全局的查询参数。 const params {name: lhhh,age: 18,list: [{ name: htt }],}; //先…

设计模式(创建型)-抽象工厂模式

摘要 在软件开发的复杂世界中,设计模式作为解决常见问题的最佳实践方案,一直扮演着至关重要的角色。抽象工厂模式,作为一种强大的创建型设计模式,在处理创建一系列或相关依赖对象的场景时,展现出了独特的优势和灵活性。它通过提供一个创建对象的接口,让开发者能够在不指定…

从Excel到搭贝的转变过程

从Excel到搭贝 1. 简介 1.1 Excel简介 Excel 作为元老级的数据管理工具&#xff0c;功能强大且被广泛使用&#xff0c;但在现代工作场景中仍存在一些局限性&#xff0c;例如&#xff1a; 数据量处理有限&#xff1a;处理大规模数据时&#xff0c;Excel可能运行缓慢或崩溃。…

Text-to-SQL将自然语言转换为数据库查询语句

有关Text-To-SQL方法&#xff0c;可以查阅我的另一篇文章&#xff0c;Text-to-SQL方法研究 直接与数据库对话-text2sql Text2sql就是把文本转换为sql语言&#xff0c;这段时间公司有这方面的需求&#xff0c;调研了一下市面上text2sql的方法&#xff0c;比如阿里的Chat2DB,麻…

MFC开发:图形的绘制

文章目录 一、获取指定窗口的设备上下文二、画笔的介绍和使用三、绘制直线四、画刷的介绍和使用五、绘制扇形六、绘制圆形七、绘制文本 一、获取指定窗口的设备上下文 1.GetDC()函数的作用 GetDC() 是 Windows API 中的一个函数&#xff0c;它用于获取指定窗口的设备上下文&am…