主頁 > 軟體設計 > RabbitMQ 中的訊息會過期嗎?

RabbitMQ 中的訊息會過期嗎?

2021-09-23 13:55:15 軟體設計

文章目錄

    • 1. 默認情況
    • 2. TTL
      • 2.1 單條訊息過期
      • 2.2 佇列訊息過期
      • 2.3 特殊情況
    • 3. 死信佇列
      • 3.1 死信交換機
      • 3.2 死信佇列
      • 3.3 實踐
    • 4. 小結

RabbitMQ 中的訊息長期未被消費會過期嗎?用過 RabbitMQ 的小伙伴可能都有這樣的疑問,今天松哥就來和大家捋一捋這個問題,

1. 默認情況

首先我們來看看默認情況,

默認情況下,訊息是不會過期的,也就是我們平日里在訊息發送時,如果不設定任何訊息過期的相關引數,那么訊息是不會過期的,即使訊息沒被消費掉,也會一直存盤在佇列中,

這種情況具體代碼就不用我再演示了吧,松哥之前的文章凡是涉及到 RabbitMQ 的,基本上都是這樣的,

2. TTL

TTL(Time-To-Live),訊息存活的時間,即訊息的有效期,如果我們希望訊息能夠有一個存活時間,那么我們可以通過設定 TTL 來實作這一需求,如果訊息的存活時間超過了 TTL 并且還沒有被訊息,此時訊息就會變成死信,關于死信以及死信佇列,松哥后面再和大家介紹,

TTL 的設定有兩種不同的方式:

  1. 在宣告佇列的時候,我們可以在佇列屬性中設定訊息的有效期,這樣所有進入該佇列的訊息都會有一個相同的有效期,
  2. 在發送訊息的時候設定訊息的有效期,這樣不同的訊息就具有不同的有效期,

那如果兩個都設定了呢?

以時間短的為準,

當我們設定了訊息有效期后,訊息過期了就會被從佇列中洗掉了(進入到死信佇列,后文一樣,不再標注),但是兩種方式對應的洗掉時機有一些差異:

  1. 對于第一種方式,當訊息佇列設定過期時間的時候,那么訊息過期了就會被洗掉,因為訊息進入 RabbitMQ 后是存在一個訊息佇列中,佇列的頭部是最早要過期的訊息,所以 RabbitMQ 只需要一個定時任務,從頭部開始掃描是否有過期訊息,有的話就直接洗掉,
  2. 對于第二種方式,當訊息過期后并不會立馬被洗掉,而是當訊息要投遞給消費者的時候才會去洗掉,因為第二種方式,每條訊息的過期時間都不一樣,想要知道哪條訊息過期,必須要遍歷佇列中的所有訊息才能實作,當訊息比較多時這樣就比較耗費性能,因此對于第二種方式,當訊息要投遞給消費者的時候才去洗掉,

介紹完 TTL 之后,接下來我們來看看具體用法,

接下來所有代碼松哥都以 Spring Boot 中封裝的 AMPQ 為例來講解,

2.1 單條訊息過期

我們先來看單條訊息的過期時間,

首先創建一個 Spring Boot 專案,引入 Web 和 RabbitMQ 依賴,如下:

然后在 application.properties 中配置一下 RabbitMQ 的連接資訊,如下:

spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/

接下來稍微配置一下訊息佇列:

@Configuration
public class QueueConfig {

    public static final String JAVABOY_QUEUE_DEMO = "javaboy_queue_demo";
    public static final String JAVABOY_EXCHANGE_DEMO = "javaboy_exchange_demo";
    public static final String HELLO_ROUTING_KEY = "hello_routing_key";

    @Bean
    Queue queue() {
        return new Queue(JAVABOY_QUEUE_DEMO, true, false, false);
    }

    @Bean
    DirectExchange directExchange() {
        return new DirectExchange(JAVABOY_EXCHANGE_DEMO, true, false);
    }

    @Bean
    Binding binding() {
        return BindingBuilder.bind(queue())
                .to(directExchange())
                .with(HELLO_ROUTING_KEY);
    }
}

這個配置類主要干了三件事:配置訊息佇列、配置交換機以及將兩者系結在一起,

  1. 首先配置一個訊息佇列,new 一個 Queue:第一個引數是訊息佇列的名字;第二個引數表示訊息是否持久化;第三個引數表示訊息佇列是否排他,一般我們都是設定為 false,即不排他;第四個引數表示如果該佇列沒有任何訂閱的消費者的話,該佇列會被自動洗掉,一般適用于臨時佇列,
  2. 配置一個 DirectExchange 交換機,
  3. 將交換機和佇列系結到一起,

這段配置應該很簡單,沒啥好解釋的,有一個排他性,松哥這里稍微多說兩句:

關于排他性,如果設定為 true,則該訊息佇列只有創建它的 Connection 才能訪問,其他的 Connection 都不能訪問該訊息佇列,如果試圖在不同的連接中重新宣告或者訪問排他性佇列,那么系統會報一個資源被鎖定的錯誤,另一方面,對于排他性佇列而言,當連接斷掉的時候,該訊息佇列也會自動洗掉(無論該佇列是否被宣告為持久性佇列都會被洗掉),

接下來提供一個訊息發送介面,如下:

@RestController
public class HelloController {
    @Autowired
    RabbitTemplate rabbitTemplate;

    @GetMapping("/hello")
    public void hello() {
        Message message = MessageBuilder.withBody("hello javaboy".getBytes())
                .setExpiration("10000")
                .build();
        rabbitTemplate.convertAndSend(QueueConfig.JAVABOY_QUEUE_DEMO, message);
    }
}

在創建 Message 物件的時候我們可以設定訊息的過期時間,這里設定訊息的過期時間為 10 秒,

這就可以啦!

接下來我們啟動專案,進行訊息發送測驗,當訊息發送成功之后,由于沒有消費者,所以這條訊息并不會被消費,打開 RabbitMQ 管理頁面,點擊到 Queues 選項卡,10s 之后,我們會發現訊息已經不見了:

很簡單吧!

單條訊息設定過期時間,就是在訊息發送的時候設定一下訊息有效期即可,

2.2 佇列訊息過期

給佇列設定訊息過期時間,方式如下:

@Bean
Queue queue() {
    Map<String, Object> args = new HashMap<>();
    args.put("x-message-ttl", 10000);
    return new Queue(JAVABOY_QUEUE_DEMO, true, false, false, args);
}

設定完成后,我們修改訊息的發送邏輯,如下:

@RestController
public class HelloController {
    @Autowired
    RabbitTemplate rabbitTemplate;

    @GetMapping("/hello")
    public void hello() {
        Message message = MessageBuilder.withBody("hello javaboy".getBytes())
                .build();
        rabbitTemplate.convertAndSend(QueueConfig.JAVABOY_QUEUE_DEMO, message);
    }
}

可以看到,訊息正常發送即可,不用設定訊息過期時間,

OK,啟動專案,發送一條訊息進行測驗,查看 RabbitMQ 管理頁面,如下:

可以看到,訊息佇列的 Features 屬性為 D 和 TTL,D 表示訊息佇列中訊息持久化,TTL 則表示訊息會過期,

10s 之后重繪頁面,發現訊息數量已經恢復為 0,

這就是給訊息佇列設定訊息過期時間,一旦設定了,所有進入到該佇列的訊息都有一個過期時間了,

2.3 特殊情況

還有一種特殊情況,就是將訊息的過期時間 TTL 設定為 0,這表示如果訊息不能立馬消費則會被立即丟掉,這個特性可以部分替代 RabbitMQ3.0 以前支持的 immediate 引數,之所以所部分代替,是因為 immediate 引數在投遞失敗會有 basic.return 方法將訊息體回傳(這個功能可以利用死信佇列來實作),

具體代碼松哥就不演示了,這個應該比較容易,

3. 死信佇列

有小伙伴不禁要問,被洗掉的訊息去哪了?真的被洗掉了嗎?非也非也!這就涉及到死信佇列了,接下來我們來看看死信佇列,

3.1 死信交換機

死信交換機,Dead-Letter-Exchange 即 DLX,

死信交換機用來接收死信訊息(Dead Message)的,那什么是死信訊息呢?一般訊息變成死信訊息有如下幾種情況:

  • 訊息被拒絕(Basic.Reject/Basic.Nack) ,井且設定requeue 引數為false
  • 訊息過期
  • 佇列達到最大長度

當訊息在一個佇列中變成了死信訊息后,此時就會被發送到 DLX,系結 DLX 的訊息佇列則稱為死信佇列,

DLX 本質上也是一個普普通通的交換機,我們可以為任意佇列指定 DLX,當該佇列中存在死信時,RabbitMQ 就會自動的將這個死信發布到 DLX 上去,進而被路由到另一個系結了 DLX 的佇列上(即死信佇列),

3.2 死信佇列

這個好理解,系結了死信交換機的佇列就是死信佇列,

3.3 實踐

我們來看一個簡單的例子,

首先我們來創建一個死信交換機,接著創建一個死信佇列,再將死信交換機和死信佇列系結到一起:

public static final String DLX_EXCHANGE_NAME = "dlx_exchange_name";
public static final String DLX_QUEUE_NAME = "dlx_queue_name";
public static final String DLX_ROUTING_KEY = "dlx_routing_key";

/**
 * 配置死信交換機
 *
 * @return
 */
@Bean
DirectExchange dlxDirectExchange() {
    return new DirectExchange(DLX_EXCHANGE_NAME, true, false);
}
/**
 * 配置死信佇列
 * @return
 */
@Bean
Queue dlxQueue() {
    return new Queue(DLX_QUEUE_NAME);
}
/**
 * 系結死信佇列和死信交換機
 * @return
 */
@Bean
Binding dlxBinding() {
    return BindingBuilder.bind(dlxQueue())
            .to(dlxDirectExchange())
            .with(DLX_ROUTING_KEY);
}

這其實跟普通的交換機,普通的訊息佇列沒啥兩樣,

接下來為訊息佇列配置死信交換機,如下:

@Bean
Queue queue() {
    Map<String, Object> args = new HashMap<>();
    //設定訊息過期時間
    args.put("x-message-ttl", 0);
    //設定死信交換機
    args.put("x-dead-letter-exchange", DLX_EXCHANGE_NAME);
    //設定死信 routing_key
    args.put("x-dead-letter-routing-key", DLX_ROUTING_KEY);
    return new Queue(JAVABOY_QUEUE_DEMO, true, false, false, args);
}

就兩個引數:

  • x-dead-letter-exchange:配置死信交換機,
  • x-dead-letter-routing-key:配置死信 routing_key

這就配置好了,

將來發送到這個訊息佇列上的訊息,如果發生了 nack、reject 或者過期等問題,就會被發送到 DLX 上,進而進入到與 DLX 系結的訊息佇列上,

死信訊息佇列的消費和普通訊息佇列的消費并無二致:

@RabbitListener(queues = QueueConfig.DLX_QUEUE_NAME)
public void dlxHandle(String msg) {
    System.out.println("dlx msg = " + msg);
}

很容易吧~

4. 小結

好啦,今天就和小伙伴們聊一聊 RabbitMQ 中的訊息過期問題,感興趣的小伙伴可以去試試哦~

公眾號江南一點雨后臺回復本文標題,可以獲取本文案例下載鏈接,

參考資料:

  • blog.csdn.net/u012988901/article/details/88958654

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/302280.html

標籤:其他

上一篇:LeetCode 1139. 最大的以 1 為邊界的正方形

下一篇:【c++】——STL容器之vector的使用和模擬實作

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more