一个轻量级、高性能、支持延时任务的任务管理器

源代码地址

特性

    支持即时任务和延时任务 可以单例部署或集群部署 每个任务都有绑定的执行器,指向真正执行任务的代理方

轻量

极少的中间件依赖

    在单例模式下,只依赖mysql/pgsql 在集群模式下,增加了对redis的依赖 资源消耗低,内存占用通常低于 300MB

安全性

    每一个改动都有审计日志 使用token进行认证

运行

已测试的依赖版本

    Java 8 MySQL 8.0, PostgreSQL 12 Redis 6.0

创建数据表

配置数据源

修改 application.yml

性能

主机配置

    OS: Win10 CPU: 6核 12线程 内存:16G 固态硬盘

MySQL 8 , 执行器类型

    stdout,任务数量1000,耗时约1s http, 127.0.0.1:8080/test/echo,任务数量1000,耗时约1s

PostgreSQL 12 , 执行器类型

    stdout,任务数量1000,耗时1s以内 http, 127.0.0.1:8080/test/echo,任务数量1000,耗时约1s

概念

执行器

真正执行任务的代理,例如一个http服务.

协调者

负责协调时钟,向JSD分配任期

Job scanner dispatcher(JSD)

接受协调者分发的任期,分配给JS

Job scanner(JS)

扫描任务序列,将任务ID投递至任务队列

Job queue(JQ)

保存将要执行的任务ID,FIFO

任务消费

从JQ中取出任务ID,获取绑定的执行器并调用执行服务。

利用线程池提升消费速度。

延时任务的实现

任务被一个长整形的唯一ID标识,该ID与执行时间是正相关的.

任务ID的计算基于执行时间和一个自增的序列号。假定任务的执行时间戳为1632041675,序列号为1,任务ID计算如下

1632041675 << 20 + 1

拿到一个时间戳,我们就可以计算出该时间戳对应的最小ID值和最大ID值

1632041675 << 20 + 1
1632041675 << 20 + (1 << 20 - 1)

真相即将揭晓.

任务存储在一张表中,该表的主键是任务ID. 当时钟到达一个时间戳时,JS开始基于计算出的最小ID和最大ID进行范围扫描

就是这样!

集群的实现

集群使用Redis进行信息同步。

在集群中,每个节点都可以是协调者或跟随者,并且所有的节点都是平等的。

跟随者负责消费任务队列,并随时准备成为协调者。

协调者同时也是跟随者,但需要做额外的工作。它还负责扫描任务表,将任务ID投递到队列。

协调者的任期很短,通常为1秒钟。

源代码地址

经验分享 程序员 微信小程序 职场和发展