延时任务的实现与优化

延时任务

概述

在工作中,我们可能会接到一些需求,需要我们做一些延时的处理,用户使用一个功能,处理业务逻辑时,不是立即执行的,可能是用户设置一个时间,过了这个时间后才执行相应的业务逻辑。

举例

case 1

在医院中某床位安装了一个智能看护床垫设备,当床垫监测到床上的人离开床后,会向服务器发送一条离床消息,当离床的时间超过了用户设定的阈值时,需要产生一条报警数据。

case 2

订单超时的关闭,当用户下单后,超过一定的时长未付款,则自动关闭该订单

分析

处理这些业务功能时,都需要流程开始时进行计时,到时间后,执行后续业务逻辑

实现方案

Redis的Key失效机制

当流程开始时,我们向Redis中放入一个key,并设置失效的时间,设置key失效监听器,当监听到key失效时,通过key的名称区分,执行相应的业务逻辑。
在之前实现类似功能时,我采用该种方法去实现,发现了一些问题:

缺点:失效时间有一定的延迟
像case1中,可能需要对失效的时间精确度有很高的要求,因为报警的时间需要越精确越好,但是实际测试中出现10s,甚至20s的延迟

然后查找Redis官方对expire的说明

过期精度
在 Redis 2.4 及以前版本,过期期时间可能不是十分准确,有0-1秒的误差。
从 Redis 2.6 起,过期时间误差缩小到0-1毫秒。

失效机制的说明:

Redis如何淘汰过期的keys
Redis keys过期有两种方式:被动和主动方式
主动
当一些客户端尝试访问它时,key会被发现并主动的过期。
被动
当然,这样是不够的,因为有些过期的keys,永远不会访问他们。 无论如何,这些keys应该过期,所以定时随机测试设置keys的过期时间。所有这些过期的keys将会从密钥空间删除。
具体就是Redis每秒10次做的事情:

  1. 测试随机的20个keys进行相关过期检测。
  2. 删除所有已经过期的keys。
  3. 如果有多于25%的keys过期,重复步奏

这是一个平凡的概率算法,基本上的假设是,我们的样本是这个密钥控件,并且我们不断重复过期检测,直到过期的keys的百分百低于25%,这意味着,在任何给定的时刻,最多会清除1/4的过期keys。

根据官方的说明,Redis每秒做10次,去随机检测20个key是否过期,也即是说100毫秒检测20个key,然后我就不太能理解,这样如何能将过期时间缩小到0-1毫秒呢?根据这种方式,1s失效200个key,假如我有2000个key的情况,怎么看也不能把误差缩小到0-1毫秒吧。。。

既然被动失效机制无法满足需求,那就采用主动失效的机制
在后台创建一个静态的ConcurrentHashMap(普通的HashMap可能会出现并发修改异常),每次放入一个expire key时,将这个key也放入这个map中,然后开启一个线程,每秒去遍历这个map中的key值,遍历一个就去Redis中查询这个key,根据主动失效的机制,可以将误差降到非常低的状态

性能分析
根据百度百科,Redis读的速度是110000次/s,所以在key不多的情况下,每秒去遍历似乎造成不了太大的性能消耗,但是可能会造成key集中的失效,这个对Redis性能的消耗情况有待确认,但是大量的key失效时,根据业务的需求,可能会需要向数据库写入大量数据,需要注意。

环形队列处理

该种方案是看云析学院的公开课时学到的,这种方案首先需要一个环形队列,队列长度为3600,理论上误差在1s以内。
环形队列长度在3600,那么我们设置一个指针,每秒钟挪动一格,移动3600格需要1h
然后在每格中放入一个Set集合,存储我们定义的延时任务对象

public class MyTask{

	private int hours;
	
	void do(){
		//执行业务逻辑
	}
}

存储任务
其中的hours代表延迟的小时数,假如一个任务需要延时的时间超过了一个小时,那么我们就将小时数存入hours,不满一个小时的时间,查询指针当前的位置,通过计算,放入队列中

执行任务
当指针指向某一格时,遍历该Set集合中的全部对象,当hours不为0时,hours-1,hours为0时,执行其中的do方法

优点
(1)无需再轮询全部任务,效率高
(2)时效性好,精确到秒(控制timer移动频率可以控制精度)

思考
是否能将任务设置为线程,执行时,使用线程池执行

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值