在现在的APP上基本都会用到这个延迟队列的思想。
应用场景:
- 某团,某了么下订单未支付,一般30分钟没有支付,自动取消订单。
- 某app注册账号通过手机号注册,信息验证码 当验证码过一分钟,则取消该验证码的使用。
RabbitMQ实现延迟队列需要通过2个重要概念:消息的TTL和死信Exchange。
1.消息的TTL(Time To Live)
RabbitMQ设置消息过期时间的有2种方法:
- 消息的的过期时间设置,expiration字段
- 队列的过期时间设置,x-message-ttl属性
注意:当2个时间都设置的时候,系统默认选择最小的。
超过了这个时间,我们认为这个消息就死了,称之为死信。这里单讲单个消息的TTL,因为它才是实现延迟任务的关键。
AMQP.BasicProperties properties = new AMQP.BasicProperties();
properties.setExpiration("60000");
当上面的消息扔到队列中后,过了60秒,如果没有被消费,它就死了。不会被消费者消费到。这个消息后面的,没有“死掉”的消息对顶上来,被消费者消费。死信在队列中并不会被删除和释放,它会被统计到队列的消息数中去。单靠死信还不能实现延迟任务,还要靠Dead Letter Exchange。
2.Dead Letter Exchanges
消息进入死信路由需具备一下三个条件:
- 一个消息被Consumer拒收了,并且reject方法的参数里requeue是false。也就是说不会被再次放在队列里,被其他消费者使用。
-
上面的消息的TTL到了,消息过期了。
-
队列的长度限制满了。排在前面的消息会被丢弃或者扔到死信路由上。
实现延迟队列
延迟任务通过消息的TTL和Dead Letter Exchange来实现。我们需要建立2个队列,一个用于发送消息,一个用于消息过期后的转发目标队列。
具体步骤:第一步, 首先需要创建2个队列。Queue1和Queue2。Queue1是一个消息缓冲队列,在这个队列里面实现消息的过期转发。如图,设置Dead letter exchange和Dead letter routing key。设置这两个属性就是当消息在这个队列中expire后,采用哪个路由发送。这个dlx的exchange需要事先创建好,就是一个普通的exchange。由于我们还需要向Queue1发送消息,那么还需要创建一个exchange,并且和Queue1绑定。例子中,exchange同样取名:queue1。