Loading

RabbitMQ延时队列

1、场景:

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


2、上述场景的解决方案:

1)spring schedule的定时任务轮询数据库

缺点:消耗系统内存,增加数据库压力,存在较大的时间误差

(例如如果订单30分钟未支付时取消订单,且定时任务30分钟执行一次,那么一个订单最晚会59分钟才会被定时任务扫描到已取消,例如定时任务在0分钟时执行,恰巧订单在一分钟时来了,定时任务在30分钟时扫描订单,发现订单还没过期,但是31分钟订单恰好过期,于是等到60分钟,定时任务再次扫描时,才能扫描到这个过期订单,所以订单在一分钟被创建,60分钟才被发现过期)

image-20220227152229409


2)RabbitMQ延时队列

rabbitmq延时队列 (消息ttl和死信Exchange结合)

image-20220227152716727


3、消息的TTL(time to live)

消息的ttl就是消息的存活时间

RabbitMQ可以对队列和消息分别设置TTL

  • 对队列设置ttl就是,消息在队列的逗留时间;也可以对每一个单独的消息做单独的设置。超过了这个时间,我们就认为这个消息死了,称之为死信

  • 如果队列设置了ttl,消息也设置了,会取两者之间较小的。可以通过设置消息的expiration字段或者x-message-ttl属性来设置时间,两者是一样的效果


4、Dead Letter Exchange (DLX)

image-20220227160755346


5、延时队列的实现

设置队列过期时间实现延时队列 (推荐)

image-20220227161640741


设置消息过期时间来实现延时队列

image-20220227163336965


6、延时队列定时关闭订单模拟

交换机,队列以及路由键的相关情况如下:

image-20220227165605031

p消息,经过交换机order-event-exchange路由到延时队列order.delay.queue,延时队列设置了如上三个属性,当延时队列中的消息过期后,会转到指定的Dead Letter Exchage(order-event-exchange),Dead Letter Exchage在将消息路由到指定的队列进行处理



7、消息丢失、积压、重复的解决方案

如何保证消息的可靠性

1、消息丢失

消息发送出去,由于网络原因没有到达服务器(producer到broker)

  • 做好容错方法(try catch),发送消息可能会网络失败,失败后要有重试机制,科技路到数据库,采用定期扫描重发的方式

  • 做好日志记录,每个消息是否被服务器收到,应该记录

  • 做好定期重发,定期去数据库扫描未成功发送的消息进行重发

消息抵达Broker,Broker要将消息写入磁盘(持久化)才算成功。此时Broker尚 未持久化完成,宕机

  • publisher也必须加入确认回调机制,确认成功的消息,修改数据库消息状态

自动ACK的状态下。消费者收到消息,但没来得及消息然后宕机

  • 一定开启手动ACK,消费成功才移除,失败或者没来得及处理就noAck并重新入队


2、消息重复

消息消费成功,事务已经提交,ack时,机器宕机。导致没有ack成功,Broker的消息 重新由unack变为ready,并发送给其他消费者(当消息正在被消费者消费时,消息是unack状态,当消息被reject时,由unack变为ready;当消息被正常消费时,从队列移除)

  • 消费者的业务消费接口应该设计为幂等性的。比如扣库存有 工作单的状态标志

  • 使用防重表(redis/mysql),发送消息每一个都有业务的唯 一标识,处理过就不用处理

  • rabbitMQ的每一个消息都有redelivered字段,可以获取是否 是被重新投递过来的,而不是第一次投递过来的


3、消息积压

消费者宕机积压

消费者消费能力不足积压

发送者发送流量太大

  • 上线更多的消费者,进行正常消费

  • 上线专门的队列消费服务,将消息先批量取出来,记录数据库,离线慢慢处理

posted @ 2022-03-14 07:19  青岑  阅读(251)  评论(0编辑  收藏  举报