死信队列就是当消息发送失败达到了一个阈值后,消息被从正常的消息队列里移除,添加到了一个系统创建的一个%DLQ%XXX这样格式的一个队列里,不再被消费。
重试次数
以下是RocketMQ默认的失败重试次数,以及每次间隔的时间,即从第一次失败起,会在接下来的4小时46分钟进行16次的重试。
测试案例
producer
public class ProducerSync {
public static void main(String[] args) throws MQClientException, MQBrokerException, RemotingException, InterruptedException {
//创建生产者
DefaultMQProducer producer = new DefaultMQProducer(RocketConstant.DEFAULT_PRODUCER_GROUP);
//绑定nameserver
producer.setNamesrvAddr(RocketConstant.NAME_SERVER_ADDR);
producer.start();
//组装消息:发送的topic,发送的消息
Message message = new Message(RocketConstant.DEFAULT_TOPIC,("Hello Dead RocketMQ").getBytes(StandardCharsets.UTF_8));
//同步发送
SendResult sendResult = producer.send(message);
System.out.println(sendResult);
}
}
consumer
consumer.setMaxReconsumeTimes(1),把重试次数调整为1,让能更快看到效果。
public class Consumer {
public static void main(String[] args) throws MQClientException {
//创建生产者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(RocketConstant.DEFAULT_CONSUMER_GROUP);
//绑定nameserver
consumer.setNamesrvAddr(RocketConstant.NAME_SERVER_ADDR);
//订阅topic,设置过滤规则
consumer.subscribe(RocketConstant.DEFAULT_TOPIC,"*");
//设置重试次数变为1,即10秒后会重试一次,若失败就放入死信队列
consumer.setMaxReconsumeTimes(1);
//注册监听,当队列有消息时,触发消费
//MessageListenerConcurrently,用的多线程模式消费,即使只有一个消费者也是并发消费的消息
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list,
ConsumeConcurrentlyContext consumeConcurrentlyContext) {
try {
for (int i = 0; i < list.size(); i++) {
MessageExt messageExt = list.get(i);
System.out.println(1/0);
System.out.println("收到消息:"+new String(messageExt.getBody()));
}
} catch (Exception e) {
e.printStackTrace();
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
}
}
输出结果
出现了两次异常
java.lang.ArithmeticException: / by zero
at com.learn.dead.Consumer$1.consumeMessage(Consumer.java:33)
at org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService$ConsumeRequest.run(ConsumeMessageConcurrentlyService.java:412)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
java.lang.ArithmeticException: / by zero
at com.learn.dead.Consumer$1.consumeMessage(Consumer.java:33)
at org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService$ConsumeRequest.run(ConsumeMessageConcurrentlyService.java:412)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
看控制台
控制台出现了一个死信队列,%DLQ%是固定前缀,后面跟着的是消费组名
此时需要注意的,死信队列对应Topic的权限默认是禁读的(perm, 2:禁读,4:禁写,6:可读可写),需把权限开放到6才能进行读,看下图配置。
consumerdead
消费死信队列消息,做重发或其他的业务逻辑
public class ConsumerDead {
public static void main(String[] args) throws MQClientException {
//创建生产者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(RocketConstant.DEFAULT_CONSUMER_GROUP);
//绑定nameserver
consumer.setNamesrvAddr(RocketConstant.NAME_SERVER_ADDR);
//订阅topic,设置过滤规则
consumer.subscribe("%DLQ%consumer_group","*");
//注册监听,当队列有消息时,触发消费
//MessageListenerConcurrently,用的多线程模式消费,即使只有一个消费者也是并发消费的消息
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list,
ConsumeConcurrentlyContext consumeConcurrentlyContext) {
try {
for (int i = 0; i < list.size(); i++) {
MessageExt messageExt = list.get(i);
System.out.println("消费死信队列消息:"+new String(messageExt.getBody()));
//TODO 重发或其他业务逻辑
}
} catch (Exception e) {
e.printStackTrace();
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
}
}
输出结果
消费死信队列消息:Hello Dead RocketMQ