使用案例
当消息处理比较耗时的时候,可能生产消息的速度会远远大于消息的消费速度。长此以往,消息就会堆积越来越多,无法及时处理。此时就可以使用work 模型:让多个消费者绑定到一个队列,共同消费队列中的消息。队列中的消息一旦消费,就会消失,因此任务是不会被重复执行的。
编写工作队列的生产者代码
// 工作队列模式生产者 ( 生产者直接链接队列,没有交换器参与 )
@Test
void contextLoads2() throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("106.15.73.43");
connectionFactory.setVirtualHost("/rabbitmq_zhj");
connectionFactory.setPort( 5672 );
connectionFactory.setUsername( "admin" );
connectionFactory.setPassword( "123" );
// 创建连接
Connection connection = connectionFactory.newConnection();
// 创建信道
Channel channel = connection.createChannel();
// 参数1:队列名 参数2: 队列是否持久化 参数3:是否独占队列 参数4:是否在消费后自动删除 参数5:其他属性
channel.queueDeclare("work",true,false,false,null );
//发布消息 参数1: 交换机名 参数2:队列名 参数3:MessageProperties.PERSISTENT_TEXT_PLAIN(持久化)传递消息的额外设置 参数4:消息的内容(字节)
for (Integer i = 0 ; i <= 10 ; i++){
channel.basicPublish("","work", MessageProperties.PERSISTENT_TEXT_PLAIN, i.toString().getBytes() );
}
// 关闭信道
channel.close();
// 关闭连接
connection.close();
}
编写工作队列的消费者者代码
消费者1
// 工作队列 消费者1
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("106.15.73.43");
connectionFactory.setVirtualHost("/rabbitmq_zhj");
connectionFactory.setPort( 5672 );
connectionFactory.setUsername( "admin" );
connectionFactory.setPassword( "123" );
// 创建连接
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("work", true, false ,false ,null);
channel.basicConsume( "work", true, new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body){
try {
Thread.sleep(1000); //处理消息比较慢 一秒处理一个消息
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println( "消费者2" + new String(body) );
}
});
}
消费者2
// 工作队列 消费者1
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("106.15.73.43");
connectionFactory.setVirtualHost("/rabbitmq_zhj");
connectionFactory.setPort( 5672 );
connectionFactory.setUsername( "admin" );
connectionFactory.setPassword( "123" );
// 创建连接
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("work", true, false ,false ,null);
channel.basicConsume( "work", true, new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body){
System.out.println( "消费者1" + new String(body) );
}
});
}
运行结果和分析
我们发现不管客户端的处理能力怎么样,消息都是平均分配的。这样的设计会产生一系列的问题,我们希望消息分配机制是能者多劳式的,其中与其相对应的是channel.basicConsume中消息的自动确认的参数,我们选择的是true,即消息的立即确认。我们需要将其设置为false,还有就是手动确认,以及信道的同时处理信息数量。需要注意的三个点如下。
//一次只接受一条未确认的消息
channel.basicQos( 1 );
// 关闭自动确认
channel.basicConsume( "work", false, new DefaultConsumer(channel);
// 手动确认
channel.basicAck(envelope.getDeliveryTag(), false);
队列模型的能者多劳模式
消费者1
// 工作队列 消费者1
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("106.15.73.43");
connectionFactory.setVirtualHost("/rabbitmq_zhj");
connectionFactory.setPort( 5672 );
connectionFactory.setUsername( "admin" );
connectionFactory.setPassword( "123" );
// 创建连接
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 设置信道的数据处理量
channel.basicQos( 1 );
channel.queueDeclare("work", true, 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 {
try {
Thread.sleep(1000); //处理消息比较慢 一秒处理一个消息
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println( "消费者1 : " + new String(body) );
channel.basicAck(envelope.getDeliveryTag(), false); // 手动确认
}
});
}
运行结果