RabbitMQ的工作佇列和路由

weixin_34402090發表於2014-03-14
工作佇列:Working Queue
 
工作佇列這個概念與簡單的傳送/接收訊息的區別就是:接收方接收到訊息後,可能需要花費更長的時間來處理訊息,這個過程就叫一個Work/Task。
 
幾個概念
分配:多個接收端接收同一個Queue時,如何分配?
訊息確認:Server端如何確定接收方的Work已經對訊息進行了完整的處理?
訊息持久化:傳送方、服務端Queue如何對未處理的訊息進行磁碟持久化?
 
Round-robin分配
多個接收端接收同一個Queue時,採用了Round-robin分配演算法,即輪叫排程——依次分配給各個接收方。
 
訊息確認
預設開啟了訊息確認(接收方接收到訊息後,立即向伺服器發回確認)。訊息接收方處理完訊息後,向伺服器傳送訊息確認,伺服器再刪除該訊息。
 
對於耗時的work,可以先關閉自動訊息確認,在work完成後,再手動發回確認。
channel.basicConsume("hello",false/*關閉自動訊息確認*/,consumer);
// ...work完成後
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
 
持久化
 
1. Server端的Queue持久化
注意的是,如果已經宣告瞭同名非持久化的Queue,則再次宣告無效。
傳送方和接收方都需要指定該引數。
boolean durable = true;
channel.queueDeclare("task_queue", durable, false, false, null); 
 
2. Message持久化
channel.basicPublish("", "task_queue", MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes());
 
負載分配
 
為了解決各個接收端工作量相差太大的問題(有的一直busy,有的空閒比較多),突破Round-robin。
int prefetchCount = 1;
channel.basicQos(prefetchCount);
意思為,最多為當前接收方傳送一條訊息。如果接收方還未處理完畢訊息,還沒有回發確認,就不要再給他分配訊息了,應該把當前訊息分配給其它空閒接收方。
 

固定關鍵詞路由:Routing
 
使用型別為direct的exchange,傳送特定關鍵詞(RoutingKey)的訊息給訂閱該關鍵詞的Queue。
 
場景示例:訊息傳送方傳送了型別為[error][info]的兩種訊息,寫磁碟的訊息接受者只接受error型別的訊息,Console列印的接收兩者。
 
(上圖採用了不同顏色來作為routingKey)
 
傳送方
 
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "direct"/*exchange型別為direct*/);
 
channel.basicPublish(EXCHANGE_NAME, "info"/*關鍵詞=info*/, null, message.getBytes());
channel.close();
connection.close();
 
接收方
 
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "direct"/*exchange型別為direct*/);
// 建立匿名Queue
String queueName = channel.queueDeclare().getQueue();
// 訂閱某個關鍵詞,繫結到匿名Queue中
channel.queueBind(quueName,EXCHANGE_NAME,"error");
channel.queueBind(quueName,EXCHANGE_NAME,"info");
 
QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(queueName, true, consumer);
 
QueueingConsumer.Delivery delivery = consumer.nextDelivery(); // Blocking...
String message = new String(delivery.getBody());
String routingKey = delivery.getEnvelope().getRoutingKey(); // 可獲取路由關鍵詞

 


關鍵詞模式路由:Topics
 
這種模式可以看做對Routing的擴充套件。Routing只能使用固定關鍵詞,而Topics模式可以訂閱模糊關鍵詞
 
關鍵詞必須是一組word,由點號分割。例如"xxx.yyy.zzz",限定255bytes。
* 表示一個word;
# 表示0個或者多個word;
 
 
傳送方
 
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "topic"/*exchange型別*/);
 
channel.basicPublish(EXCHANGE_NAME, "xxx.yyy"/*關鍵詞routingKey*/, null, message.getBytes());
channel.close();
connection.close();

 

接收方
 
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "topic"/*exchange型別*/);
// 建立匿名Queue
String queueName = channel.queueDeclare().getQueue();
// 訂閱某個關鍵詞,繫結到匿名Queue中
channel.queueBind(quueName,EXCHANGE_NAME,"*.yyy");
 
QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(queueName, true, consumer);
 
QueueingConsumer.Delivery delivery = consumer.nextDelivery(); // Blocking...
String message = new String(delivery.getBody());
String routingKey = delivery.getEnvelope().getRoutingKey(); // 可獲取路由關鍵詞

 


Refs
 

相關文章