背景
最近一直忙于对数据进行清洗及业务数据输出,构建了大量的hadoop、hive等定时任务,这些任务存在依赖关系,任务A是任务B的基础数据生产者,但且叫做B依赖A,那么B必须在A之后运行(复杂的依赖关系可以查看下图),同时,这些任务分散到各个系统中,仅仅依靠linux的crontab
,或者开发语言内的定时框架,不能更好的维护、管理越来越多的任务,因此,我需要一个可以方便调度、管理的任务中心平台,但仅限于管理和调度,不对单个任务做分布式的计算,所以,基于此做了一个简单的实现。
目的
- 实现分布式调度任务
- 实现负载均衡
- 实现任务的依赖关系管理,被依赖任务可自动触发依赖任务的执行
- 实现方便添加、删除、触发任务等
- 实现对任务的监控、告警
- 调度中心必须高可用
架构设计
- 整体设计
使用后台管理系统申请分组,创建任务等。任务创建好后,使用第三方组件(robfig/cron)做定时任务的触发,任务触发后,将任务数据包装,丢进Redis的队列中,客户端通过接口消费Redis队列数据。在任务触发到丢进Redis队列之间这个时间段,可以做依赖关系、任务状态、负载均衡等等操作,以决定是否下发此任务,或者选择客户端某个节点执行。客户端获取到任务消息后,负责执行任务,上报任务状态及上报节点负载情况。 - 模块
- 任务调度模块
- api模块(支持rpc、http等)
- client模块(支持众多语言,如Go、Java、Python、Shell等)
- web后台管理模块
- 内部定时任务
架构设计图如下
数据库设计
- task:任务表
- task_prev:前置任务任务表
- job:触发的作业表
- job_state:作业执行状态表
- group:分组表,一般以项目或者团队分组
- node:用户节点表
Redis设计
- tsc:t:i:{tid}:数据库任务对应cron装配的任务ID,结构string
- tsc:j:q:{tid}:{node}:任务队列,结构list
- tsc:t:j:l:{tid}:{date}:任务执行中锁,结构string
- tsc:w:s:{tid}:{date}:后置任务列表,结构set
- tsc:w:s:l:{tid}:{date}:后置任务表操作锁,结构string
核心代码实现
- 任务调度
//检验是否有任务已经在运行
exists, err := existsJob(t.Tid, t.TaskDate)
if err != nil {
fmt.Println(fmt.Sprintf("task job exists err,jobId:%d,%v", jobId, err))
saveJobState(jobId, domain.StateInnerFailed)
return jobId
}
if exists {
fmt.Println(fmt.Sprintf("task job exists,jobId:%d", jobId))
saveJobState(jobId, domain.StateDuplicated)
return jobId
}
//负载均衡,目前简单做成随机,后续根据任务数量、cpu、内存等节点负载情况做优化
targetIp := ips[rand.Intn(len(ips))]
key := fmt.Sprintf(db.TaskJobQueue, t.gid, targetIp)
t.JobId = jobId
value, err := json.Marshal(t)
if err != nil {
fmt.Println(fmt.Sprintf("serialization job err,job_id:%d,%v", jobId, err))
saveJobState(jobId, domain.StateInnerFailed)
return jobId
}
err = db.RDB.RPush(context.Background(), key, value).Err()
if err != nil {
fmt.Println(fmt.Sprintf("add job to queue err, job_id: %d,%v", jobId, err))
saveJobState(jobId, domain.StateInnerFailed)
return jobId
}
总结
由于时间有限,花了两天时间写完了大概的代码,项目使用go语言开发,本人一直使用go刷lc,对go情有独钟,当然,以目前的情况看,本人go代码写的并不够美观,但并不影响这个项目的设计初衷。目前待做的事情很多,如权限代码的加入,负载均衡的完善,日志的收集,监控告警的实现等等,后面有时间慢慢实现吧。查看源码请移步 jackmanwu/task-schedule-center