本文主要介绍一下任务调度框架Flowjob的整体结构,以及整体的心路历程。
功能介绍
flowjob主要用于搭建统一的任务调度平台,方便各个业务方进行接入使用。 项目在设计的时候,考虑了扩展性、稳定性、伸缩性等相关问题,可以作为公司的任务调度中间件被使用。
当前项目的主要稳定版本为2.x,并且在2.x版本中提供了相应的前端页面配合使用。
项目地址
https://github.com/limbo-world/flowjob
在线试用
在线试用
账号:flowjob
密码:fjdemo
功能介绍
flowjob主要分为以下几个部分:
- Broker:管控节点,对配置好的任务在集群进行负载,调度任务并下发Agent,同时管理和维护Agent/Worker节点注册等。
- Agent:代理节点,接收下发的Job信息,生成Task下发给Worker执行,处理Job的生命周期,比如工作流流转等。可以独立部署,也可以依赖宿主启动。
同时此节点可以减少广播/Map/MapReduce等分片任务导致Broker存在的数据/性能压力,以及云原生环境下一些启停导致的数据问题。 - Worker:工作节点,主要负责Task的具体执行。
- Console:通过Broker提供的Api,进行任务创建/更新等一些管控操作。
- Registry:注册中心,目前使用DB做为注册中心。提供了对应接口,可以基于其它组件如zk、nacos等进行灵活的封装。
- Datasource:数据库用于持久化运行数据
调度类型
- 固定速度:作业创建后,每次调度下发后,间隔固定时间长度后,再次触发作业调度。
- 固定延迟:作业创建后,每次作业下发执行完成(成功或失败)后,间隔固定时间长度后,再次触发作业调度。
- CRON:通过CRON表达式指定作业触发调度的时间点。
负载策略
- 随机:将作业随机下发给某一个worker执行。
- 轮询:将任务逐个分配给worker。
- 最不经常使用:将作业下发给一个时间窗口内,接收作业最少的worker。
- 最近最少使用:将作业下发给一个时间窗口内,最长时间没有接受worker的worker。
- 一致性hash:同样参数的作业将始终下发给同一台机器。
- 指定节点:让作业指定下发到某个worker执行。
节点过滤方式
- 执行器:任务只会下发给包含任务对应执行器的worker。
- 标签:任务只会下发给包含指定标签的worker。
- 容量:基于worker的任务队列/CPU/内存使用情况过滤
任务触发方式
- API:通过指定api触发任务执行。
- 调度:Broker自动组装数据,调度对应的任务。
任务类型
按大体配置分为:
- 普通任务:只会执行一个Job。
- 工作流任务:DAG视图,可以串联Job
按Job类型分为:
- 普通:对应某个执行器,执行结束任务结束。
- 广播:在下发的时间点,对每个可下发的节点下发任务,所以子任务执行完成当前任务才执行完成。
- Map:分为sharding和map两个步骤。sharding的时候进行分片,map则对每个拆分任务进行执行。
- MapReduce:相比于Map多了Reduce过程,可以对所有Map任务的执行结果进行一个汇总。
经历分享
会接触任务调度系统也是因为工作原因。其实在平时工作中很多时候接触比较多的是Quartz、xxl-job这两款框架。然后之前工作中我们组内使用的是light-task-scheduler(此框架也是当时项目组的前辈做的)。但是在使用过程中,我们发现存在一些不太便利的问题,比如没法动态进行配置,有些时候可能需要高配置节点跑数据,没法指定节点,我们的任务存在关联关系,当时只能通过代码写逻辑来实现等等。所以和之前同事也是在后面慢慢开始打算自己着手搞一个出来。
项目兜兜转转也是经历和好几年的时间才终于能有一个相对满意的2.x版本出来。开发这样一个分布式系统,其实耗费的精力十分大,由于是工作之余进行整体方案设计和功能开发,总会被这样那样的事情打断,中间因为一些个人原因以及时间分配问题,也是中断了好多次。
项目过程中,你要考虑,分布式场景下如何保证任务的重试,如何判断长时间的任务是否还在正常执行,还得考虑任务越来越多节点压力过高的挑战。
希望本项目可以帮助大家理解分布式系统中存在的问题和如何解决这类问题。代码中有很多不足也是希望大家能帮忙指出一起进步。后续有时间会继续更新项目中存在的难点,以及项目中的解决思路。