如何避免扫描数据库且保证低延迟触发定时任务的一些思考

用户自定义触发时间

用户自定义触发时间,存在不固定,所以需要秒级的扫描来触发任务。但是如果直接扫表的话,会给数据库造成比较大的压力。可以考虑基于RedisZSet来处理

  1. 明确年月日时分秒, 即希望在一个具体的时间执行,这种执行基本就是一次性。
    解决方案:

    1. 把时间转换为时间戳, 然后使用zset的数据格式,key根据业务决定,将同一类的定时统一划分到一个key
    2. value按需决定是否需要放入定时任务所需要的数据, score即为用户设置的定时任务触发时间的时间戳。
    3. 定时任务扫描, 调用redis操作类的opsForZSet().rangeByScore(key, 0, 当前时间戳)方法,这样即会把缓存中score小于当前时间的数据扫描出来,而这部分数据则是满足定时任务的数据。然后将这部分数据取出来直接执行业务即可。
    4. 执行完业务之后, 调用opsForZSet().removeRangeByScore(key, 0, 当前时间戳)清除这段时间的数据,避免下次再次扫描到。
    5. 可以看到第3步扫描到的数据大小依赖于定时的执行间隔, 如果实时性要求比较高,可以将定时设置为每秒执行也是可以的。注意这里面的一些时间定义一定要是在开始就定义的变量,后续保证使用的时间都不能变化。如上面3和4的当前时间戳。
  2. 只明确时分(秒), 即时间是固定的,但对年月日没要求, 这种执行基本就是循环的,每天或者都会执行
    解决方案

    1. 将时间部分的数据转换为毫秒值, 如10:30, 则对应的毫秒值为10 * 60 * 60 * 1000 + 30 * 60 * 1000,然后使用zset的数据格式,key根据业务决定,将同一类的定时统一划分到一个key
    2. value按需决定是否需要放入定时任务所需要的数据, score即为转换后的时间戳。
    3. 定时任务扫描,首先获取当前时间,但是是获取和触发时间对等的格式。比如设置的触发时间为时:分格式, 则当前获取时间也获取到对应的时:分格式的值,然后将这个值按照第1步的计算公示,计算出来当前时间对应的时间戳
    4. 调用opsForZSet().rangeByScore(key, 第3步计算出来的值, 第3步计算出来的值),扫描出来的数据即是满足第一步设置的对应的时分的定时任务, 然后对取出来的数据进行业务处理即可
    5. 由于这个是循环任务,因此执行完定时之后,是不需要从缓存中将本次扫描到的数据从缓存中移除的。
    6. 关于第4步的beforeTime的选择, 可以按需决定是否往前推一个单位,这样即使上一次的定时执行失败了,下一次依然可以扫描到,相当于多了一次重试机会。但是要根据实际情况决定, 做好业务方面的 幂等性控制
    7. 关于这个方案的缓存同步问题, 由于严重依赖缓存, 如果数据丢失,则会导致定时无法执行的情况。其实可以根据业务决定,在每天的最后一个时间段进行检查定时任务的执行结果。这个执行结果一般都会对应着一个业务状态,可以根据业务状态是否更改成功来判断定时任务是否达到了业务的目的。如果没有达到,有可能是任务没执行,也有可能是任务执行失败。然而不论什么原因,可以在这个定时里根据需要是否在兜底重试一次。不论这里是否重试,可以重新同步一下失败业务的定时触发时间到缓存中。

系统层面的定时

  1. 统计定时
    比如对所有的一个主体进行资源统计, 如果定时要求延迟性比较低的话, 倒是可以在流量比较低的凌晨统一进行处理。但是比如延迟要求是1个小时,那么数据就会比较集中的被分到一个时间点上。而且这个时间点很有可能是系统使用高峰期,能否对这种数据进行错开处理呢?
    一种思路是针对一个主体的统计,那么这个主体必然会存在一些基本属性,如创建时间,激活时间之类的。选取一个比较合适的字段,用这个时间来作为触发时间点。比如每一个小时统计一次,创建时间是2021-03-10 15:57:30, 那么就可以把57分作为一个触发时间,即每个小时的57分触发一次。而定时如果是一个小时触发一次,那么就每天15:57触发一次。
    那么这个问题又回到了上面用户自定义时间的定时解决方案2上面了,即把57分转换为对应的毫秒数,然后套入上面的用户自定义触发时间方案2即可
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值