死信队列
什么情况下消息会变为死信
- 队列达到最大长度
- 消息TTL过期
- 消息被拒绝(basic.reject / basic.nack),并且requeue = false
给队列设置参数的方式
新建一个Map<String,Object>的map集合,通过规定的键,可以给队列对应的属性设置值
键 | 用途 |
---|---|
“x-max-length” | 设置队列最大消息数量 |
"“x-message-ttl” | 设置队列中的消息多少ms后过期 |
“x-dead-letter-exchange” | 设置队列中的消息变为死信要放入的交换机名 |
“x-dead-letter-routing-key” | 设置队列中的消息变为死信的routing-key |
“x-max-length-bytes” | 队列中所有消息的总字节数上限值 |
队列达到最长
设置私信队列和死信交换机,和最大消息数量队列
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Configuration
public class RabbitMqConfig {
private static final String topicExchange="topicExchange";
private static final String topicRoutingkey="key.#";
private static final String fanoutExchange="fanoutExchange";
private static final String headsExchange="headsExchange";
private static final String deadExchange="deadExchange";
private static final String deadRoutingkey="deadkey";
@Bean
public FanoutExchange fanoutExchange(){
return new FanoutExchange(fanoutExchange,true,false);
}
@Bean
public DirectExchange deadExchange(){
return new DirectExchange(deadExchange,true,false);
}
@Bean
public Queue maxLengthQueue(){
Map<String,Object> map=new HashMap<>();
map.put("x-max-length",10);
map.put("x-dead-letter-exchange","deadExchange");
map.put("x-dead-letter-routing-key","deadkey");
return new Queue("maxLengthQueue",true,false,false,map);
}
@Bean
public Binding binding6(){
return BindingBuilder.bind(maxLengthQueue()).to(fanoutExchange());
}
@Bean
public Binding binding7(){
return BindingBuilder.bind(deadQueue()).to(deadExchange()).with(deadRoutingkey);
}
}
给maxLengthQueue添加15条消息
for(int i=0;i<15;i++){
rabbitTemplate.convertAndSend("fanoutExchange","","hi");
}
访问http://localhost:15672
5条多出的死信进入了死信队列
消息TTL过期
设置TTL过期队列
@Bean
public Queue messageTTlQueue(){
Map<String,Object> map=new HashMap<>();
map.put("x-message-ttl",10000);
map.put("x-dead-letter-exchange","deadExchange");
map.put("x-dead-letter-routing-key","deadkey");
return new Queue("messageTTlQueue",true,false,false,map);
}
@Bean
public Binding binding8(){
return BindingBuilder.bind(messageTTlQueue()).to(fanoutExchange());
}
给messageTTlQueue添加消息,访问http://localhost:15672
10s后消息进入死信队列
消息被拒绝(basic.reject / basic.nack),并且requeue = false
消费者拒绝消息,并且不再接收该消息,消息会放入死信队列中
配置文件再之前的基础上修改为
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
publisher-confirm-type: correlated #有这个才会回调
publisher-returns: true
listener:
type: simple
simple:
#手动确认
acknowledge-mode: manual
prefetch: 1 #限制每次发送一条数据。
concurrency: 3 #同一个队列启动几个消费者
max-concurrency: 3 #启动消费者最大数量
#重试策略相关配置
retry:
enabled: true #是否支持重试
max-attempts: 5
stateless: false
#时间策略乘数因子
multiplier: 1.0
initial-interval: 1000ms
max-interval: 10000ms
default-requeue-rejected: true
添加一待拒绝的个队列并绑定交换机
@Bean
public Queue rejectQueue(){
Map<String,Object> map=new HashMap<>();
map.put("x-dead-letter-exchange","deadExchange");
map.put("x-dead-letter-routing-key","deadkey");
return new Queue("rejectQueue",true,false,false,map);
}
@Bean
public Binding binding9(){
return BindingBuilder.bind(rejectQueue()).to(fanoutExchange());
}
添加一个消费者消费该队列并且拒绝该消息
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@RabbitListener(queues = "rejectQueue")
public class RejectConsumer {
@RabbitHandler
public void process(String s, Channel channel,Message message) throws Exception{
log.info(s);
channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
}
}
往队列中添加消息
@RequestMapping("/1")
@ResponseBody
public String test1(){
rabbitTemplate.convertAndSend("fanoutExchange","","reject message ");
return "3";
}
访问http://localhost:15672
在死信队列中找到该消息,并且死信来自于rejectQueue,消息变为死信的原因是rejected