分布式任务调度系统设计与实现

背景

最近一直忙于对数据进行清洗及业务数据输出,构建了大量的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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章