场景: 比如未付款订单,超过一定时间后,系统自动取消订单并释放占有物品。
常用解决方案: spring的 schedule 定时任务轮询数据库
缺点: 消耗系统内存、增加了数据库的压力、存在较大的时间误差
解决:rabbitmq的消息TTL和死信Exchange结合
二、
1、消息的TTL(Time To Live)
消息的TTL就是消息的存活时间
2、RabbitMQ可以对队列和消息分别设置TTL
队列设置就是队列没有消费者连着的保留时间,也可以对没一个单独的消息做单独的设置。超过这个时间,我们认为这个消息死了,称之为死信
如果队列设置了,消息也设置了,那么会取小的。所以一个消息如果被路由到不同的队列中,这个消息的死亡时间又可能不一样(不同的队列设置)。这里单讲单个消息的TTL,因为它才是实现延迟任务的关键。可以通过设置消息的expiration字段或者x-message-ttl属性来设置时间,两种是一样的效果
3、Dead Letter Exchanges(DLX)
一个消息在满足如下条件,会进死信路由,这里是指路由,而不是队列,一个路由可以对应很多队列
1)、一个消息被Consumer拒收了,并且reject方法的参数里request是false.也就是说不会被再次放在队列里。被其他消费者使用。
2)、上面的消息TTL到了。消息过期了
3)、队列的长度限制满了。排在前面的消息会被丢弃或者扔到死信路由上
4、Dea Letter Exchange 其实就是一种普通的exchange,和创建其他exchange没有两样,只是在某一个设置Dead Letter Exchange 的队列中有消息过期了,会自动触发消息的转发,发送到Dead Letter Exchange中区。
我们既可以控制消息在一段时间后变成死信,又可以耦控制变成死信的消息被路由到某一个指定的交换机,结合二者。其实就可以实现一个延时队列
总结;给消息设置过期------(过期 通过死信路由)---->指定的交换机(exchange)--------->再到一个队列--(过期时间后)--------->特点交换器(exchange)------->指定队列---->consumer消费
附:消息的整个流转过程