场景: 比如未付款订单,超过一定时间后,系统自动取消订单并释放占有物品。

常用解决方案: 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消费



消息队列的设计:
总结就是 库存服务----->关联一个交换器----->两个队列--------->消费者
所有消息先进延时队列。过期的消息进特点的解锁队列 被消费解锁
二个绑定关系:
延时队列跟交换器绑定
解锁队列跟交换器绑定
二个路由键:
锁库存的路由键
死信的路由键
一个交换器:
库存交换器
二个队列:
延时队列:
设置延时规则(死信规则)
arguments.put("x-dead-letter-exchange","stock-event-exchange");
arguments.put("x-dead-letter-routing-key","stock.release");
arguments.put("x-message-ttl",120000);
解锁队列:
普通队列
订单服务---->关联一个交换器----->三个队列 ------->消费者
所有消息先进延时队列。过期的消息进特点的解锁队列 被消费解锁
三个绑定关系:
延时队列跟交换器绑定
订单解锁队列跟交换器绑定
库存解锁队列跟交换器绑定
三个路由键:
创建订单的路由键
(订单)死信的路由键
(库存)死信的路由键
一个交换器:
订单交换器
三个队列:
延时队列:
设置延时规则(死信规则)
arguments.put("x-dead-letter-exchange","stock-event-exchange");
arguments.put("x-dead-letter-routing-key","stock.release");
arguments.put("x-message-ttl",120000);
(订单)解锁队列:
普通队列
(库存)解锁队列:
普通队列
图解:
附:消息的整个流转过程

本文介绍了如何利用RabbitMQ的消息TTL和死信交换机(DLX)来实现未付款订单的自动取消。通过设置消息存活时间和死信路由,当订单超过预设时间未付款时,系统将自动将其标记为死信并转发到特定交换机,最终由消费者处理取消订单的操作。这种方法减少了系统内存消耗和数据库压力,同时提高了时间精度。
629

被折叠的 条评论
为什么被折叠?



