RabbitMQ学习-延时队列

Posted on 2022-01-09 11:31  樱木007  阅读(86)  评论(0编辑  收藏  举报

一.延时队列的定义

延时队列,首先,它是一种队列,队列意味着内部的元素是有序的,元素出队和入队是有方向性的,元素从一端进入,从另一端取出。其次,延时队列最重要的特性就体现在它的延时属性上,跟普通的队列不一样的是,普通队列中的元素总是希望被早点取出处理,而延时队列中的元素则是希望在指定的时间得到取出和处理。所以延时队列中的元素是都是带时间属性的,通常来说是需要被处理的消息或者任务。简单来说,延时队列就是用来存放需要在指定时间被处理的元素的队列。

二.延时队列的使用场景

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

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

3.账单在一周内未支付,则自动结算。

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

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

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

       这些场景都有一个特点,需要在某个事件发生之后或者之前的指定时间点完成某一项任务,如:发生订单生成事件,在十分钟之后检查该订单支付状态,然后将未支付的订单进行关闭;发生店铺创建事件,十天后检查该店铺上新商品数,然后通知上新数为0的商户;发生账单生成事件,检查账单支付状态,然后自动结算未支付的账单;发生新用户注册事件,三天后检查新注册用户的活动数据,然后通知没有任何活动记录的用户;发生退款事件,在三天之后检查该订单是否已被处理,如仍未被处理,则发送消息给相关运营人员;发生预定会议事件,判断离会议开始是否只有十分钟了,如果是,则通知各个与会人员。

       看起来似乎使用定时任务,一直轮询数据,每秒查一次,取出需要被处理的数据,然后处理不就完事了吗?如果数据量比较少,确实可以这样做,比如:对于“如果账单一周内未支付则进行自动结算”这样的需求,如果对于时间不是严格限制,而是宽松意义上的一周,那么每天晚上跑个定时任务检查一下所有未支付的账单,确实也是一个可行的方案。但对于数据量比较大,并且时效性较强的场景,如:“订单十分钟内未支付则关闭“,短期内未支付的订单数据可能会有很多,活动期间甚至会达到百万甚至千万级别,对这么庞大的数据量仍旧使用轮询的方式显然是不可取的,很可能在一秒内无法完成所有订单的检查,同时会给数据库带来很大压力,无法满足业务要求而且性能低下。

三.RabbitMQ的TTL(Time To Live)

1. TTL定义

       TTL是RabbitMQ中一个消息或者队列的属性,表明一条消息或者该队列中的所有消息的最大存活时间,单位是毫秒。换句话说,如果一条消息设置了TTL属性或者进入了设置TTL属性的队列,那么这条消息如果在TTL设置的时间内没有被消费,则会成为“死信”。

2.设置TTL的值

(1)创建队列的时候设置

var args = new Dictionary<string, object>();
args.Add("x-message-ttl",60000);
channel.QueueDeclare("myqueue", true, false, false, args);

设置为60秒过期

(2)对每条消息设置TTL

  string message = "零下10度";
  var body = Encoding.UTF8.GetBytes(message);
  IBasicProperties props = channel.CreateBasicProperties();
  props.ContentType = "text/plain";
  props.DeliveryMode = 2;
  props.Expiration = "60000";
  channel.BasicPublish(exchange: RabbitConstant.EXCHANGE_WEATHER,
                                         routingKey: "",
                                         basicProperties: props,
                                         body: body);

       但这两种方式是有区别的,如果设置了队列的TTL属性,那么一旦消息过期,就会被队列丢弃,而第二种方式,消息即使过期,也不一定会被马上丢弃,因为消息是否过期是在即将投递到消费者之前判定的,如果当前队列有严重的消息积压情况,则已过期的消息也许还能存活较长时间。

      另外,还需要注意的一点是,如果不设置TTL,表示消息永远不会过期,如果将TTL设置为0,则表示除非此时可以直接投递该消息到消费者,否则该消息将会被丢弃。

 参考链接:https://www.cnblogs.com/mfrank/p/11260355.html

Copyright © 2024 樱木007
Powered by .NET 8.0 on Kubernetes