资讯专栏INFORMATION COLUMN

swoft中Crontab定时器的坑

CarterLi / 1803人阅读

摘要:我们项目使用的是框架,所以我就想到用框架的定时器。,以及的结构注在定时器这块使用到两个一个是用于存储任务的实例。

这两天老大给了个需求想把商城热点数据同步到redis缓存。我们项目使用的是swoft框架,所以我就想到用框架的Crontab定时器。但是在测试的时候发现把Table的size设置为1024时(实际上设置为任何大小都一样,贴上swoole的解释)发现内存溢出了

普及一下Table(来自swoole文档):
Table底层是建立在共享内存之上的HashTable数据结构。$size最大行数,决定了HashTable的总行数。由于Table是在共享内存之上,所以无法动态扩容。这个$size必须在创建前设置好。
$size参数指定表格的最大行数,如果$size不是为2的N次方,如1024、8192,65536等,底层会自动调整为接近的一个数字,如果小于1024则默认成1024,即1024是最小值

先把框架任务投递流程走一下:

首先当框架启动一秒后,启动定时器每秒去更新执行一次Task(任务)。更新任务之前先去队列内存表中清理已完成的队列数据(这点很重要)

然后获取出所有的任务中的队列(可以理解为获取所有的Task类中的方法),以任务规则,以及taskClass,分钟,时间戳这些数据以md5方式加密得到每个任务队列的key值,保存在runTimeTable 中。(originTable,以及runTimeTable 的结构)

注:在定时器这块使用到两个Table 一个是originTable用于存储任务的(Task)实例。另一个是runTimeTable 存储任务队列实例,通俗地说就是存需要执行的任务实例

再看看任务执行流程,任务的执行就很简单了

首先通过getExecTasks这个方法把所有满足条件的队列任务放在一个数组,然后通过遍历数据把runStatus的值改为self::START

之后执行所有runStatus的值为self::START的队列任务

把执行后的队列任务的runStatus的值改为self::FINISH

最后把runStatus的值改为self::FINISH的剔除掉

重新梳理一下我们逻辑
当我们新建执行一个任务的时候,系统每秒钟都回去更新执行一个每个任务中的队列数。
代码如下:

通过代码我们能够发现每一分钟他都会往runTimeTable 中添加60个任务队列
但是当我们getExecTasks获取将要执行的任务队里的时候是根据当前的时候是否等于执行时间而标志状态的
那么现在就会出现一个问题。当前时间往任务队里中添加数据的时候 他把前面执行过的任务队列再次添加进runTimeTable 中
举个栗子:
假如我有个异步任务Sync,其中有个每秒执行一次的方法cronTask,
现在时间是2019-03-22 10:01:20 现在往更新runTimeTable 的时候 他会往里面添加60的任务队列key分别会是
MD5(" "."Sync"."cronTask"."01"."00")
MD5(" "."Sync"."cronTask"."01"."01")
MD5(" "."Sync"."cronTask"."01"."02")
MD5(" "."Sync"."cronTask"."01"."03")
MD5(" "."Sync"."cronTask"."01"."04")
...
MD5(" "."Sync"."cronTask"."01"."59")

当时间到下一秒(是2019-03-22 10:01:21)的时候后 依然会往更新runTimeTable数据 key值为
MD5(" "."Sync"."cronTask"."01"."00")
MD5(" "."Sync"."cronTask"."01"."01")
MD5(" "."Sync"."cronTask"."01"."02")
MD5(" "."Sync"."cronTask"."01"."03")
MD5(" "."Sync"."cronTask"."01"."04")
...
MD5(" "."Sync"."cronTask"."01"."59")

那么我们可以很明确地看出来在2019-03-22 10:01:21秒前的数据都是没用的了 。这些数据永远不会被消费,也不会被删除。因此一段时间后会出现内存溢出的情况。
所以解决方法是在清理消费数据的时候把过期数据也同时清理
把cleanRunTimeTable中的

if ($value["runStatus"] === self::FINISH) {

改为

$currentTime = time();
if ($value["runStatus"] === self::FINISH || $value["sec"] < $currentTime) {

本文为本人学习过程记录。如果有哪些地方描述不当望各位大佬指出。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/31065.html

相关文章

  • Swoft 源码剖析 - Swoole和Swoft的那些事(Task投递/定时任务篇)

    摘要:作为定时任务的执行者,通过每唤醒自身一次,然后把执行表遍历一次,挑选当下需要执行的任务,通过投递出去并更新该任务执行表中的状态。 作者:bromine链接:https://www.jianshu.com/p/b44...來源:简书著作权归作者所有,本文已获得作者授权转载,并对原文进行了重新的排版。Swoft Github: https://github.com/swoft-clou.....

    vvpvvp 评论0 收藏0
  • Swoft 源码解读

    摘要:官网源码解读号外号外欢迎大家我们开发组定了一个就线下聚一次的小目标里面的框架算是非常重的了这里的重先不具体到性能层面主要是框架的设计思想和框架集成的服务让框架可以既可以快速解决很多问题又可以轻松扩展中的框架有在应该无出其右了这次解读的源码 官网: https://www.swoft.org/源码解读: http://naotu.baidu.com/file/8... 号外号外, 欢迎大...

    weij 评论0 收藏0
  • Swoole 在 Swoft 的应用

    摘要:在中的应用官网源码解读号外号外欢迎大家我们开发组定了一个就线下聚一次的小目标上一篇源码解读反响还不错不少同学推荐再加一篇讲解一下中使用到的功能帮助大家开启的实战之旅服务器开发涉及到的相关技术领域的知识非常多不日积月累打好基础是很难真正 date: 2017-12-14 21:34:51title: swoole 在 swoft 中的应用 swoft 官网: https://www.sw...

    EscapedDog 评论0 收藏0
  • linux下使用crontab运行Python脚本的坑

    摘要:在使用脚本实现功能时发现并没有定时运行在指令后面添加指令,发现如下报错脚本单独运行是正常的,但是已使用后运行异常,再一番后发现,是不能正确加载的环境变量导致,需要做如下修改这里是列表文本直接执行所在路径,路径可以使用指令来获取,所以我的在使用Python脚本实现DDNS功能时发现并没有定时运行在指令后面添加>/dev/null 2&>1指令,发现如下报错00-18-01 Traceback ...

    Tecode 评论0 收藏0
  • Swoft| Swoft官网全站 HTTP2 实践

    摘要:官网全站实践正式来袭也迎来自己的一个里程碑数正式突破官网作为项目组服务开发者们的重要渠道也迎来了自己的一次重大更新重构升级到全站实现本篇先介绍官网全站实践先来一张官网效果图镇楼静态资源由托管开启业务代码交由执行设置使用协议要实现非常简单 date: 2018-3-8 13:50:03title: Swoft| Swoft官网全站 HTTP2 实践 Swoft1.0正式来袭, Swoft...

    stdying 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<