訊息中介軟體RabbitMQ系列,多個消費者的時候,不使用預設的輪詢,要實現能者多勞(八)

- ich lebe .發表於2020-10-20

之前我們已經實現了一個傳送者將訊息傳送到佇列,有多個消費者從佇列裡面拿資料,但是這樣多個消費者是輪詢的方式從佇列裡面拿資料的,每一個消費者拿到的資料都一樣多,現在我們想要實現的是能者多勞,咋實現這個呢?

什麼是訊息確認機制

rabbitmq軟體為什麼 預設是輪詢的了,這個和軟體的訊息確認機制有一定的關係,那麼什麼是訊息確認機制了?

我們先看消費者端的程式碼

public class Customer1 {

    public static void main(String[] args) throws IOException, TimeoutException {

        Connection connection = RabbitMqUtils.getConnection();
//        建立通道
        Channel channel = connection.createChannel();
//        讓通道和訊息佇列進行繫結
        channel.queueDeclare("work",false,false,false,null);
//接受訊息
        channel.basicConsume("work",true,new DefaultConsumer(channel){

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消費者1==="+new String(body));
            }
        });

    }
}
 channel.basicConsume("work",true,new DefaultConsumer(channel)

第一個引數的意思: 要接受哪個佇列裡面的訊息
第二個引數:訊息確認機制 true false
第三個引數: 接受訊息後的回撥函式,在這個回撥函式裡面拿出佇列裡面的資料

當第二個引數為true的時候,一個消費者從訊息佇列裡面拿出一個訊息,這個訊息佇列就將佇列裡面的這個訊息刪除,訊息佇列是不管這個消費者拿這個訊息幹什麼,也不管這個訊息執行完沒有,意思就是隻要這個消費者拿了訊息佇列裡面的一個訊息,那麼訊息佇列就刪除佇列中的資訊。

現在我們的問題

現在我們使用預設的訊息確認機制,當一個佇列裡面有10個訊息,現在有兩個消費者,那麼如果是預設的,那麼每一個消費者可以拿到5個訊息,但是現在就有一個問題,如果消費者A拿到5個訊息,在執行第2個 的時候,這個消費者當機了,那麼其他的3個訊息咋辦,那就丟失了啊,訊息佇列只要將訊息給了消費者,那麼訊息佇列裡面的資訊就刪除了,現在消費者A也當機了,其他的3個訊息咋辦,現在我們想要做的就是將這還沒有處理的3個資訊給了消費者B ,讓消費者B 進行處理,實現能者多勞。

解決問題

1 不使用預設的訊息確認機制

   channel.basicConsume("work",false,new DefaultConsumer(channel){

第二個引數只要變為false,那麼就不會使用預設的確認機制了。
即使我們的消費者已經將訊息消費了,但是也不會自動的告訴佇列,我已經消費了。

2 設定一個通道里面只是放一個訊息

意思就是 一個消費者在一個通道里面只能消費一個訊息,
所以,我們要告訴我們的通道,一次只能消費一個訊息
原始碼:

   Connection connection = RabbitMqUtils.getConnection();
//        建立通道
        Channel channel = connection.createChannel();
        channel.basicQos(1);
//        讓通道和訊息佇列進行繫結

解釋原始碼新增的一句話

  channel.basicQos(1);這個的意思是告訴通道,一次只能消費一個訊息
     讓通道和訊息佇列進行繫結
        channel.queueDeclare("work",false,false,false,null);

        channel.basicConsume("work",false,new DefaultConsumer(channel){

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消費者1==="+new String(body));
                channel.basicAck(envelope.getDeliveryTag(),true);
            }
        });
  channel.basicAck(envelope.getDeliveryTag(),false);   手動確認訊息

相關文章