rabbitmq 操作记录
当前记录的版本为 springboot2 及以上版本
问题一 :同一个队列,两个不同类型的消费者监听(一个消费者为手动ack,一个消费者为自动ack) ,当消息数量不多的时候,消费日志打印信息只有其中某一个队列在处理。没有办法两个队列同时工作。
当前只有默认的5个消费者
测试 消费端方法进入直接 手动ACK 之后,然后休眠等待10min查看队列数据信息
消费端代码如下,当修改端启动之后,
package com.example.customer;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@SpringBootApplication
public class CustomerApplication {
public static void main(String[] args) {
SpringApplication.run(CustomerApplication.class, args);
}
@Component
public class Customer {
@Bean
public SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory(@Autowired ConnectionFactory
connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
// 设置消费者个数
factory.setConcurrentConsumers(5);
factory.setMaxConcurrentConsumers(10);
factory.setConnectionFactory(connectionFactory);
// 设置此容器需要 手动ack
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
return factory;
}
@RabbitListener(queues = "local_test",
containerFactory = "simpleRabbitListenerContainerFactory")
public void test(String message1, Message message, Channel channel) {
try {
// 每个消费者第一次进入此代码之后, 消息队列中的会直接丢弃
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
System.out.println("----------->" + message1);
// 此时会休眠等待
TimeUnit.MINUTES.sleep(10L);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
}
执行后。消费端数据信息
控制台信息
新增 一个自动ACK的消费端
package com.example.customer;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@SpringBootApplication
public class CustomerApplication {
public static void main(String[] args) {
SpringApplication.run(CustomerApplication.class, args);
}
@Component
public class Customer {
@Bean
public SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory(@Autowired ConnectionFactory
connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConcurrentConsumers(5);
factory.setMaxConcurrentConsumers(10);
factory.setConnectionFactory(connectionFactory);
// 设置此容器需要 手动ack
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
return factory;
}
@RabbitListener(queues = "local_test",
containerFactory = "simpleRabbitListenerContainerFactory")
public void test(String message1, Message message, Channel channel) {
try {
// 每个消费者第一次进入此代码之后, 消息队列中的会直接丢弃
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
System.out.println("----------->" + message1);
// 此时会休眠等待,此后不会
TimeUnit.MINUTES.sleep(10L);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
//新增 自动ack
@RabbitListener(queues = "local_test")
public void test1(String message1, Message message, Channel channel) {
System.out.println("消费者2 -->" + message1);
}
}
}
当前消息数量
项目启动,发现消费者数量增加,但是控制台并没有打印消费者2的消费日志信息;打印的依旧是 5个消费者1的日志信息
再看mq管理页面信息; 5个消息被消费了;还有1230个等待ACK
正常理解应该是 消费2会把后面消息消费掉才对,但是实际并没有消费; 原因是因为
当前每个消费者的 prefetch count 预取消息数量为 250 ;
由上面的代码 ,有5个队列监听参数使用了 SimpleRabbitListenerContainerFactory 来执行手动ACK; 每个消费者预取消息数为250; 5个可预取的消息数为 5 * 250 = 1250 条;导致 队列的1235个消息(1235 < 1250)被前5个队列 预取,导致消费者2没有可消费的消息。所以消费者2 控制台没有打印任何日志信息;
修改待消费数量,验证消费者2会把 剩余的消息消费掉
新发送一万条消息
开启消费端。消费结果
控制台打印日志信息
mq管理页面消息数量
有1250个消息待ACK
问题答案
当前的消息预处理数较多,消息数量不多,导致所有消息被其中的一个队列全部拉取到了,另外一个队列无法获取消费