rabbitMQ的高级特性
使用这些特性解决一些特定的问题
1. 限制消费者每秒从队列拉取的消息的数量
如果并发数量很高,那么这个时候队列中就会有很多消息等待处理,如果不限制消费者的拉取数量,消费者就会每秒拉取很多的消息,最后还是会达到一个很高的并发数,消费者服务器照样存在崩溃的可能性。
使用前提:消费者采用的是手动确认模式
修改配置文件,这里使用的是yml格式
spring:
rabbitmq:
listener:
simple:
acknowledge-mode: manual
prefetch: 1000 # 这个数量需要根据机器性能自己进行调节,这里只是一个演示
2. 设置队列/消息的过期时间
给队列设置过期时间
队列的过期时间并不是说到达了时间这个队列被删除。
设置队列的过期时间是指:
给队列中的每一个消息都设置一个过期时间,从消息进入该队列开始计算时间,
如果消息还未被消费就过期,那么该消息将不会获得被消费的机会。
但并不是直接删除该消息,而且该消息到达队首的时候进行删除,该消息不会被消费
如果给消息单独设置了过期时间,那么队列的过期时间不会生效
给队列设置过期,在创建队列的时候就可以进行指定过期了
代码:
@Bean("queue1")
public Queue buildQueue1() {
// ttl 中的过期时间单位是 ms(毫秒)
return QueueBuilder.durable(queue1).ttl(3000).build();
}
除了使用 ttl() 之外,还可以这样,ttl其实就是调用了这个方法
@Bean("queue1")
public Queue buildQueue1() {
return QueueBuilder.durable(queue1)
.withArgument("x-message-ttl", 3000) // ttl其实就是调用了这个方法
.build();
}
给消息设置过期时间:
在给发送消息时 创建一个消息发送处理器(MessagePostProcessor)进行设置,不推荐和队列过期时间一起设置
代码: 这里使用的是springboot的测试方法
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
void contextLoads() {
Map<String, Object> message = new HashMap<>();
message.put("product_id", 10);
message.put("num", 50);
message.put("price", 600);
MessagePostProcessor messagePostProcessor = message1 -> {
message1.getMessageProperties().setExpiration("3000");
return message1;
};
/*
* String exchange 交换机名称
* String routingKey 路由key
* final Object object 要发送的消息
* MessagePostProcessor messagePostProcessor 消息发送处理器
*/
for (int i = 0; i < 10000; i++) {
rabbitTemplate.convertAndSend(MyConfig.exchange
, "lazy.orange.abc"
, JSON.toJSONString(message), messagePostProcessor);
}
}
3. 死信交换机
死信交换机简单来说就是:“死掉”的消息使用的一个交换机
死信交换机英文为 Dead Letter Exchange(DLX)
消息成为死信的三种情况:
1. 队列消息长度达到了最大长度的限制
2. 消费者没有确认消息,并且不允许消息重新发送
3. 消息超时未被消费
死信交换机图示:
当消息队列中的消息成为死信的时候,消息会被发送到死信交换机。
死信交换机和正常的交换机是一样的,只是用来处理死信的交换机。
死信交换机和普通交换机并没有什么本质的不同。
在使用死信交换机的时候,死信队列就成为了死信交换机的消费者。
在新建队列的时候指定死信交换机:
这里只写出 核心代码
// 死信交换机的名称
public static String exchange_name02="dead-exchange";
/**
* 创建死信交换机,和创建普通交换机的方式一样
* @return
*/
@Bean(value = "deadExchange")
public Exchange buildDeadExchange(){
return ExchangeBuilder.topicExchange(exchange_name02).build();
}
/**
* 创建队列,并且绑定死信交换机,
* 给死信交换机发消息的时候,发消息的队列充当死信交换机的生产者
* @return
*/
@Bean("queue01")
public Queue buildQueue01(){
//withArgument("x-message-ttl",10000):设置队列的过期时间
return QueueBuilder.durable(queue_name01).
// 设置队列超时时间 30s
withArgument("x-message-ttl",30000)
//设置队列的最大容量
.withArgument("x-max-length",10)
//队列与死信交换机绑定
.withArgument("x-dead-letter-exchange",exchange_name02)
//队列发送消息时需要绑定的routing-key
.withArgument("x-dead-letter-routing-key","abc")
.build();
}
/**
* 队列02和死信交换机进行绑定
*/
@Bean
public Binding binding02(Queue queue02,Exchange deadExchange){
return BindingBuilder.bind(queue02).to(deadExchange).with("abc").noargs();
}
在创建队列时限制队列长度的方法:
@Bean("queue01")
public Queue buildQueue01(){
return QueueBuilder.durable(queue_name01).
//设置队列的最大容量
.withArgument("x-max-length",10)
.build();
}
4. 延迟队列
也就是消息进入队列之后不会被立即进行消费,只有在到达了指定时间后,这个消息才会被消费。
但是在RabbitMQ 中并没有提供延迟队列,但是可以通过: 消息的过期时间 + 死信队列
的方式实现延迟效果
实现思路:
1. 给需要延迟的消息设置过期时间,然后发送到队列中(队列一)
2. 给该队列(队列一)绑定一个死信交换机
3. 死信交换机将消息转发道对应的队列中(队列二)
4. 让消费者监听存放延迟死信的队列(队列二)
图解: