【Fifty Project - D35】

今日完成記錄

TimePlan完成情況
7:00 - 7:40爬坡
8:30 - 11:30Rabbit MQ
17:30 - 18:30羽毛球

RabbitMQ

消費者端如何保證可靠性?

  • 消息投遞過程出現網絡故障
  • 消費者接收到消息但是突然宕機未消費消息
  • 消費者接收到消息后處理不當拋出異常
  • 。。。

消費者確認機制

Consumer Acknowledgement:消費者處理消息結束應該給MQ發送一個回執,告知自己的消息處理狀態:ack【成功處理消息,MQ從隊列中刪除消息】nack【消息處理失敗,MQ需要重新推送消息】reject【消息處理失敗并拒絕該消息,MQ從隊列刪除消息】

springAMQP提供了三種ACK處理方式:

  • none:不處理,消息投遞給消費者后直接返回ack【不安全,不建議】
  • manual:手動處理,自己在業務代碼中調用api發送ack或者reject【存在業務入侵但是更靈活】
  • auto:自動處理,利用aop自動對業務代碼進行增強,正常執行則返回ack,出現異常則根據異常類型處理【業務異常返回nack, 消息處理或者校驗異常返回reject】

返回reject常見異常:MessageConversionException、MethodArgumentNotValidException、MethodArgumentTypeMissmatchException、NoSuchMethodException、ClassCastException
基本上就是消息校驗異常以及不匹配處理方法或者參數的異常

通過如下配置可以設置ack處理方法:

spring:rabbitmq:listener:simple:acknowledge-mode: none # 不做處理

1、測試none處理方式,修改消費者端代碼,使其拋出觸發reject的異常。在拋出異常前打斷點,并觀察發現rabbitmq的客戶端發現消息在發送到消費者則觸發了自動ack并且刪除了消息 ,觸發異常后客戶端并沒有做任何處理。
在這里插入圖片描述

2、修改acknowledge-mode為auto,再觀察發現阻塞異常觸發前消息處于uack狀態,但同時觀察到收到了一個manual ack。
在這里插入圖片描述
(1)當代碼繼續執行,拋出MessageConversionException,會向MQ發送reject,刪除消息。

這里發生了一個有意思的現象,因為我消息阻塞了太久觸發了MQ消息重新投遞,因此又出現了一個manual ack以及交替出現的ready和unack。
在這里插入圖片描述

(2)當拋出異常是RuntimeException,可以觀察到unack一直是1,且一直嘗試重新投遞。(重新投遞沒有觸發那個自動的manual ack)
在這里插入圖片描述

這里留兩個小問題:為什么會自動發送了一個manual ack?這個重傳是否是超時重傳還是什么其他機制?

3、設置acknowledge-mode為manual,修改消費者端代碼手動調用api返回消息回執

@RabbitListener(bindings = @QueueBinding(key="*.top",value = @Queue(value="df.topic.queue1"),exchange = @Exchange(value = "df.topic1", type = ExchangeTypes.TOPIC)
))
public void listenDirectQueue1(Object msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException {System.out.println("這是第" + (cnt++) + "條消息");channel.basicAck(deliveryTag, false);
}

(1)測試ack
首先是接著2的調試代碼繼續調試【也就是此時消息隊列中有一個消息沒有被接收】,所以啟動測試代碼后這個消息會被重新投遞,消息被消費者接收后手動回復確定,整個過程如下圖
在這里插入圖片描述
接下來重新投遞一條消息觀察正常的手動ack全過程,圖中上面的圖藍色線(unacked)被紅色線遮擋,它們其實是同樣的走勢。也就是當消息成功投遞到消費者,會觸發一次自動的ack(Deliver manual ack),但是消息處于uack,等到業務代碼完成手動進行ack后該消息被ack并且刪除。
在這里插入圖片描述
(2)測試nack

@RabbitListener(bindings = @QueueBinding(key="*.top",value = @Queue(value="df.topic.queue1"),exchange = @Exchange(value = "df.topic1", type = ExchangeTypes.TOPIC)
))
public void listenDirectQueue1(Object msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException {try {System.out.println("這是第" + (cnt++) + "條消息");throw new BusinessException();
//            channel.basicAck(deliveryTag, false);}catch (BusinessException e){// nack且重新入隊 重新推送channel.basicNack(deliveryTag, false, true);}catch (MessageConversionException e){// reject 并且不重新入隊channel.basicReject(deliveryTag, false);}
}

上面的代碼拋出了自定義的業務異常,這個異常會被捕獲并且返回nack,然后重新推送,如下圖
在這里插入圖片描述
(3)測試reject

@RabbitListener(bindings = @QueueBinding(key="*.top",value = @Queue(value="df.topic.queue1"),exchange = @Exchange(value = "df.topic1", type = ExchangeTypes.TOPIC)
))
public void listenDirectQueue1(Object msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException {try {System.out.println("這是第" + (cnt++) + "條消息");throw new MessageConversionException("just a test for msg reject");
//            channel.basicAck(deliveryTag, false);}catch (MessageConversionException e){// reject 并且不重新入隊channel.basicReject(deliveryTag, false);}}

這里拋出MessageConversionException,捕獲后手動返回拒絕并且不重新投遞,過程如下
在這里插入圖片描述
**總結:**實際上SpringAMQP只是提供了三個接口basicAckbasicNackbasicReject,這三個接口何時觸發,基于何種規則觸發都是可以自定義的,上面的三個實現是基本與acknowledge-mode: auto一樣的邏輯:業務異常nack且重新投遞、消息異常reject且不重新投遞、正常接收和消費則ack

消息失敗重試機制


在這里插入圖片描述

上面提到的兩個小問題

為什么會觸發一次自動的Deliver(Manual ACK)

原來這個Deliver(Manual ACK)是一個投遞事件ACK,當消息進入消息隊列未被消費,其狀態為ready,當其被投遞到消費者,狀態會更新為unacked,如果被成功消費并且確認,則會被刪除。
當首次投遞,則會觸發一個投遞事件(ready變為unacked)
當消息被重新投遞,不會再觸發投遞事件
這是因為:

  1. 性能優化:重復發送投遞事件會導致網絡帶寬浪費、Broker的CPU浪費、監控系統負載
  2. 語義精確性:RabbitMQ的事件新系統旨在“報告狀態變化的邊界,而非狀態本身”,重復投遞的狀態變化是首次投遞的重復,因此沒有必要重復報告
  3. 避免誤導性監控:重復報告投遞事件會導致消息計數錯誤,無法區分實際新消息以及重新投遞消息

這個重傳是否是超時重傳還是什么其他機制?

明天再補了

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/84205.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/84205.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/84205.shtml

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

相關文章

P3 QT項目----記事本(3.4)

3.4 文件選擇對話框 QFileDialog 3.4.1 QFileDialog 開發流程 使用 QFileDialog 的基本步驟通常如下: 實例化 :首先,創建一個 QFileDialog 對象的實例。 QFileDialog qFileDialog;設置模式 :根據需要設置對話框的模式&…

學習筆記(26):線性代數-張量的降維求和,簡單示例

學習筆記(26):線性代數-張量的降維求和,簡單示例 1.先理解 “軸(Axis)” 的含義 張量的 “軸” 可以理解為 維度的方向索引 。對于形狀為 (2, 3, 4) 的張量,3 個軸的含義是: 軸 0(axis0&…

健康檔案實訓室:構建全周期健康管理的數據基石

一、健康檔案實訓室建設背景 隨著“健康中國2030”戰略深入推進,健康檔案作為居民健康數據的核心載體,在疾病預防、慢性病管理、醫療決策等領域的價值日益凸顯。在此背景下,健康檔案實訓室建設成為職業院校對接政策要求、培養專業健康管理…

【MATLAB第119期】基于MATLAB的KRR多輸入多輸出全局敏感性分析模型運用(無目標函數,考慮代理模型)

【MATLAB第119期】基于MATLAB的KRR多輸入多輸出全局敏感性分析模型運用(無目標函數,考慮代理模型) 下一期研究SHAP的多輸入多輸出敏感性分析方法 一、SOBOL(無目標函數) (1)針對簡單線性數據…

Linux常用文件目錄命令

瀏覽目錄命令: ls 、pwd目錄操作命令:cd、mkdir、rmdir瀏覽文件命令:cat、more、less、head、tail文件操作命令:cp、rm、mv、find、grep、tar 瀏覽目錄命令 ls ? 命令名稱:ls ? 命令英文原意:list ? …

PIN碼vs密碼,電腦登錄的快捷鍵你用對了嗎?

你是否也遇到過這樣的窘境:信心滿滿地輸入電腦開機密碼,屏幕卻無情地提示“密碼錯誤”。仔細一看,才發現登錄界面悄悄地變成了要求輸入“PIN碼”。這種因為混淆了PIN碼和賬戶密碼而導致的開機失敗,相信不少朋友都碰到過。 PIN碼作…

【大模型科普】AIGC技術發展與應用實踐(一文讀懂AIGC)

【作者主頁】Francek Chen 【專欄介紹】 ? ? ?人工智能與大模型應用 ? ? ? 人工智能(AI)通過算法模擬人類智能,利用機器學習、深度學習等技術驅動醫療、金融等領域的智能化。大模型是千億參數的深度神經網絡(如ChatGPT&…

Spring是如何解決Bean的循環依賴:三級緩存機制

1、什么是 Bean 的循環依賴 在 Spring框架中,Bean 的循環依賴是指多個 Bean 之間?互相持有對方引用?,形成閉環依賴關系的現象。 多個 Bean 的依賴關系構成環形鏈路,例如: 雙向依賴:Bean A 依賴 Bean B,同時 Bean B 也依賴 Bean A(A?B)。鏈條循環: Bean A → Bean…

XXE漏洞知識

目錄 1.XXE簡介與危害 XML概念 XML與HTML的區別 1.pom.xml 主要作用 2.web.xml 3.mybatis 2.XXE概念與危害 案例:文件讀取(需要Apache >5.4版本) 案例:內網探測(雞肋) 案例:執行命…

02-性能方案設計

需求分析與測試設計 根據具體的性能測試需求,確定測試類型,以及壓測的模塊(web/mysql/redis/系統整體)前期要與相關人員充分溝通,初步確定壓測方案及具體的性能指標QA完成性能測試設計后,需產出測試方案文檔發送郵件到項目組&…

STL優先級隊列的比較函數與大堆小堆的關系

STL中的priority_queue&#xff08;優先級隊列&#xff09;通過比較函數來確定元素的優先級順序&#xff0c;從而決定其內部是形成大堆還是小堆。以下是關鍵點總結&#xff1a; 默認行為與大堆&#xff1a; 默認情況下&#xff0c;priority_queue使用std::less<T>作為比較…

React---day11

14.4 react-redux第三方庫 提供connect、thunk之類的函數 以獲取一個banner數據為例子 store&#xff1a; 我們在使用異步的時候理應是要使用中間件的&#xff0c;但是configureStore 已經自動集成了 redux-thunk&#xff0c;注意action里面要返回函數 import { configureS…

OD 算法題 B卷【反轉每對括號間的子串】

文章目錄 反轉每對括號間的子串 反轉每對括號間的子串 給出一個字符串s&#xff0c; 僅含有小寫英文字母和英文括號’(’ ‘)’&#xff1b;按照從括號內到外的順序&#xff0c;逐層反轉每對括號中的字符串&#xff0c;并返回最終的結果&#xff1b;結果中不能包含任何括號&am…

如何做好一份技術文檔?從規劃到實踐的完整指南

如何做好一份技術文檔&#xff1f;從規劃到實踐的完整指南 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 總有一行代碼&#xff0c;能點亮萬千星辰。 &#x1f50d; 在技術的宇宙中&#xff0c;我愿做永不停歇的探索者。 ? 用代碼丈量世界&…

css的定位(position)詳解:相對定位 絕對定位 固定定位

在 CSS 中&#xff0c;元素的定位通過 position 屬性控制&#xff0c;共有 5 種定位模式&#xff1a;static&#xff08;靜態定位&#xff09;、relative&#xff08;相對定位&#xff09;、absolute&#xff08;絕對定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…

詳細講解Flutter GetX的使用

Flutter GetX 框架詳解&#xff1a;狀態管理、路由與依賴注入 GetX 是 Flutter 生態中一款強大且輕量級的全功能框架&#xff0c;集成了狀態管理、路由管理和依賴注入三大核心功能。其設計理念是簡潔高效&#xff0c;通過最小的代碼實現最大的功能&#xff0c;特別適合快速開發…

【大模型:知識庫管理】--Dify接入RAGFlow 知識庫

ragflow的官方文檔&#xff1a; HTTP API 接口 |抹布流 --- HTTP API | RAGFlow 接著前文&#xff0c;我們已經創建了知識庫&#xff0c;那么如何才能使用它呢&#xff1f; 當然也是通過網絡API的形式去調用它。本文將講解兩種方式&#xff1a; Dify調用python源碼調用 目錄…

Vue 模板配置項深度解析

Vue 模板配置項深度解析 在 Vue 組件開發中&#xff0c;template 是定義組件視圖結構的核心配置項。作為 Vue 專家&#xff0c;我將全面解析模板的各個方面&#xff0c;幫助你掌握高效構建 Vue 組件的藝術。 一、模板基礎概念 1. 模板的本質 聲明式渲染&#xff1a;描述 UI…

基于深度哈希與圖索引的十億級圖像近重復檢測系統

引言 在上一篇文章中,我們介紹了基于Vision API和SimHash的億級圖像去重方案。本文將更進一步,探討如何應對十億級圖像庫的近重復檢測挑戰,提出一種結合深度哈希學習與圖索引的創新架構。該系統在多個關鍵指標上比傳統方法提升顯著: 檢測精度提升:mAP@100達到0.92(傳統方…

Python開發基礎手語識別(基礎框架版)

一、前期準備 想要實現這些&#xff0c;首先就是要模擬出來一個大致的框架&#xff0c;方便后續開展&#xff0c;下面的就是隨便寫的一個框架&#xff0c;大家湊合看看就行&#xff0c;基本上是這個意思&#xff1a; from tkinter import *w Tk() w.title("手語識別&am…