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.pswp.cn/web/72385.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/72385.shtml
英文地址,請注明出處:http://en.pswp.cn/web/72385.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

王者榮耀道具頁面爬蟲(json格式數據)

首先這個和英雄頁面是不一樣的&#xff0c;英雄頁面的圖片鏈接是直接放在源代碼里面的&#xff0c;直接就可以請求到&#xff0c;但是這個源代碼里面是沒有的 雖然在檢查頁面能夠搜索到&#xff0c;但是應該是動態加載的&#xff0c;源碼中搜不到該鏈接 然后就去看看是不是某…

【一起來學kubernetes】12、k8s中的Endpoint詳解

一、Endpoint的定義與作用二、Endpoint的創建與管理三、Endpoint的查看與組成四、EndpointSlice五、Endpoint的使用場景六、Endpoint與Service的關系1、定義與功能2、創建與管理3、關系與交互4、使用場景與特點 七、Endpoint的kubectl命令1. 查看Endpoint2. 創建Endpoint3. 編輯…

結構型模式之橋接模式:解耦抽象和實現

在面向對象設計中&#xff0c;我們經常遇到需要擴展某些功能&#xff0c;但又不能修改現有代碼的情況。為了避免繼承帶來的復雜性和維護難度&#xff0c;橋接模式&#xff08;Bridge Pattern&#xff09;應運而生。橋接模式是一種結構型設計模式&#xff0c;旨在解耦抽象部分和…

如何用Java將實體類轉換為JSON并輸出到控制臺?

在軟件開發的過程中&#xff0c;Java是一種廣泛使用的編程語言&#xff0c;而在眾多應用中&#xff0c;數據的傳輸和存儲經常需要使用JSON格式。JSON&#xff08;JavaScript Object Notation&#xff09;是一種輕量級的數據交換格式&#xff0c;易于人類閱讀和編寫&#xff0c;…

Vue3 開發的 VSCode 插件

1. Volar Vue3 正式版發布&#xff0c;Vue 團隊官方推薦 Volar 插件來代替 Vetur 插件&#xff0c;不僅支持 Vue3 語言高亮、語法檢測&#xff0c;還支持 TypeScript 和基于 vue-tsc 的類型檢查功能。 2. Vue VSCode Snippets 為開發者提供最簡單快速的生成 Vue 代碼片段的方…

C# Enumerable類 之 集合操作

總目錄 前言 在 C# 中&#xff0c;System.Linq.Enumerable 類是 LINQ&#xff08;Language Integrated Query&#xff09;的核心組成部分&#xff0c;它提供了一系列靜態方法&#xff0c;用于操作實現了 IEnumerable 接口的集合。通過這些方法&#xff0c;我們可以輕松地對集合…

51c自動駕駛~合集54

我自己的原文哦~ https://blog.51cto.com/whaosoft/13517811 #Chameleon 快慢雙系統&#xff01;清華&博世最新&#xff1a;無需訓練即可解決復雜道路拓撲 在自動駕駛技術中&#xff0c;車道拓撲提取是實現無地圖導航的核心任務之一。它要求系統不僅能檢測出車道和交…

Spring Cloud Eureka - 高可用服務注冊與發現解決方案

在微服務架構中&#xff0c;服務注冊與發現是確保系統動態擴展和高效通信的關鍵。Eureka 作為 Spring Cloud 生態的核心組件&#xff0c;不僅提供去中心化的服務治理能力&#xff0c;還通過自我保護、健康檢查等機制提升系統的穩定性&#xff0c;使其成為微服務架構中的重要支撐…

Unity屏幕適配——立項時設置

項目類型&#xff1a;2D游戲、豎屏、URP 其他類型&#xff0c;部分原理類似。 1、確定設計分辨率&#xff1a;750*1334 為什么是它&#xff1f; 因為它是 iphone8 的尺寸&#xff0c;寬高比適中。 方便后續適配到真機的 “更長屏” 或 “更寬屏” 2、在場景…

深度學習中LayerNorm與RMSNorm對比

LayerNorm不同于BatchNorm&#xff0c;其與batch大小無關&#xff0c;均值和方差 在 每個樣本的特征維度 C 內計算&#xff0c; 適用于 變長輸入&#xff08;如 NLP 任務中的 Transformer&#xff09; 詳細的BatchNorm在之前的一篇文章進行了詳細的介紹&#xff1a;深度學習中B…

使用WireShark解密https流量

概述 https協議是在http協議的基礎上&#xff0c;使用TLS協議對http數據進行了加密&#xff0c;使得網絡通信更加安全。一般情況下&#xff0c;使用WireShark抓取的https流量&#xff0c;數據都是加密的&#xff0c;無法直接查看。但是可以通過以下兩種方法&#xff0c;解密抓…

數字化轉型 - 數據驅動

數字化轉型 一、 數據驅動1.1 監控1.2 分析1.3 挖掘1.4 賦能 二、數據驅動案例2.1 能源工業互聯網&#xff1a;綠色節能的數字化路徑2.2 光伏產業的數字化升級2.3 數據中心的綠色轉型2.4云遷移的質效優化2.5 企業數字化運營的實踐2.6數字化轉型的最佳實踐 一、 數據驅動 從數…

解決 Docker 鏡像拉取超時問題:配置國內鏡像源

在使用 Docker 的過程中&#xff0c;經常會遇到鏡像拉取超時的問題&#xff0c;尤其是在國內網絡環境下。這不僅會浪費大量的時間&#xff0c;還可能導致一些項目無法順利進行。今天&#xff0c;我將分享一個簡單而有效的解決方法&#xff1a;配置國內鏡像源。 環境 操作系統 c…

Linux命令基礎,創建,輸入,輸出,查看,查詢

什么是命令、命令行 命令行&#xff1a;即&#xff1a;Linux終端&#xff08;Terminal&#xff09;&#xff0c;是一種命令提示符頁面。以純“字符”的形式操作操作系統&#xff0c;可以使用各種字符化命令對操作系統發出操作指令。 命令&#xff1a;即Linux程序。一個命令就…

【GNU Radio】ZMQ模塊學習

【GNU Radio】ZMQ模塊學習 ZMQ 介紹前置知識Socket通信模型PUB/SUB&#xff08;發布/訂閱&#xff09;模型PUSH/PULL&#xff08;推/拉&#xff09;模型REQ/REP&#xff08;請求/響應&#xff09;模型 ZMQ 詳解基于通信模型分析基于數據格式分析Data BlocksMessage Blocks ZMQ …

【筆記】深度學習模型訓練的 GPU 內存優化之旅:綜述篇

開設此專題&#xff0c;目的一是梳理文獻&#xff0c;目的二是分享知識。因為筆者讀研期間的研究方向是單卡上的顯存優化&#xff0c;所以最初思考的專題名稱是“顯存突圍&#xff1a;深度學習模型訓練的 GPU 內存優化之旅”&#xff0c;英文縮寫是 “MLSys_GPU_Memory_Opt”。…

Vue 3 Diff 算法深度解析:與 Vue 2 雙端比對對比

文章目錄 1. 核心算法概述1.1 Vue 2 雙端比對算法1.2 Vue 3 快速 Diff 算法 2. 算法復雜度分析2.1 時間復雜度對比2.2 空間復雜度對比 3. 核心實現解析3.1 Vue 2 雙端比對代碼3.2 Vue 3 快速 Diff 代碼 4. 性能優化分析4.1 性能測試數據4.2 內存使用對比 5. 使用場景分析5.1 Vu…

神經網絡的基本知識

感知機 輸入&#xff1a;來自其他 n 個神經元傳遞過來的輸入信號 處理&#xff1a;輸入信號通過帶權重的連接進行傳遞, 神經元接受到總輸入值將與神經元的閾值進行比較 輸出&#xff1a;通過激活函數的處理以得到輸出 感知機由兩層神經元組成, 輸入層接受外界輸入信號傳遞給…

UE5與U3D引擎對比分析

Unreal Engine 5&#xff08;UE5&#xff09;和Unity 3D&#xff08;U3D&#xff09;是兩款主流的游戲引擎&#xff0c;適用于不同類型的項目開發。以下是它們的主要區別&#xff0c;分點整理&#xff1a; 1. 核心定位 UE5&#xff1a; 主打3A級高畫質項目&#xff08;如主機/P…

C++相關基礎概念之入門講解(上)

1. 命名空間 C中的命名空間&#xff08;namespace&#xff09;是用來避免命名沖突問題的一種機制。通過將類、函數、變量等封裝在命名空間中&#xff0c;可以避免不同部分的代碼中出現相同名稱的沖突。在C中&#xff0c;可以使用namespace關鍵字來定義命名空間。 然后我們在調…