【RabbitMQ】work模式

      上一篇博客的作爲rabbitMQ的入門程序,也是簡單隊列模式,一個生產者,一個消費者,今天這篇博客介紹work模式,一個生產者,多個消費者,下面的例子模擬兩個消費者的情況。


圖示
        


  一個生產者、兩個消費者;一個消息只能被一個消費者獲取。

  在work模式中可以分爲兩種模式,一種是兩個消費者平均消費隊列中的消息,即使他們的消費能力是不一樣的,這種似乎不太符合實際的情況。另一種是能者多勞模式,處理消息能力強的消費者會獲取更多的 消息,這種模式更符合實際需求。


  生產者:向隊列發送50條消息,下面代碼中,生產者每生產一條消息後都會休眠一段時間,並且越往後休眠的時間越長。

public class Send {

    private final static String QUEUE_NAME = "test_queue_work";

    public static void main(String[] argv) throws Exception {
        // 獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();

        // 聲明隊列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        for (int i = 0; i < 50; i++) {
            // 消息內容
            String message = "" + i;
            channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
            System.out.println(" [x] Sent '" + message + "'");

            Thread.sleep(i * 10);
        }

        channel.close();
        connection.close();
    }
}


消費者1:休眠時間爲10ms

public class Recv {

    private final static String QUEUE_NAME = "test_queue_work";

    public static void main(String[] argv) throws Exception {

        // 獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();

        // 聲明隊列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // 同一時刻服務器只會發一條消息給消費者
        //channel.basicQos(1);

        // 定義隊列的消費者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        // 監聽隊列,手動返回完成
        channel.basicConsume(QUEUE_NAME, false, consumer);

        // 獲取消息
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" [x] Received '" + message + "'");
            //休眠
            Thread.sleep(10);
            // 返回確認狀態
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}


消費者2:休眠時間爲1000ms

public class Recv2 {

    private final static String QUEUE_NAME = "test_queue_work";

    public static void main(String[] argv) throws Exception {

        // 獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();

        // 聲明隊列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // 同一時刻服務器只會發一條消息給消費者
        //channel.basicQos(1);

        // 定義隊列的消費者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        // 監聽隊列,手動返回完成狀態
        channel.basicConsume(QUEUE_NAME, false, consumer);

        // 獲取消息
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" [x] Received '" + message + "'");
            // 休眠1秒
            Thread.sleep(1000);

            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}

  從上面代碼中我們知道消費者2的休眠時間更長,消費者1的處理能力應該比消費者2更強,但是最後運行的結果會發現,兩個消費者獲得消息的數量十一樣的,一個全部爲奇數,一個全部爲偶數。

  我們把每個消費者中的代碼:channel.basicQos(1);這句代碼解開註釋會發現消費者2獲取到8條數據,而消費者1獲取到42條消息。這樣的結果才符合work模式的能者多勞模式。這句代碼表示服務器同一時刻只會發送一條消息給消費者,但並不指定是哪個消費者,處理能力高的人會接收到更多的消息。


小結:

  簡單隊列和work 模式的不同:
  簡單隊列只要消息從隊列中獲取,無論消費者獲取到消息後是否成功消費,比如遇到狀況:斷電,都認爲是消息已經成功消費;

  work模式消費者從隊列中獲取消息後,服務器會將該消息標記爲不可用狀態,等待消費者反饋,如果消費這一直沒有反饋,則該消息一直處於不可用狀態。

  具體使用哪種模式具體問題具體分析。

  channel.basicConsume(QUEUE_NAME, false, consumer);false表示監聽隊列,手動返回完成狀態,true表示自動返回。


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