一、需求设计
======
1.1 需求概述
--------
**背景:**
传统的crontab任务调度存在以下缺点
1.机器故障,任务停止调度,设置crontab配置都找不回来(单机故障)
2.任务数量多,单机的硬件资源耗尽,需要人工的迁移到其他机器上(扩展性不好)
3.需要人工去机器上配置crontab规则,任务执行状态不方便查看(可通过配置中心来批量管理多台机器)
以上都是传统的crontab任务调度存在的痛点
**需求:**
通过设计一款分布式任务调度系统来解决传统crontab任务调度存在的单机故障、扩展性不好,众多机器管理麻烦的问题
做这个项目主要是为了练练手,加强下分布式系统的实践,实践出真知嘛
1.2 功能需求
1.2.1 web前端需求
1)增加任务页面
2)删除任务页面
3)修改任务页面
4)查询所有任务的页面
5)查询任务执行日志(了解任务运行情况)
6)查看worker集群中的健康节点
7)强杀执行中的任务(force kill)
1.2.2 后端需求
1)提供增加任务的http接口
2)提供删除任务的http接口
3)提供修改任务的http接口
4)提供查询任务的http接口
5)提供查询所有任务的http接口
6)提供查询任务执行日志信息的http接口
二、概要设计
======
2.1 系统架构
--------
整个功能涉及到的子系统的框架图如下:
Master集群:提供任务的增删改查服务,以及任务执行日志的查询
Worker集群:从etcd中同步master下发的任务,执行任务,并将任务执行结果上传到mongodb数据库
etcd任务存储:负责存储master下发的任务,如定时任务、强杀任务等
mongodb日志存储:负责存储任务执行结果,便于了解任务的运行状态,提供接口给master集群来查询任务执行日志
分布式锁:当多个worker节点想同时执行一个任务时,需要通过etcd分布式乐观锁来实现一个任务只被一个worker节点执行。
每个worker利用分布式锁抢占,解决并发调度相同任务的问题
三、详细设计
======
详细设计分为Master集群设计、Worker集群设计、通用数据结构设计三部分
3.1 Master集群设计
--------------
任务管理HTTP接口:新建、删除、修改、查看任务
通过etcd操作/cron/jobs/目录
任务日志HTTP接口:查看任务执行历史日志
通过读取mongodb
任务控制HTTP接口:提供强制结束任务的接口(强杀)
通过向etcd的/cron/killer目录写入要强杀的任务名字,worker感知到此任务需要被强杀
web管理页面:基于jquery + bootstrap的web控制台,实现前后端分离
3.2 Worker集群设计
--------------
**任务同步**:监听etcd中/cron/jobs目录的变化
**任务调度**:基于crontab表达式计算,并触发过期的任务
**任务执行**:协程池并发执行多个任务,基于etcd分布式锁抢占,抢到锁的才进行执行
**执行日志保存**:捕获任务执行输出,保存到Mongodb中
根据各个功能的不同,可分为以下几个协程
1)监听协程
利用etcd watch api监听/cron/jobs和/cron/killer目录的变化
将变化的事件通过channel通知给调度协程,并更新内存中的任务信息
2)cron调度协程
要做的事情包括以下几点:
监听任务变化的事件event(如增删改查),并维护内存中的任务列表(etcd中任务的一个镜像)
检查cron表达式,扫描过期任务,交给执行协程去执行
监听任务控制事件event,强制中断正在执行中的子进程(通过context来取消任务)
监听任务执行成功后的结果,更新内存中的任务状态(未执行,执行中,执行完成),投递执行日志到日志上报协程
3)任务执行协程
在etcd中抢占分布式乐观锁,/cron/lock/任务名
抢占成功则通过Command类来执行shell命令
捕获Command输出并等待子进程结束,将执行结果重新投递给调度协程
4)日志上报协程
监听调度协程发来的执行日志,放入一个batch中,等待批量处理(批量插入可提高mongodb的吞吐量)
申请指定长度的buffer
1s超时提交
buffer满了,也会进行提交
3.3 通用数据结构
----------
**任务管理**
struct jobMgr {
name string, //任务名
command string, //shell命令
cronExpr string, //crontab表达式
}
通过3.1部分的描述可知,向etcd中写入位置是/cron/jobs,key为任务名,value为jobMgr结构体
worker节点监听/cron/jobs目录的所有变化,当master将指定任务写入到etcd的/cron/jobs目录后,内容会被实时同步到所有worker节点。
**任务日志**
任务日志是记录任务的执行情况,存储在mongodb数据库
{
jobName, //任务名
command, //shell命令
err, //任务执行报错
output, //任务执行输出
startTime, //开始时间
endTime, //结束时间,看出任务执行了多久
}
请求mongodb,按照任务名来查看最近的执行日志,最近的N条日志
**任务控制**
etcd结构
/cron/killer/任务名 -> ""
向etcd的/cron/killer目录下写入,key为任务名,value为空
worker节点会监听/cron/killer目录下的put修改操作
当master向/cron/killer目录下写入指定任务名时,相当于通知worker集群强杀这个任务
四、测试
4.1 测试用例的设计
4.2 功能测试
4.3 性能测试
其中功能测试和性能测试,