【开源访谈】JTimer:crontab 的替代品,工程师的福音

h4cd 发布于 2018/06/26 16:53
阅读 6K+
收藏 66

作为程序员,在日常工作中免不了与各种任务打交道,有一些任务的执行是具有重复性质的,比如工作人员每天登录系统之后进行一系列基础操作:(1)先确认一下系统时间,(2)查看之前登录的用户,(3)再打开某个监控日志……这些操作基本上是固定项目,每次一登录就需要一个一个地执行,那么,如何节省工程师宝贵的时间,把这些操作捆绑起来,只通过一次输入就全部执行呢?在 Unix/Linux 环境下,shell 脚本出现了,它负责处理批量任务,类似于 Windows 环境下的批处理 .bat 文件,都是按照先后顺序,依次执行文件中的每一个任务条目。

而再进一步,工程师又想让任务能够定时自动执行,不必等到每次想让任务执行时再操作,大名鼎鼎的 crontab 工具就满足了他们的愿望。crontab 是 Linux 下的一个与 Windows 下的计划任务类似的命令,它被用来管理用户需要周期性执行的任务,由守护进程 crond 驱动,crond 定期检查是否有任务需要执行,如果有那么就执行相应任务。更具体一点,通过 crontab 命令参数与相应格式的设置,它能够做到对定时任务进行按需管理。

然而,还是有追求极致体验与性能的开发者不够满意 crontab,他们非要自己改造/创造一个新的替代工具,以适应自己的工作方式。本次采访嘉宾周君就开发了一个号称 crontab 替代品的 JTimer,我们请他分享了 JTimer 的开发背景与相关技术细节。

定时任务具体是指什么?定时任务管理是什么?介绍一下整个工作场景。

定时任务是指在用户指定的时间点执行用户指定的任务。而随着业务的增加与变动,定时任务常常需要修改,定时任务的管理就是对定时任务的 CRUD 等操作。

大多数业务系统都会有使用定时任务的需求,以此来代替人工的驻守与繁琐的重复操作,例如某系统有每天生成业务报表的需求,但是由于数据量过于庞大,为了避免对生产环境用户造成影响,应选择在凌晨访问量较少时执行生成报表的操作,定时任务不仅节省了人力,免去了人工可能导致的“忘了执行任务”的尴尬场面,也能让开发人员不用半夜起床工作。

一个定时任务管理器的优劣主要可以从哪些方面考量?

通常,我们对定时任务管理器的要求最主要的考量有以下两方面:

  • 定时器的稳定性、高可用性
  • 管理上的便捷性

第一点考量是最为重要的,定时任务是按时执行用户指定的业务任务,定时器的不稳定、延迟与宕机等问题都可能直接影响用户的业务,严重的甚至导致公司的经济损失。

至于上述的第二点考量,对运维和开发人员来说是一个痛点,如果管理不够便捷,那么也会严重影响到工程师的效率。

JTimer 号称 crontab 的替代品,那么与之相比,JTimer 有什么优势?二者还有哪些异同?

crontab 是开发人员耳熟能详的知名定时任务工具,也是业内目前最优秀的同类产品,但是在使用 crontab 的过程中也有许多不便之处:

  • 编辑任务时需要登录服务器,需要使用 vim 操作,虽然这对于开发人员和运维人员来说不是什么大问题,但是相对于使用 Web 界面操作来说还是麻烦了不少,如果能够使用 Web 界面可视化来操作,那会更加便捷与高效。
  • crontab 的定时只支持到分钟级别,而 JTimer 支持到秒级。
  • 在管理任务时,crontab 不支持分类管理,需要我们自己人为的分类,当任务数量很多时会显得有些杂乱,管理上略有不便。
  • 有时候我们需要查询任务的执行日志,而 crontab 的执行日志存放在一个日志文件中,我们无法快速并且直观的筛选中我们想要的内容。
  • 当有多台服务器需要部署或修改任务时,需要同时修改相应服务器配置。

JTimer 就是因为在使用 crontab 的过程中发现了这些不足,所以才研发出来的,那它的优势就很明显了。JTimer 的目的是提供更快速便捷的任务管理方式,以及任务日志的快速搜索。这是 JTimer 的优势和存在的意义,也是 JTimer 和 crontab 最大的不同之处。

JTimer 使用 Web 界面,让操作更加便捷、高效,下图展示了其管理页面:

任务列表:

编辑任务:

任务分类:

任务执行日志,可条件查询:

系统设置(Java 版暂无验证码与 ip 限制功能):

自动清除旧日志:



JTimer 的架构是怎么样的?工作流程又是怎么样的?

JTimer 可以大致分为两个模块,一是任务的管理模块,二是任务执行模块。

JTimer 分为 Java 版和 PHP 版,两者从管理模块上来说几乎完全一样,都提供了定时任务的 CRUD 和执行日志查询等功能,连 UI 都基本一致,不同之处在于任务执行模块的架构和实现机制。

JTimer for PHP

PHP 版任务执行模块使用了经典的 master-worker 进程模型。



  • 有1个 master 进程负责监控整个系统的运行,保证所有进程的高可用。
  • 有2个 worker 进程,其中一个负责监控任务的变化,另一个 worker 是一个定时器,负责任务的调度工作(使用了时间轮的算法),一旦有任务需要执行,就将任务传递给 task 进程执行,worker 本身不涉及任务的具体执行。两个 worker 之间以 tp 框架自带的文件缓存作为沟通的桥梁。
  • n个 task 进程,负责任务的具体执行。

JTimer for Java

从工作流程上来说,Java 版和 PHP 版相差不多,只是具体的实现方式上不同。PHP 版使用的是多进程,而 Java 版使用的多线程:

  • 两个线程,分别对应 PHP 版的的两个 worker,工作职责与 worker 一样。
  • 任务的调度使用了 Spring 框架 CronTrigger。
  • 任务的具体执行使用了 Java 原生的 Runtime.getRuntime().exec(),该方法本身是多进程方式执行任务,因此不需要我们参与进程的管理。

PHP 版与 Java 版相比较,Java 版在实现上大部分是使用了 Java 和 Spring 为我们提供的能力,因此较为简单。而 PHP 在这方面较为薄弱,无论是多进程方面还是定时器方面,都需要我们自己动手去实现,开发起来也复杂不少。

在 JTimer 研发的过程中,遇到的主要难点是什么?踩过什么坑?

开发 JTimer 的 PHP 版,从技术上来说并不难,并没有遇到太多困难。但在测试中遇到过一个问题,用了好几天才找到问题所在,下边简单讲一讲。

当时 JTimer 已经发布,有一位网友使用了 JTimer,但是在使用中,发现任务会被遗漏。例如有一个任务是每小时执行一次(整点执行),正常情况下一天会执行24次,但是实际上会被随机的遗漏掉1-2次,一天只执行了22或23次。

当这位网友把问题反馈给我之后,我查看了我这边的测试服务器上的 JTimer,却没有发现这个问题。后来这位网友说他的两台服务器,一台 CentOS 没有发现这个问题,一台 Ubuntu 却有这个问题。一开始我们以为是环境问题,排查了好几天,后来才发现是定时器的 bug。

导致 bug 的原因是:假设现在的时间是 00:00:00,当代码执行到“判断当前是否有任务需要执行”时,时间已经跳到 00:00:01 秒,导致判断错误,本应该在 00:00:00 执行的任务没有执行。

后来我解决这个问题的方法是在自己定义一个时钟,程序启动时获取当前时间戳保存下来,然后每秒加1。在要用到时间时都使用自己定义的这个时钟,而不用系统时间,这样就避免了时间差导致的任务丢失问题。

但是这样又产生了一个新的问题,理论上自定义的时钟和系统时间应该是一致的,但实际上每一秒会产生零点零零几毫秒的误差,累计下来几个小时就会产生一秒的误差。想要解决这个问题只能重构整个任务调度功能,该问题暂时还没有解决。不过仅 PHP 版有该问题,如果时间误差会影响业务,建议使用 Java 版。

目前在生产环境中使用该项目了吗?效果如果?或者测试效果如何?

目前已经有一个网友在生产环境中使用了 JTimer 的 PHP 版本,从效果上来说,除了上面所说的时间问题(Java 版没有该问题),暂时还没有发现别的问题。同时在此要感谢这位网友,在测试过程中帮我发现了一些问题(就是上个问题提到的网友)。

而从我自己的测试效果上来说,已经基本达到可以上线生产环境的标准。但毕竟测试样本太少,也许有尚未发现的 bug,广大开发者们在使用 JTimer 的过程中如果发现问题,希望能够反馈给我,帮助完善 JTimer。

介绍一下项目接下来的计划。

到目前为止项目的进展已经基本告一段落,并没有计划开发新的功能。JTimer 诞生的初衷是解决 crontab 管理不便的问题,该目的已经达到,我不希望将 JTimer 发展成一个庞大臃肿的项目,保持单一功能,能够解决同行们的痛点就够了。

不过前面提到的 PHP 版时间误差的问题仍需要解决的,这也是接下来唯一的计划,虽然 Java 版无此问题,但我还是希望能将 PHP 版做得更完美一些。同时,如果有意参与 JTimer 开发的开发者对它的发展有什么好的想法,也欢迎大家一起交流。

项目地址:https://gitee.com/itzhoujun/JTimer

嘉宾介绍

周君,资深后端工程师,博客作者,精通 PHP、Java、Web开发。多年实战经验,热衷分享。

加载中
2
震秦
震秦

精通PHP跟Java, 看你们怎么吐槽。 无论哪个是最好的语言,都是最牛逼的。

blu10ph
blu10ph
角度刁钻~
1
紫薯精
紫薯精

JTimer  这名子 一看还以为是java写的  所以一点用的欲望都没有~~

君君要上天哈
君君要上天哈
有JAVA和PHP两个版本。
osc_bd34fa5
osc_bd34fa5
确实
1
hakuyo
hakuyo

任务设置一个状态,比如是否已执行过,等等,可以解决时间点过后,任务被跳过的问题。

当然,还要有一个未被执行的任务队列。

1
宇润-非洲black鬼人人得而诛之
宇润-非洲black鬼人人得而诛之

我们做开发的,给别人开发了很多图形化管理系统,给自己的却是命令行。我很支持这样的图形化开发、运维工具!!!

宇润-非洲black鬼人人得而诛之
宇润-非洲black鬼人人得而诛之
命令行不直观,有时候需要一目了然的
邪小白
邪小白
个人觉得命令行比图形化更方便、快捷,个人还是比价喜欢。当然,图形化还是好。
1
Moumoon
Moumoon
我都去管理服务器了还要图形界面干啥子
0
pytimer
pytimer
��,不过感觉还是linux的crontab更方便,毕竟是linux标配,JTimer是不是需要额外安装,生产环境上用稍微有点麻烦,不过自己的开发机器上可以用
你看我像谁
你看我像谁
crontab只能在本机执行,可移值性和管理都是很大的问题。jtimer不知道是否支持集群环境?
0
你若安好
你若安好

这种东西就应该用golang啊不需要搭建环境直接运行

0
little_kid
little_kid

部署稍微有些麻烦。推荐一个国人开发的分布式任务管理系统。。。部署简单,支持多机,也带UI管理

https://github.com/shunfei/cronsun/blob/master/README_ZH.md

0
osc_225877
osc_225877

 Rundeck 了解下 

0
刘建业
刘建业
大于等于和小于等于是个好东西,等于就会有这个问题。
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部