分布式任务调度

原因

  1. 存在一些耗时较长的运算,需要从web服务中移出,比如缓存计算、报表导出
  2. 管控力度:原先的运算集群采用mq通信方式,master对worker的管控力度不够,会出现一个任务重复失败拖垮集群的现象
  3. worker之前不能区分,原因还是没有直接由master派发任务,也无法做跨语言调度

目标

master

  1. 稳定、高可用,不执行具体运算
  2. 接收、记录待执行的任务,按任务优先级派发,记录任务执行结果,支持超时、重试、失败状态
  3. 能管控worker生命,知道它的运行状态和任务进度,根据worker状态派发任务
  4. 向业务方通知运行结果

worker

  1. 启动时向master注册自己的环境和算力
  2. 定时汇报自己的运行状态
  3. 支持多语言

实现

通信

基于grpc的stream方式通信,worker端目前采用重启方式重连,master端可通过end事件清除失效worker

1
2
3
4
5
6
7
service Greeter {
rpc Command (stream body) returns (stream body) {}
}
message body {
string body = 1;
}

master和worker的结构

  • 基于egg,风格结构与后端业务框架基本相同
  • 主要分为job和life_cycle,分管任务和生命周期

Resize icon

master
  • 通过mq记录任务,并定期读取任务到缓存,按优先级排序,
  • 处理worker连接,定期检查连接情况
  • 派发任务,只在新worker连接和任务完成时执行,定期检查任务执行状态
worker
  • 接受master派发的任务调用本地service/method执行,在表中记录执行结果
  • 定期自检健康发送心跳给master

使用

任务代码的编写

  • 在worker端实现
  • 代码位置在service文件夹
1
2
3
4
5
6
// app/service/authorization.js
const Service = require('@fgrid/egg').Service;
class AuthorizationService extends Service {
async deleteAuthorization(){}
}

代码结构与业务框架一致,业务数据通过rpc获取,原则上不直连业务数据库

业务服务调用任务

  • sdk直接写在fgrid-middleware

调用方式和rpc调用类似

1
2
// 通过mifStart来调用分布式任务,后面接serviceName.methodName
this.ctx.mifStart.authorization.deleteAuthorization()

计划实现功能

  1. master高可用
  2. worker多语言版和算力等属性
  3. 定时任务