zoukankan      html  css  js  c++  java
  • RabbitMQ学习延时队列

    一.延时队列的定义

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

    二.延时队列的使用场景

    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

  • 相关阅读:
    洛谷 P1903 【模板】分块/带修改莫队(数颜色)
    BZOJ 2038: [2009国家集训队]小Z的袜子(hose)
    LibreOJ #6208. 树上询问
    LibreOJ #6002. 「网络流 24 题」最小路径覆盖
    hdu 3861 The King’s Problem
    洛谷 P2868 [USACO07DEC]观光奶牛Sightseeing Cows
    洛谷 P2905 [USACO08OPEN]农场危机Crisis on the Farm
    洛谷 U3348 A2-回文数
    洛谷 P1001 A+B Problem
    LibreOJ #2130. 「NOI2015」软件包管理器
  • 原文地址:https://www.cnblogs.com/hobelee/p/15780572.html
Copyright © 2011-2022 走看看