redis的list可以用作队列,效率高,好用,但是有个缺点就是队列的时效性只能统一设置,一个list一个,要过期只能批量过期,不能达到只过旧的数据,新数据保留的情况。

网上解决方法是换成sring,每个单个项目单独设置ttl,不用list ,批量用keys + * 正则表表达式过滤,可以批量pos数据出来达到队列效果,但是redis官网上描述有keys只能用作debug模式,性能上会产生比较大的影响。

另一种解决方案就是采用多个list,分时间片段做队列,取队列优先按照到期时间近的队列取,队列分别过期方式,大概实现方法如下


规则:

(1) 设置两个list --> parta , partb

(2) 时限分为 2个区域 【总ttl】 = 【可写入】 + 【不可写入等待期】

比如: ttl = 48小时 , 写入list队列规则为 0~24 小时可写, 24~48 小时队列不再写入,等到ttl到期销毁 , ttl=24+24

(3)两个 parta , partb 分别轮流时间写入

创建parta--->写入parta队列--->parta到了等待期 ---> 创建partb 写入 ---->写入partb队列--->partb到了等待期---->创建parta写入(此时前一个parta应该已经销毁)


代码:

    long expire_a = redisUtil.getExpire(parta_list);
    long expire_b = redisUtil.getExpire(partb_list);
    //(24小时等待过期)
    long expire_out = 24;
    //两个分区时间间隔大小
    long expire = 24 * 2;
    if (expire_a > expire_out && expire_a>=expire_b-100) {
      //队列a还有剩余时间 ,且 a >= b (100秒作为误差)
      redisUtil.ListSet("parta", ob);//不设置ttl
    } else if (expire_b > expire_out && expire_a<=expire_b) {
      //队列b还有剩余时间 ,且 b >= a
      redisUtil.ListSet("partb", ob);//不设置ttl
    } else if ((expire_a < 0 && expire_b < 0) || (expire_a < 0 && expire_b <= expire_out)) 
      { 
      //队列a ,b 不存在,新建队列a
      //队列a(a可能-1,-2)没有剩余时间且<0, 队列b没有剩余时间(b可能>0,=0,=-1,=-2),新建队列a
      redisUtil.ListSet("parta", ob, expire);//设置ttl
    } else if (expire_a <= expire_out && expire_b < 0) {
      //队列a(a可能-2,-1,0,>0)没有有剩余时间 且 队列b(b可能-2,-1)没有剩余时间且<0,新建队列b
       redisUtil.ListSet("partb", ob, expire);//设置ttl
    }
    else
    {
      //此处属于意外情况,理论上不存在,比如 a和b 几乎相同(不可能)
      //或者 a|b消亡一瞬间的,由于物理原因延迟几秒,还存在0状况,或未被及时销毁不为-2 ,造成 a|b 两个不可写入时间重叠,两个都无法写入
      //谁剩余时间大,写谁,不设置ttl
      if (expire_a >= expire_b)
        redisUtil.ListSet("parta", ob);//不设置ttl;
      else
         redisUtil.ListSet("partb", ob);//不设置ttl
    }

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐