rabbitmq系列03---發佈確認

一、發佈確認邏輯

生產者將信道設置成 confirm 模式,一旦信道進入 confirm 模式,所有在該信道上面發佈的消息都將會被指派一個唯一的 ID (從 1 開始),一旦消息被投遞到所有匹配的隊列之後,broker 就會發送一個確認給生產者 (包含消息的唯一 ID),這就使得生產者知道消息已經正確到達目的隊列了
當消息最終得到確認之後,生產者應用便可以通過回調方法來處理該確認消息,如果 RabbitMQ 因爲自身內部錯誤導致消息丟失,就會發送一條 nack 消息, 生產者應用程序同樣可以在回調方法中處理該 nack 消息。

 二、發佈發佈確認的策略

發佈確認默認是沒有開啓的,如果要開啓,需要調用方法 confirmSelect每當你要想使用發佈確認,都需要在 channel 上調用該方法

 

1、單個發佈確認

這是一種簡單的確認方式,它是一種同步確認發佈的方式,也就是發佈一個消息之後只有它被確認發佈,後續的消息才能繼續發佈,waitForConfirmsOrDie(long) 這個方法只有在消息被確認的時候才返回,如果在指定時間範圍內這個消息沒有被確認那麼它將拋出異常。

這種確認方式有一個最大的缺點就是:發佈速度特別的慢,因爲如果沒有確認發佈的消息就會阻塞所有後續消息的發佈,這種方式最多提供每秒不超過數百條發佈消息的吞吐量。當然對於某些應用程序來說這可能已經足夠了。

//單個確認
    public static void publishMessageSingle() throws Exception{
        Channel channel = Util.getChannel();
        //隊列的聲明
        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,true,false,false,null);
        //開啓發布確認
        channel.confirmSelect();
        //開始時間
        long begin = System.currentTimeMillis();

        //批量發消息
        for (int i = 0; i < MESSAGE_COUNT; i++) {
            String message = i + "";
            channel.basicPublish("",queueName,null,message.getBytes());
            //單個消息就馬上發佈確認
            boolean flag = channel.waitForConfirms();
            if(flag){
                System.out.println("消息發送成功");
            }
        }
        //結束時間
        long end = System.currentTimeMillis();
        System.out.println("發佈"+MESSAGE_COUNT+"個單獨確認消息,耗時"+(end-begin)+"ms");
    }

 

2、批量確認發佈
與單個等待確認消息相比,先發布一批消息然後一起確認可以極大地提高吞吐量,當然這種方式的缺點就是:當發生故障導致發佈出現問題時,不知道是哪個消息出現問題了,我們必須將整個批處理保存在內存中,以記錄重要的信息而後重新發布消息。當然這種方案仍然是同步的,也一樣阻塞消息的發佈。

//批量確認
    public static void publishMessageBatch() throws Exception{
        Channel channel = Util.getChannel();
        //隊列的聲明
        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,true,false,false,null);
        //開啓發布確認
        channel.confirmSelect();
        //批量確認消息大小
        int batchSize = 100;
        //開始時間
        long begin = System.currentTimeMillis();
        //批量發消息 批量發佈確認
        for (int i = 0; i < MESSAGE_COUNT; i++) {
            String message = i + "";
            channel.basicPublish("",queueName,null,message.getBytes());
            //每達到100次,批量發佈確認一次
            if(i%batchSize == 0){
                //發佈確認
              channel.waitForConfirms();
            }
        }
        //結束時間
        long end = System.currentTimeMillis();
        System.out.println("發佈"+MESSAGE_COUNT+"個批量確認消息,耗時"+(end-begin)+"ms");
    }

3、異步確認發佈

異步確認雖然編程邏輯比上兩個要複雜,但是性價比最高,無論是可靠性還是效率都沒得說,他是利用回調函數來達到消息可靠性傳遞的,這個中間件也是通過函數回調來保證是否投遞成功。

//異步發佈確認
    public static void publishMessageAsync() throws Exception{
        Channel channel = Util.getChannel();
        //隊列的聲明
        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,true,false,false,null);
        //開啓發布確認
        channel.confirmSelect();
        //開始時間
        long begin = System.currentTimeMillis();

        /**
         * deliveryTag:消息的標記
         * multiple:是否批量確認
         */
        //消息確認成功 回調函數
        ConfirmCallback ackCallback = (deliveryTag,multiple)->{
            System.out.println("確確認消息"+deliveryTag);
        };
        //消息確認失敗 回調函數
        ConfirmCallback nackCallback = (deliveryTag,multiple)->{
            System.out.println("未確認消息"+deliveryTag);
        };
        //準備消息監聽器 監聽那些消息成功,那些消息失敗
        /**
         * 1.監聽成功方法
         * 2.監聽失敗方法
         */
         channel.addConfirmListener(ackCallback,nackCallback);//異步通知
        //批量發送消息
        for (int i = 0; i < MESSAGE_COUNT; i++) {
            String message = i + "";
            channel.basicPublish("",queueName,null,message.getBytes());
        }
        //結束時間
        long end = System.currentTimeMillis();
        System.out.println("發佈"+MESSAGE_COUNT+"個異步發佈確認消息,耗時"+(end-begin)+"ms");
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章