上一篇博客的作爲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();
}
}
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表示自動返回。