消费者限流;设定每次消费者所取信息的条数,并且手动签收,可以有效地缓解服务器的压力
我在springboot中运行的,需要在配置文件中声明手动签收以及每次消费者所获得的信息数
listener:
simple:
max-concurrency: 1 #每次最多拿一条消息
acknowledge-mode: manual #手动ACK
TTL设置过期时间
可以将队列设置过期时间
可以将单条信息设置过期时间
若设置了队列过期时间和消息单独过期时间,按时间短的为准 消息过期时间到了,只有消息在队列顶端,才会去判断其是否过期
设置队列的过期时间
@Bean("bootQueue")
public Queue bootQueue(){
return QueueBuilder.durable(QUEUE_NAME)
.deadLetterExchange(DEAD_EXCHANGE_NAME) //绑定死信交换机的名称
.deadLetterRoutingKey("dead_ttl.Hello")
.ttl(20000) //设置队列过期事件 ,过期后进入死信队列
.maxLength(10)//设置队列最大容量,超过后进入死信队列
.build();
}
设置单个信息的过期时间(将第五条信息设置为过期时间5s)
@Test
public void test3() {
for (int i = 0; i < 10; i++) {
//此时消息并不在队列顶端,不会单独过期!
if (i == 5) {
rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, "boot.ttl", "test ttl rabbitmq", new MessagePostProcessor() {
/**
* 消息后处理对象,设置一些参数的信息
*/
@Override
public Message postProcessMessage(Message message) throws AmqpException {
//设置message的信息
message.getMessageProperties().setExpiration("5000"); //消息的过期时间
//返回该消息
return message;
}
});
} else {
//若设置了队列过期,所有消息等待过期
rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, "boot.ttl", "test ttl rabbitmq");
}
}
}
死信队列
成为死信队列的三种情况:
队列的过期时间到了
超过队列的最大空间
消费拒绝接受
步骤:
1.设置死信队列和死信交换机
@Bean("deadExchange")
public Exchange deadExchange(){
return ExchangeBuilder.topicExchange(DEAD_EXCHANGE_NAME).durable(true).build();
}
@Bean("deadQueue")
public Queue deadQueue(){
return QueueBuilder.durable(DEAD_QUEUE_NAME).build();
}
2.绑定死信队列和死信交换
@Bean
public Binding bindDeadQueueExchange(@Qualifier("deadQueue") Queue queue, @Qualifier("deadExchange")Exchange exchange ){
//return BindingBuilder.bind(queue).to(exchange).with("confirm").noargs();
return BindingBuilder.bind(queue).to(exchange).with("dead_ttl.#").noargs();
}
3.设计交换机的的空间大小以及过期时间和绑定死信交换机
@Bean("bootQueue")
public Queue bootQueue(){
return QueueBuilder.durable(QUEUE_NAME)
.deadLetterExchange(DEAD_EXCHANGE_NAME) //绑定死信交换机的名称
.deadLetterRoutingKey("dead_ttl.Hello")
.ttl(20000) //设置队列过期事件 ,过期后进入死信队列
.maxLength(10)//设置队列最大容量,超过后进入死信队列
.build();
}
接下来开始测试
@Test
public void testdead() {
//超过队列限制
// for (int i = 0; i < 20; i++) {
// rabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE_NAME, "ttl.ggg", "Message Confirm1");
// }
//正常队列的过期时间
// rabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE_NAME, "ttl.ggg", "huazi 6666");
//被消费者拒收
rabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE_NAME, "ttl.ggg", "huazi 6666");
}
前两种情况在可视化平台可以发现五秒后内容都进入了死信交换机,第三种情况需要在消费者端进行手动签收以及抛出异常后拒绝签收
public void onMessage(Message message, Channel channel) throws Exception {
/**
* void basicAck(long deliveryTag, boolean multiple) throws IOException;
* deliveryTag:收到的消息的标签
* multiple:是否接收多条消息
*/
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
//接受转换消息
System.out.println(new String(message.getBody()));
//处理业务逻辑
System.out.println("处理业务逻辑");
//手动签收
channel.basicAck(deliveryTag, true);
}catch (Exception e){
/**
*void basicNack(long deliveryTag, boolean multiple, boolean requeue)
*
* requeue:重回队列,若发送失败,消息重回queue,broker重新发送给consumer
*/
//拒绝签收
channel.basicNack(deliveryTag,true,true);
}
}
自此死信队列已将完成!!!
延迟队列
所谓延迟队列,就是ttl+死信队列,信息在普通队列中设置过期时间。假如说过期时间时30分钟,30分钟后信息已经过期,然后到达死信交换机再到死信队列,消费端可以接受到死心队列中的信息,步骤和之前的一样,唯一的区别在于消费端中的监听类需要监听的队列是死信交换机的队列而不是正常设置过期时间的队列。