<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    SpringBoot+RabbitMQ 死信隊列

    VSole2022-05-23 16:45:30

    前言

    死信:無法被消費的消息,稱為死信。

    如果死信一直留在隊列中,會導致一直被消費,卻從不消費成功。

    所以我們專門開辟了一個來存放死信的隊列,叫死信隊列(DLX,dead-letter-exchange)。

    死信的幾種來源:
    • 消息 TTL 過期(time to live,存活時間,可以用在限時支付消息)
    • 隊列達到最大長度(隊列滿了,無法路由到該隊列)
    • 消息被拒絕( basic.reject / basic.nack ),并且 requeue = false

    環境準備配置

    準備 MQ 的隊列和環境:

    • 正常交換機
    • 正常隊列(最長隊列 5) ---- 正常消費者,拒絕消息
    • ttl 隊列(過期時間 60 秒) ---- 沒有消費者
    • 死信交換機
    • 死信隊列

    主要配置文件如下:

    @Configuration
    public class DeadConfig {
    
        /* 正常配置 **********************************************************************************************************/
    
        /**
         * 正常交換機,開啟持久化
         */
        @Bean
        DirectExchange normalExchange() {
            return new DirectExchange("normalExchange", true, false);
        }
    
        @Bean
        public Queue normalQueue() {
            // durable: 是否持久化,默認是false,持久化隊列:會被存儲在磁盤上,當消息代理重啟時仍然存在,暫存隊列:當前連接有效
            // exclusive: 默認也是false,只能被當前創建的連接使用,而且當連接關閉后隊列即被刪除。此參考優先級高于durable
            // autoDelete: 是否自動刪除,當沒有生產者或者消費者使用此隊列,該隊列會自動刪除。
            Map args = deadQueueArgs();
            // 隊列設置最大長度
            args.put("x-max-length", 5);
            return new Queue("normalQueue", true, false, false, args);
        }
    
        @Bean
        public Queue ttlQueue() {
            Map args = deadQueueArgs();
            // 隊列設置消息過期時間 60 秒
            args.put("x-message-ttl", 60 * 1000);
            return new Queue("ttlQueue", true, false, false, args);
        }
    
        @Bean
        Binding normalRouteBinding() {
            return BindingBuilder.bind(normalQueue()).to(normalExchange()).with("normalRouting");
        }
    
        @Bean
        Binding ttlRouteBinding() {
            return BindingBuilder.bind(ttlQueue()).to(normalExchange()).with("ttlRouting");
        }
    
        /* 死信配置 **********************************************************************************************************/
    
        /**
         * 死信交換機
         */
        @Bean
        DirectExchange deadExchange() {
            return new DirectExchange("deadExchange", true, false);
        }
    
        /**
         * 死信隊列
         */
        @Bean
        public Queue deadQueue() {
            return new Queue("deadQueue", true, false, false);
        }
    
        @Bean
        Binding deadRouteBinding() {
            return BindingBuilder.bind(deadQueue()).to(deadExchange()).with("deadRouting");
        }
    
        /**
         * 轉發到 死信隊列,配置參數
         */
        private Map deadQueueArgs() {
            Map map = new HashMap<>();
            // 綁定該隊列到私信交換機
            map.put("x-dead-letter-exchange", "deadExchange");
            map.put("x-dead-letter-routing-key", "deadRouting");
            return map;
        }
    
    }
    

    arguments 具體參數如下:

    隊列達到最大長度

    首先測試最簡單的,沒有消費者。

    調用6次正常隊列的生產方法。

     /**
      * 正常消息隊列,隊列最大長度5
      */
     @GetMapping("/normalQueue")
     public String normalQueue() {
    
         Map map = new HashMap<>();
         map.put("messageId", String.valueOf(UUID.randomUUID()));
         map.put("data", System.currentTimeMillis() + ", 正常隊列消息,最大長度 5");
    
         rabbitTemplate.convertAndSend("normalExchange", "normalRouting", map, new CorrelationData());
         return JSONObject.toJSONString(map);
     }
    

    MQ 結果如下:

    消息 TTL 過期

    消息的TTL 指的是消息的存活時間,我們可以通過設置消息的TTL或者隊列的TTL來實現。

    • 消息的TTL :對于設置了過期時間屬性(expiration)的消息,消息如果在過期時間內沒被消費,會過期
    • 隊列的TTL :對于設置了過期時間屬性(x-message-ttl)的隊列,所有路由到這個隊列的消息,都會設置上這個過期時間

    兩種配置都行,一般都用在定時任務,限時支付這種地方。

     /**
      * 消息 TTL, time to live
      */
     @GetMapping("/ttlToDead")
     public String ttlToDead() {
    
         Map map = new HashMap<>();
         map.put("messageId", String.valueOf(UUID.randomUUID()));
         map.put("data", System.currentTimeMillis() + ", ttl隊列消息");
    
         rabbitTemplate.convertAndSend("normalExchange", "ttlRouting", map, new CorrelationData());
         return JSONObject.toJSONString(map);
     }
    

    發送后:

    等待過期后:

    Demo 中只是為了方便,代碼中盡量使用 消息TTL,不要用 隊列TTL


    拒絕消息

    正常隊列消費后拒絕消息,并且不進行重新入隊:

    @Component
    @RabbitListener(queues = "normalQueue")
    public class NormalConsumer {
        @RabbitHandler
        public void process(Map message, Channel channel, Message mqMsg) throws IOException {
            System.out.println("收到消息,并拒絕重新入隊 : " + message.toString());
            channel.basicReject(mqMsg.getMessageProperties().getDeliveryTag(), false);
        }
    }
    

    MQ 控制臺:

    死信隊列消費:

    @Component
    @RabbitListener(queues = "deadQueue")
    public class DeadConsumer {
        @RabbitHandler
        public void process(Map message, Channel channel, Message mqMsg) throws IOException {
            System.out.println("死信隊列收到消息 : " + message.toString());
            channel.basicAck(mqMsg.getMessageProperties().getDeliveryTag(), false);
        }
    }
    

    消息順序和實驗一致:

    死信隊列收到消息 : {data=1631534291765, 正常隊列消息,最大長度 5, messageId=bce3888b-da38-4299-ac88-d22cbe164739}
    死信隊列收到消息 : {data=1631535222745, ttl隊列消息, messageId=a4617445-5aab-4fac-aec7-5709ea699598}
    死信隊列收到消息 : {data=1631534503765, 正常隊列消息,最大長度 5, messageId=b65ecaab-5ce7-4597-a32c-c90b67ec46da}
    死信隊列收到消息 : {data=1631534511468, 正常隊列消息,最大長度 5, messageId=d63d2a4c-e7d3-4f00-a6ca-78e2d62d1d92}
    死信隊列收到消息 : {data=1631534585087, 正常隊列消息,最大長度 5, messageId=eed0c349-415b-43dc-aa79-c683122a1289}
    死信隊列收到消息 : {data=1631534588311, 正常隊列消息,最大長度 5, messageId=7a7bd152-f2fa-4a74-b9e6-943ac7cbb3d4}
    死信隊列收到消息 : {data=1631534608504, 正常隊列消息,最大長度 5, messageId=9de512a1-4ca4-4060-9096-27aba01c1687}在看點這里好文分享給更多人↓↓
    
    優先級隊列ttl
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    死信:無法被消費的消息,稱為死信。 如果死信一直留在隊列中,會導致一直被消費,卻從不消費成功。 所以我們專門開辟了一個來存放死信的隊列,叫死信隊列(DLX,dead-letter-exchange)。 死信的幾種來源: 消息 TTL 過期(time to live,存活時間,可以用在限時支付消息) 隊列達到最大長度(隊列滿了,無法路由到該隊列) 消息被拒絕( basic.reject / b
    雖然平時大部分工作都是和網絡相關, 但會接觸Linux系統, 尤其是使用了Mac之后, 每天都是工作在黑色背景的命令行環境中. 自己記憶力不好, 很多有用的Linux命令不能很好的記憶, 現在逐漸總結一下, 以便后續查看。基本操作Linux 關機,重啟#?查看當前用戶環境變量。查看有幾顆cpu,每顆分別是幾核。
    Linux比較麻煩的就是很多東西都要用命令來控制,當然,這也是很多人喜歡它的原因,比較短小但卻功能強大。
    雖然平時大部分工作都是和Java相關的開發, 但是每天都會接觸Linux系統, 尤其是使用了Mac之后, 每天都是工作在黑色背景的命令行環境中. 自己記憶力不好, 很多有用的Linux命令不能很好的記憶, 現在逐漸總結一下, 以便后續查看。
    Truzz通過路徑轉換間的差異,識別與驗證檢查相關的字節,并在變異階段保護該字節以緩解上述問題。Truzz會對每個種子進行排名,能夠發現更多新邊的種子具有更高的優先級。字節分析在字節分析階段,Truzz根據路徑轉換過程中兩種執行路徑之間的差異為輸入字節建立概率分布,并利用概率分布選擇要變異的字節。
    RSA-CRT算法是使用中國剩余定理加速模冪運算的RSA算法,可大幅度降級計算時間。其中,底數為c,指數l位用d表示,模數為N,窗口大小為w。結合已泄露的部分密鑰,通過對二叉樹的深度優先遍歷可恢復完整密鑰。但第一個方案的實驗結果可達到一次模冪運算的窗口值恢復不超過3個錯誤,因此結合部分密鑰泄露攻擊對剩余窗口值進行恢復的時間和空間開銷可以容忍。
    目前業界常見的延時消息方案
    本期我們就一起來詳細的了解 思科、華為、H3C、銳銳四家廠商交換機的配置命令。
    Java并發隊列與容器
    2022-07-29 10:03:36
    所謂“阻塞”是指在某些情況下線程被掛起,當滿足一定條件時會被自動喚醒,可以通過API進行控制。生產和消費數據時,直接將枚舉對象插入或刪除,不會產生或銷毀額外的對象實例。
    當線程從等待狀態蘇醒后,會自動檢測自己得APC隊列中是否存在APC過程。所以只需要將目標進程的線程的APC隊列里面添加APC過程,當然為了提高命中率可以向進程的所有線程中添加APC過程。然后促使線程從休眠中恢復就可以實現APC注入。往線程APC隊列添加APC,系統會產生一個軟中斷。第二個參數表示插入APC的線程句柄,要求線程句柄必須包含THREAD_SET_CONTEXT訪問權限。第三個參數表示傳遞給執行函數的參數。如果直接傳入shellcode不設置第三個函數,可以直接執行shellcode。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类