Round-robin dispatching
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//it will only be created if it doesn't exist already
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
String[] messages = new String[]{"11 message.","21 message..","31 message...","41 message....","51 message.....","61 message.....","71 message.....","81 message.....","91 message....."};
for(String msg : messages){
channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
//channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, msg.getBytes());
System.out.println(" [x] Sent '" + msg + "'");
}
channel.close();
connection.close();
编写两个rabbitmq-consumer端代码:(两个consumer是一样的即可)
package yzr.main;
import java.io.IOException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
public class Worker {
private final static String QUEUE_NAME = "hello";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
boolean durable = true;
channel.queueDeclare(QUEUE_NAME, durable, false, false, null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
//channel.basicQos(30);
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
try {
doWork(message);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(" [x] Done");
}
}
};
boolean autoAck = true;
channel.basicConsume(QUEUE_NAME, autoAck, consumer);
}
private static void doWork(String task) throws InterruptedException {
for (char ch: task.toCharArray()) {
if (ch == '.') Thread.sleep(1000);
}
}
}
[x] Sent '21 message..'
[x] Sent '31 message...'
[x] Sent '41 message....'
[x] Sent '51 message.....'
[x] Sent '61 message.....'
[x] Sent '71 message.....'
[x] Sent '81 message.....'
[x] Sent '91 message.....'
[x] Done
[x] Received '31 message...'
[x] Done
[x] Received '51 message.....'
[x] Done
[x] Received '71 message.....'
[x] Done
[x] Received '91 message.....'
[x] Done
[x] Received '21 message..'
[x] Done
[x] Received '41 message....'
[x] Done
[x] Received '61 message.....'
[x] Done
[x] Received '81 message.....'
[x] Done
Message acknowledgment
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME, autoAck, consumer);
将此处的autoAck的值设为false之后,我们发现当send端发送消息之后,当接受消息的consumer端挂掉之后,rabbitmq会将消息发往到正常的consumer,(消息不会丢失)
[x] Sent '21 message..'
[x] Sent '31 message...'
[x] Sent '41 message....'
[x] Sent '51 message.....'
[x] Sent '61 message.....'
[x] Sent '71 message.....'
[x] Sent '81 message.....'
[x] Sent '91 message.....'
rabbitmqctl.bat list_queues name messages_ready messages_unacknowledged
//确认消息消费
channel.basicAck(envelope.getDeliveryTag(), true);
完整的代码:
package yzr.main;
import java.io.IOException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
public class Worker2 {
private final static String QUEUE_NAME = "hello";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
boolean durable = false;
channel.queueDeclare(QUEUE_NAME, durable, false, false, null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
//int prefetchCount = 100;
//channel.basicQos(prefetchCount);
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
try {
doWork(message);
//确认消息消费
channel.basicAck(envelope.getDeliveryTag(), true);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(" [x] Done");
}
}
@Override
public void handleConsumeOk(String consumerTag) {
System.out.println(consumerTag+" reisgter");
}
};
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME, autoAck, consumer);
}
private static void doWork(String task) throws InterruptedException {
for (char ch: task.toCharArray()) {
if (ch == '.') Thread.sleep(1000);
}
}
}
Message durability
消息持久化,比如当我们重启rabbitmqserver服务器的时候,send端发送的消息(已经保存在rabbitmq中的消息)将会全部丢失,为了保证服务器不正常(包括重启)的情况下,保存在服务器中的消息不会丢失,我们可以将发送的消息设置为持久化,即使重启服务器,只要服务器能正常工作的情况下,消息就可以正常获取到. boolean durable = true;
channel.queueDeclare(QUEUE_NAME, durable, false, false, null);
....
channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, msg.getBytes());
[x] Sent '211 message..'
[x] Sent '311 message...'
[x] Sent '411 message....'
[x] Sent '511 message.....'
[x] Sent '611 message.....'
[x] Sent '711 message.....'
[x] Sent '811 message.....'
[x] Sent '911 message.....'
Marking messages as persistent doesn't fully guarantee that a message won't be lost. Although it tells RabbitMQ to save the message to disk, there is still a short time window when RabbitMQ has accepted a message and hasn't saved it yet. Also, RabbitMQ doesn't do fsync(2) for every message -- it may be just saved to cache and not really written to the disk. The persistence guarantees aren't strong, but it's more than enough for our simple task queue.
Fair dispatch
设置consumer接收消息的数量最大值:
int prefetchCount = 100;
channel.basicQos(prefetchCount);
consumer只会最多接收指定的条数的消息,比如这里指定了100,那么即使send端发送了101条消息到这里,此consumer只会接收100条.超出的消息会发送到另外一个不忙的consumer中.
In order to defeat that we can use the basicQos method with the prefetchCount = 1 setting. This tells RabbitMQ not to give more than one message to a worker at a time. Or, in other words, don't dispatch a new message to a worker until it has processed and acknowledged the previous one. Instead, it will dispatch it to the next worker that is not still busy.