中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java RabbitMQ中的消息長期不消費是否會過期

發布時間:2021-09-24 18:00:30 來源:億速云 閱讀:183 作者:柒染 欄目:開發技術

Java RabbitMQ中的消息長期不消費是否會過期,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

1. 默認情況

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

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

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

2. TTL

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

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

  • 在聲明隊列的時候,我們可以在隊列屬性中設置消息的有效期,這樣所有進入該隊列的消息都會有一個相同的有效期。

  • 在發送消息的時候設置消息的有效期,這樣不同的消息就具有不同的有效期。

那如果兩個都設置了呢?

以時間短的為準。

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

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

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

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

2.1 單條消息過期

我們先來看單條消息的過期時間。

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

Java 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);
    }
}

這個配置類主要干了三件事:配置消息隊列、配置交換機以及將兩者綁定在一起。

  • 首先配置一個消息隊列,new 一個 Queue:第一個參數是消息隊列的名字;第二個參數表示消息是否持久化;第三個參數表示消息隊列是否排他,一般我們都是設置為 false,即不排他;第四個參數表示如果該隊列沒有任何訂閱的消費者的話,該隊列會被自動刪除,一般適用于臨時隊列。

  • 配置一個 DirectExchange 交換機。

  • 將交換機和隊列綁定到一起。

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

關于排他性,如果設置為 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 之后,我們會發現消息已經不見了:

Java RabbitMQ中的消息長期不消費是否會過期

很簡單吧!

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

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 管理頁面,如下:

Java 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);
}

很容易吧~

關于Java RabbitMQ中的消息長期不消費是否會過期問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

大埔区| 宝山区| 贵南县| 同德县| 湖南省| 曲周县| 武定县| 富民县| 宣城市| 随州市| 浪卡子县| 东丽区| 孟津县| 德昌县| 通渭县| 三明市| 扬州市| 平舆县| 桂东县| 青州市| 云林县| 保德县| 襄垣县| 长阳| 泸州市| 常宁市| 白城市| 九江县| 定兴县| 曲水县| 德化县| 浮山县| 中山市| 邯郸县| 漳浦县| 家居| 鹤山市| 德令哈市| 尼勒克县| 南漳县| 富民县|