文章目录
Work Queues模型
这种模型有一个生产者,两个消费者,一个队列。
生产者向"hello"队列发送消息。消费者从该队列接收消息。
循环调度
默认情况下,RabbitMQ 会按顺序将每条消息发送给下一个使用者。平均而言,每个使用者都会收到相同数量的消息。这种分发消息的方式称为循环调度。
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
=====2hello rabbitmq
=====4hello rabbitmq
=====6hello rabbitmq
=====8hello rabbitmq
=====10hello rabbitmq
=====12hello rabbitmq
=====14hello rabbitmq
=====16hello rabbitmq
=====18hello rabbitmq
=====20hello rabbitmq
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
=====1hello rabbitmq
=====3hello rabbitmq
=====5hello rabbitmq
=====7hello rabbitmq
=====9hello rabbitmq
=====11hello rabbitmq
=====13hello rabbitmq
=====15hello rabbitmq
=====17hello rabbitmq
=====19hello rabbitmq
消息确认机制
Problem:但是完成一项任务往往需要一段时间,如果一个消费者在执行任务期间宕机了,那么未被处理的消息就会全部丢失。
Solution:为了确保每一个消息都能被确认没有丢失,RabbitMQ就采用了消息确认的方式。只有当消费者返回给了RabbitMQ一个特定的消息告诉它这个消息已经从队列中正确接收,那么这条消息才会从队列中被移除。如果一个消费者宕机了(其通道关闭、连接关闭或 TCP 连接丢失)那么RabbitMQ 会知道消息没有完全处理,并将重新返回进队列。如果同时有其他在线消费者,它会迅速重新递送给其他消费者。这样,您就可以确保不会丢失任何消息,即使消费者偶尔会死亡。
1.开发消费者1(Accept1):
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMQUtils.getConnection("192.168.1.18", "/ems", 5672, "ems", "123");
Channel channel = connection.createChannel();
channel.basicConsume("hello", false, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("=====" + new String(body));
}
});
//channel.close();
//connection.close();
}
2.开发消费者2(Accept2):
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMQUtils.getConnection("192.168.1.18", "/ems", 5672, "ems", "123");
Channel channel = connection.createChannel();
channel.basicConsume("hello", false, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("=====" + new String(body));
channel.basicAck(envelope.getDeliveryTag(),false); //消费者返回给了RabbitMQ一个特定的消息告诉它这个消息已经从队列中正确接收
}
});
//channel.close();
//connection.close();
}
由于Accept1种没有加channel.basicAck(envelope.getDeliveryTag(),false);从而导致处理的十条消息没有被确认。当其断开连接的时候Accept2会帮忙处理Accept1处理但未被确认的消息。
3.测试结果:
公平派送(能者多得,弱者少得)
Problem:但是上面这些还不是我们想要的结果。举个例子,比如当任务繁重的时候,会出现一个消费者工作而另一个消费者完全空闲。这是因为 RabbitMQ 只是在消息进入队列时调度一条消息,它不查看使用者未确认的消息数。它只是盲目地将每条 n 消息都调度到 n - th 使用者。
Solution:为了解决这个问题,我们就要用到,*channel.basicQos(1);*去声明每次消息队列只分发给消费者一个消息,只有你返回给我确认了我才会给你发下一条消息。
1.开发消费者1(Accept1):
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMQUtils.getConnection("192.168.1.18", "/ems", 5672, "ems", "123");
Channel channel = connection.createChannel();
channel.basicQos(1);
channel.queueDeclare("hello", false, false, false, null);
channel.basicConsume("hello", false, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("=====" + new String(body));
channel.basicAck(envelope.getDeliveryTag(),false);
}
});
//channel.close();
//connection.close();
}
2.开发消费者2(Accept2):
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMQUtils.getConnection("192.168.1.18", "/ems", 5672, "ems", "123");
Channel channel = connection.createChannel();
channel.basicQos(1);
channel.queueDeclare("hello", false, false, false, null);
channel.basicConsume("hello", false, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("=====" + new String(body));
channel.basicAck(envelope.getDeliveryTag(),false);
}
});
//channel.close();
//connection.close();
}
由于Accept2中在回调方法执行的时候线程休眠了2000毫秒,导致返回确认消息延时,使得Accept1将所有的消息都已接受。形成了能者多得,弱者少得的现象。
3.测试结果: