目录

成为死信的条件 

消息TTL过期 

 队列达到最大长度

 消息被拒

延迟队列

 延迟队列使用场景

 消息设置 TTL

队列设置 TTL

 两者区别

 

producer

将消息投递到

broker

或者直接到

queue

里了,

consumer

queue

取出消息

进行消费,但某些时候由于特定的

原因导致

queue

中的某些消息无法被消费

,这样的消息如果没有后续的处理,就变成了死信,有死信自然就有了死信队列。

成为死信的条件 

超过消息的存活时间(TTL):可以为消息设置一个存活时间,在该时间段之后,如果消息还未被消费或者被重新投递到其他队列,该消息将成为死信。 消息被拒绝(Reject):当消息被消费者拒绝接收时,可以选择将该消息重新投递到另一个队列或将其标记为死信。 消息达到最大重试次数:可以通过在消费者端设置重试次数限制,当消息达到一定的重试次数而仍然无法被消费时,该消息将成为死信。 队列满溢(Queue Overflow):当一个队列的消息数量已经超过队列的最大容量限制时,新消息无法进入队列,而被视为死信。

 

消息TTL过期 

生产者 

import com.rabbitmq.client.AMQP;

import com.rabbitmq.client.BuiltinExchangeType;

import com.rabbitmq.client.Channel;

public class Producer {

private static final String NORMAL_EXCHANGE = "normal_exchange";

public static void main(String[] argv) throws Exception {

try (Channel channel = RabbitMqUtils.getChannel()) {

channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);

//设置消息的 TTL 时间

AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("10000").build();

//该信息是用作演示队列个数限制

for (int i = 1; i <11 ; i++) {

String message="info"+i;

channel.basicPublish(NORMAL_EXCHANGE, "zhangsan", properties,

message.getBytes());

System.out.println("生产者发送消息:"+message);

}

}

}

}

 消费者1

import com.rabbitmq.client.BuiltinExchangeType;

import com.rabbitmq.client.Channel;

import com.rabbitmq.client.DeliverCallback;

import java.util.HashMap;

import java.util.Map;

public class Consumer01 {

//普通交换机名称

private static final String NORMAL_EXCHANGE = "normal_exchange";

//死信交换机名称

private static final String DEAD_EXCHANGE = "dead_exchange";

public static void main(String[] argv) throws Exception {

Channel channel = RabbitMqUtils.getChannel();

//声明死信和普通交换机 类型为 direct

channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);

channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);

//声明死信队列

String deadQueue = "dead-queue";

channel.queueDeclare(deadQueue, false, false, false, null);

//死信队列绑定死信交换机与 routingkey

channel.queueBind(deadQueue, DEAD_EXCHANGE, "lisi");

//正常队列绑定死信队列信息

Map params = new HashMap<>();

//正常队列设置死信交换机 参数 key 是固定值

params.put("x-dead-letter-exchange", DEAD_EXCHANGE);

//正常队列设置死信 routing-key 参数 key 是固定值

params.put("x-dead-letter-routing-key", "lisi");

String normalQueue = "normal-queue";

channel.queueDeclare(normalQueue, false, false, false, params);

channel.queueBind(normalQueue, NORMAL_EXCHANGE, "zhangsan");

System.out.println("等待接收消息.....");

DeliverCallback deliverCallback = (consumerTag, delivery) -> {

String message = new String(delivery.getBody(), "UTF-8");

System.out.println("Consumer01 接收到消息"+message);

};

channel.basicConsume(normalQueue, true, deliverCallback, consumerTag -> {

});

}

}

消费者2

import com.rabbitmq.client.BuiltinExchangeType;

import com.rabbitmq.client.Channel;

import com.rabbitmq.client.DeliverCallback;

public class Consumer02 {

private static final String DEAD_EXCHANGE = "dead_exchange";

public static void main(String[] argv) throws Exception {

Channel channel = RabbitMqUtils.getChannel();

channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);

String deadQueue = "dead-queue";

channel.queueDeclare(deadQueue, false, false, false, null);

channel.queueBind(deadQueue, DEAD_EXCHANGE, "lisi");

System.out.println("等待接收死信队列消息.....");

DeliverCallback deliverCallback = (consumerTag, delivery) -> {

String message = new String(delivery.getBody(), "UTF-8");

System.out.println("Consumer02 接收死信队列的消息" + message);

};

channel.basicConsume(deadQueue, true, deliverCallback, consumerTag -> {

});

}

}

关闭消费者1,模拟出故障

正常队列

 消息超时进入死信队列

 死信队列接收信息

 队列达到最大长度

生产者

import com.rabbitmq.client.BuiltinExchangeType;

import com.rabbitmq.client.Channel;

public class Producer {

private static final String NORMAL_EXCHANGE = "normal_exchange";

public static void main(String[] argv) throws Exception {

try (Channel channel = RabbitMqUtils.getChannel()) {

channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);

//该信息是用作演示队列个数限制

for (int i = 1; i <11 ; i++) {

String message="info"+i;

channel.basicPublish(NORMAL_EXCHANGE,"zhangsan",null, message.getBytes());

System.out.println("生产者发送消息:"+message);

}

}

}

}

 消费者1

import com.rabbitmq.client.BuiltinExchangeType;

import com.rabbitmq.client.Channel;

import com.rabbitmq.client.DeliverCallback;

import java.util.HashMap;

import java.util.Map;

public class Consumer01 {

//普通交换机名称

private static final String NORMAL_EXCHANGE = "normal_exchange";

//死信交换机名称

private static final String DEAD_EXCHANGE = "dead_exchange";

public static void main(String[] argv) throws Exception {

Channel channel = RabbitMqUtils.getChannel();

//声明死信和普通交换机 类型为 direct

channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);

channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);

//声明死信队列

String deadQueue = "dead-queue";

channel.queueDeclare(deadQueue, false, false, false, null);

//死信队列绑定死信交换机与 routingkey

channel.queueBind(deadQueue, DEAD_EXCHANGE, "lisi");

//正常队列绑定死信队列信息

Map params = new HashMap<>();

//正常队列设置死信交换机 参数 key 是固定值

params.put("x-dead-letter-exchange", DEAD_EXCHANGE);

//正常队列设置死信 routing-key 参数 key 是固定值

params.put("x-dead-letter-routing-key", "lisi");

// 设置正常队列长度的限制

params.put("x-max-length",6);

String normalQueue = "normal-queue";

channel.queueDeclare(normalQueue, false, false, false, params);

channel.queueBind(normalQueue, NORMAL_EXCHANGE, "zhangsan");

System.out.println("等待接收消息.....");

DeliverCallback deliverCallback = (consumerTag, delivery) -> {

String message = new String(delivery.getBody(), "UTF-8");

System.out.println("Consumer01 接收到消息"+message);

};

channel.basicConsume(normalQueue, true, deliverCallback, consumerTag -> {

});

}

}

 消费者2

import com.rabbitmq.client.BuiltinExchangeType;

import com.rabbitmq.client.Channel;

import com.rabbitmq.client.DeliverCallback;

public class Consumer02 {

private static final String DEAD_EXCHANGE = "dead_exchange";

public static void main(String[] argv) throws Exception {

Channel channel = RabbitMqUtils.getChannel();

channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);

String deadQueue = "dead-queue";

channel.queueDeclare(deadQueue, false, false, false, null);

channel.queueBind(deadQueue, DEAD_EXCHANGE, "lisi");

System.out.println("等待接收死信队列消息.....");

DeliverCallback deliverCallback = (consumerTag, delivery) -> {

String message = new String(delivery.getBody(), "UTF-8");

System.out.println("Consumer02 接收死信队列的消息" + message);

};

channel.basicConsume(deadQueue, true, deliverCallback, consumerTag -> {

});

}

}

关闭消费者1,模拟接收不到信息

 死信队列消费了四个消息

 分析:生产者产生10个消息,正常队列只能接受6个消息,多的消息便被转移到死信队列去了

 消息被拒

生产者

import com.rabbitmq.client.BuiltinExchangeType;

import com.rabbitmq.client.Channel;

public class Producer {

private static final String NORMAL_EXCHANGE = "normal_exchange";

public static void main(String[] argv) throws Exception {

try (Channel channel = RabbitMqUtils.getChannel()) {

channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);

//该信息是用作演示队列个数限制

for (int i = 1; i <11 ; i++) {

String message="info"+i;

channel.basicPublish(NORMAL_EXCHANGE,"zhangsan",null, message.getBytes());

System.out.println("生产者发送消息:"+message);

}

}

}

}

消费者1

import com.rabbitmq.client.BuiltinExchangeType;

import com.rabbitmq.client.Channel;

import com.rabbitmq.client.DeliverCallback;

import java.util.HashMap;

import java.util.Map;

public class Consumer01 {

//普通交换机名称

private static final String NORMAL_EXCHANGE = "normal_exchange";

//死信交换机名称

private static final String DEAD_EXCHANGE = "dead_exchange";

public static void main(String[] argv) throws Exception {

Channel channel = RabbitMqUtils.getChannel();

//声明死信和普通交换机 类型为 direct

channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);

channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);

//声明死信队列

String deadQueue = "dead-queue";

channel.queueDeclare(deadQueue, false, false, false, null);

//死信队列绑定死信交换机与 routingkey

channel.queueBind(deadQueue, DEAD_EXCHANGE, "lisi");

//正常队列绑定死信队列信息

Map params = new HashMap<>();

//正常队列设置死信交换机 参数 key 是固定值

params.put("x-dead-letter-exchange", DEAD_EXCHANGE);

//正常队列设置死信 routing-key 参数 key 是固定值

params.put("x-dead-letter-routing-key", "lisi");

String normalQueue = "normal-queue";

channel.queueDeclare(normalQueue, false, false, false, params);

channel.queueBind(normalQueue, NORMAL_EXCHANGE, "zhangsan");

System.out.println("等待接收消息.....");

DeliverCallback deliverCallback = (consumerTag, delivery) -> {

String message = new String(delivery.getBody(), "UTF-8");

if(message.equals("info5")){

System.out.println("Consumer01 接收到消息" + message + "并拒绝签收该消息");

//requeue 设置为 false 代表拒绝重新入队 该队列如果配置了死信交换机将发送到死信队列中

channel.basicReject(delivery.getEnvelope().getDeliveryTag(), false);

}else {

System.out.println("Consumer01 接收到消息"+message);

channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

}

};

boolean autoAck = false;

channel.basicConsume(normalQueue, autoAck, deliverCallback, consumerTag -> {

});

}

}

 消费者2

import com.rabbitmq.client.BuiltinExchangeType;

import com.rabbitmq.client.Channel;

import com.rabbitmq.client.DeliverCallback;

public class Consumer02 {

private static final String DEAD_EXCHANGE = "dead_exchange";

public static void main(String[] argv) throws Exception {

Channel channel = RabbitMqUtils.getChannel();

channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);

String deadQueue = "dead-queue";

channel.queueDeclare(deadQueue, false, false, false, null);

channel.queueBind(deadQueue, DEAD_EXCHANGE, "lisi");

System.out.println("等待接收死信队列消息.....");

DeliverCallback deliverCallback = (consumerTag, delivery) -> {

String message = new String(delivery.getBody(), "UTF-8");

System.out.println("Consumer02 接收死信队列的消息" + message);

};

channel.basicConsume(deadQueue, true, deliverCallback, consumerTag -> {

});

}

}

 结果

消费者1,拒绝接受消息info5,info5进入死信队列

 消费者2,死信队列接受到info5

延迟队列

延时队列

,

队列内部是有序的,最重要的特性就体现在它的延时属性上,延时队列中的元素是希望

在指定时间到了以后或之前取出和处理,简单来说,延时队列就是用来存放需要在指定时间被处理的 元素的队列。

 延迟队列使用场景

1.

订单在十分钟之内未支付则自动取消

2.

新创建的店铺,如果在十天内都没有上传过商品,则自动发送消息提醒。

3.

用户注册成功后,如果三天内没有登陆则进行短信提醒。

4.

用户发起退款,如果三天内没有得到处理则通知相关运营人员。

5.

预定会议后,需要在预定的时间点前十分钟通知各个与会人员参加会议

 消息设置 TTL

 

import com.rabbitmq.client.AMQP;

import com.rabbitmq.client.BuiltinExchangeType;

import com.rabbitmq.client.Channel;

public class Producer {

private static final String NORMAL_EXCHANGE = "normal_exchange";

public static void main(String[] argv) throws Exception {

try (Channel channel = RabbitMqUtils.getChannel()) {

channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);

//设置消息的 TTL 时间

AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("10000").build();

//该信息是用作演示队列个数限制

for (int i = 1; i <11 ; i++) {

String message="info"+i;

channel.basicPublish(NORMAL_EXCHANGE, "zhangsan", properties,

message.getBytes());

System.out.println("生产者发送消息:"+message);

}

}

}

}

队列设置 TTL

import com.rabbitmq.client.BuiltinExchangeType;

import com.rabbitmq.client.Channel;

import com.rabbitmq.client.DeliverCallback;

import java.util.HashMap;

import java.util.Map;

public class Consumer01 {

//普通交换机名称

private static final String NORMAL_EXCHANGE = "normal_exchange";

//死信交换机名称

private static final String DEAD_EXCHANGE = "dead_exchange";

public static void main(String[] argv) throws Exception {

Channel channel = RabbitMqUtils.getChannel();

//声明死信和普通交换机 类型为 direct

channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);

channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);

//声明死信队列

String deadQueue = "dead-queue";

channel.queueDeclare(deadQueue, false, false, false, null);

//死信队列绑定死信交换机与 routingkey

channel.queueBind(deadQueue, DEAD_EXCHANGE, "lisi");

//正常队列绑定死信队列信息

Map params = new HashMap<>();

//正常队列设置死信交换机 参数 key 是固定值

params.put("x-dead-letter-exchange", DEAD_EXCHANGE);

//正常队列设置死信 routing-key 参数 key 是固定值

params.put("x-dead-letter-routing-key", "lisi");

// 设置 TTL 值为 5000 毫秒(5 秒)

params.put("x-message-ttl", 5000);

String normalQueue = "normal-queue";

channel.queueDeclare(normalQueue, false, false, false, params);

channel.queueBind(normalQueue, NORMAL_EXCHANGE, "zhangsan");

System.out.println("等待接收消息.....");

DeliverCallback deliverCallback = (consumerTag, delivery) -> {

String message = new String(delivery.getBody(), "UTF-8");

if(message.equals("info5")){

System.out.println("Consumer01 接收到消息" + message + "并拒绝签收该消息");

//requeue 设置为 false 代表拒绝重新入队 该队列如果配置了死信交换机将发送到死信队列中

channel.basicReject(delivery.getEnvelope().getDeliveryTag(), false);

}else {

System.out.println("Consumer01 接收到消息"+message);

channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

}

};

boolean autoAck = false;

channel.basicConsume(normalQueue, autoAck, deliverCallback, consumerTag -> {

});

}

}

 两者区别

如果设置了队列的

TTL

属性,那么一旦消息过期,就会被队列丢弃

(

如果配置了死信队列被丢到死信队列中)

,而第二种方式,消息即使过期,也不一定会被马上丢弃,因为

消息是否过期是在即将投递到消费者

之前判定的

,如果当前队列有严重的消息积压情况,则已过期的消息也许还能存活较长时间;另外,还需 要注意的一点是,如果不设置 TTL

,表示消息永远不会过期,如果将

TTL

设置为

0

,则表示除非此时可以 直接投递该消息到消费者,否则该消息将会被丢弃。

 

精彩链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: