go-forest

分布式任务调度平台
授权协议 Apache-2.0
开发语言 Google Go
所属分类 程序开发、 作业/任务调度
软件类型 开源软件
地区 国产
投 递 者 卢锋
操作系统 跨平台
开源组织
适用人群 未知
 软件概览

前言

在企业系统开发过程中难免少不了一些定时任务来进行定时触发执行任务,对于非分布式环境系统中,我们只需要在对应系统中内部集成一些调度库进行配置定时触发即可。
比如:使用 Spring 框架集成 quartz ,只需要进行一些简单的配置就能定时执行任务了。但是随着企业的系统越来越多、逐步从单一应用慢慢演变为微服务集群。
在分布式集群系统中主要面临出如:任务的重复执行、没有统一定时任务配置、任务节点故障转移、任务监控&报警等一些列的功能都是要在分布式系统中进行解决。

此分布式的定时任务调度平台,它非常轻量小巧,使用简单,后端以中心服务器为调度核心,负责集群中各种任务的动态分配和调度执行。
在平台前端支持 Web 界面可视化管理,我们可以创建、暂停/启动任务、删除未执行的任务快照、或者查看任务的调度状态和执行日志。
任务抽象调度任务中心不负责业务任务格式,只负责将任务快照分发到指定的客户端即可。

系统架构

可以部署 N 个 Node 节点,同一时刻只有一台 Leader 节点,只有选举成功的Leader节点才有派发任务的权限。任务客户端启动时候通过 Etcd 进行注册客户端元数据信息。

架构

架构图

角色

Job Node Leader 

任务调度集群负责任务的配置管理、监控、任务统计、故障转移以及任务分发工作。整个任务调度集群只有一台 Job Node 是 Leader。

Job Node Follower 

任务调度集群负责任务的配置管理以及监控,整个任务调度集群可以有 N 台 Job Node 是 Follower。没有故障转移、任务分发能力,当Job Node Leader 不可用下线后触发选举,才有机会成为Leader节点。

任务集群(Group)

为了发挥集群的处理业务作业的能力,我们不可能只希望作业集群中的某一台只执行作业。任务集群是将同一个任务或者同一组的任务并发分散到不同的作业机器中。发挥更大的作业能力。

任务作业(Client)

任务作业(Client)是每一台作业机器重启后会自动注册至Etcd中方便Job Node Leader 能够将指定的任务分配给自己。自己作业完毕会将结果回传给Etcd指定的目录中以方便Leader进行统计收集工作。

选举

由于一个任务调度集群有多台提供服务,我们在可以从集群节点中选举出一台领导节点来进行发号师令,比较成熟的选举算法(Paxos、Raft 等)这里不做讨论。这里使用etcd中的租约机制来实现选举功能。
当一个调度服务节点启动的时候首先尝试发起选举请求(PUT 节点 /forest/server/elect/leader),如果执行成功则选举成功。如果判断已经有其他调度服务节点已经选举成功过则放弃选举请求并进行监听(/forest/server/elect/leader)选举节点变化。如果有领导下线通知则立即发起选举。

在任务调度服务集群中一条任务配置在同一时刻保证只能触发一次任务,如果所有的任务集群都触发了次任务那就说明此任务被重复的执行了N次。我们需要从调度集群中选举出一个调度Leader节点进行指挥。
只有Leader调度节点才能分发任务,其他的Follower节点没有权限分发任务,一旦Leader调度Node挂掉,其他Follower节点则会重新选举,诞生一台新的Leader节点继续指挥服务。

平台特点

1.  通过[Web界面管理](https://github.com/busgo/duck),操作简单方便,支持各种任务
2.  高可用可以部署N台调度集群节点,保证没有单点故障。
3.  部署简单、仅仅需要一个执行文件即可运行。
4.  集成方便,统一任务抽象,接入sdk so easy!
5.  任务故障转移,任务客户端下线自动切至在线客户端任务机器。

快速开始

sql脚本

CREATE TABLE `job_execute_snapshot` (
	`id` VARCHAR (64) NOT NULL COMMENT '主键',
	`job_id` VARCHAR (32) NOT NULL COMMENT '任务定义id',
	`name` VARCHAR (32) NOT NULL COMMENT '任务名称',
	`group` VARCHAR (32) NOT NULL COMMENT '任务集群',
	`cron` VARCHAR (32) NOT NULL COMMENT 'cron表达式',
	`target` VARCHAR (255) NOT NULL COMMENT '目标任务',
	`params` VARCHAR (255) DEFAULT NULL COMMENT '参数',
	`ip` VARCHAR (32) NOT NULL COMMENT 'ip',
	`status` TINYINT (4) NOT NULL COMMENT '状态 1-执行中 2-完成 3-未知 4-错误',
	`mobile` VARCHAR (32) DEFAULT NULL COMMENT '手机号码',
	`remark` VARCHAR (255) DEFAULT NULL COMMENT '备注',
	`create_time` VARCHAR (32) NOT NULL COMMENT '创建时间',
	`start_time` VARCHAR (255) DEFAULT NULL COMMENT '开始时间',
	`finish_time` VARCHAR (32) DEFAULT NULL COMMENT '结束时间',
	`times` BIGINT (20) DEFAULT '0' COMMENT '耗时',
	`result` VARCHAR (255) DEFAULT NULL COMMENT '返回结果',
	PRIMARY KEY (`id`),
	KEY `ip` (`ip`),
	KEY `job_id` (`job_id`),
	KEY `status` (`status`),
	KEY `group` (`group`)
) ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT = '任务作业执行快照';

先决条件
  golang(>=1.11)
  git

源代码安装

   git clone https://github.com/busgo/forest.git
    cd forest/forest
    go build forest.go
等待自动下载依赖库
appledeMacBook-Pro:forest apple$ go build forest.go 
go: finding github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2
go: finding github.com/dgrijalva/jwt-go v3.2.0+incompatible
go: finding github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6
go: finding github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f
go: finding github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a
go: finding github.com/prometheus/client_golang v1.0.0
go: finding github.com/coreos/bbolt v1.3.3
go: finding github.com/prometheus/common v0.4.1
go: finding github.com/grpc-ecosystem/go-grpc-middleware v1.0.0
go: finding github.com/coreos/etcd v3.3.13+incompatible
go: finding github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5
go: finding github.com/grpc-ecosystem/grpc-gateway v1.9.4
go: finding github.com/gogo/protobuf v1.1.1
go: finding github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc
go: finding github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d
go: finding gopkg.in/yaml.v2 v2.2.1
...
如果下载依赖库出现超时问题,请重复执行编译命令直到成功为止。

查询命令参数

appledeMacBook-Pro:forest apple$ ./forest  -help
flag needs an argument: -help
Usage of ./forest:
  -db-url string
        db url for mysql (default "root:123456@tcp(127.0.0.1:3306)/forest?charset=utf8")
  -etcd-dailtimeout int
        etcd dailtimeout (default 5)
  -etcd-endpoints string
        etcd endpoints (default "127.0.0.1:2379")
  -help string
        forest help
  -http-address string
        http address (default ":2856")

启动服务

nohup etcd  > etcd.log 2>&1 & 
	
nohup forest  > forest.log 2>&1 & 
	
appledeMacBook-Pro:forest apple$ tail -500f forest.log 
{"time":"2019-07-25T15:05:40.041263+08:00","level":"-","prefix":"-","file":"node.go","line":"71","message":"the job node:192.168.10.35, success register to :/forest/server/node/192.168.10.35"}

   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v3.3.10-dev
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
{"time":"2019-07-25T15:05:40.046041+08:00","level":"INFO","prefix":"-","file":"group.go","line":"92","message":"add a new group:account,for path:/forest/server/group/account"}
{"time":"2019-07-25T15:05:40.046172+08:00","level":"INFO","prefix":"-","file":"group.go","line":"92","message":"add a new group:order,for path:/forest/server/group/order"}
{"time":"2019-07-25T15:05:40.049989+08:00","level":"-","prefix":"-","file":"node.go","line":"210","message":"the job node:192.168.10.35,elect  success to :/forest/server/elect/leader"}
{"time":"2019-07-25T15:05:40.050021+08:00","level":"INFO","prefix":"-","file":"group.go","line":"92","message":"add a new group:trade,for path:/forest/server/group/trade"}
⇨ http server started on [::]:2856
交叉编译
 # mac os 
  GOOS=darwin GOARCH=amd64 go build forest.go
   
  # linux
  GOOS=linux GOARCH=amd64 go build forest.go
    
  # windows
  GOOS=windows GOARCH=amd64 go build forest.go
安装web分布式任务调度平台
下载源码[duck](https://github.com/busgo/duck)
 git clone https://github.com/busgo/duck.git
    cd duck 
    
    修改 request.js 文件中的地址
    
    npm install 
    
    启动服务 
    
     # 开发环境
    npm  run dev
    
    # 生产环境
    npm run-script build
Etcd 元数据目录说明
### 选举目录

>   /forest/server/elect/leader

是一个临时节点,用于任务调度节点选举,选举成功将节点的ip写入

### 调度节点注册目录

>   /forest/server/node/%s

调度集群中的节点将自己的节点ip写入

### 任务集群

>   /forest/server/group/

任务集群信息全放入此目录下

### 任务快照

>   /forest/client/snapshot/%s/%s/%s

分配任务快照信息放入此目录下

such as  /forest/client/snapshot/trade/192.168.1.1/201901011111111323


### 任务客户端信息

>   /forest/client/%s/clients/

所有任务客户端注册此目录下

such as  /forest/client/trade/clients/192.168.1.1


### 任务作业上报目录
>   /forest/client/execute/snapshot/%s/%s/

such as  /forest/client/execute/snapshot/trade/192.168.1.1/201901011111111323

 管理任务

任务配置管理

任务配置管理

新建任务 

新建任务

任务集群

任务集群

任务执行计划 

任务执行计划

调度集群

调度集群

任务快照 

任务快照

任务客户端节点

任务作业客户端列表

任务作业快照

任务作业列表

Client Libraries

jforest for java

gforest for go 

待完善

1. ~~任务故障转移~~

2. ~~任务执行日志收集~~

3. 任务作业sdk

4. ~~手动执行任务~~

5. ~~任务统计~~

6. 任务报警

7. ~~任务调度计划同步~~

 

  • 【判断题】维生素C是所有维生素中最不稳定的一种维生素 【填空题】吉田兼好の作『徒然草』の読み方:( ) 【单选题】目前最新版本的Linux可以支持( )。 【单选题】在linux下,符号( )表示追加输出重定向。 【单选题】可以使用下面命令( ),快速把一个文件中所有字符转换成大写字符。 【单选题】LINUX内核自行启动后,通过启动一个用户级程序init的方式,完成了自己的引导进程。在这个过程中i

  • MagicForest has many trees, such as linetree , suffix-tree , red-black tree.... Do you master all the trees? But don't worry, in this problem I will not talk about trees.Instead, I am going to introdu

  • 给出一个 n ≤ 3 e 5 n\leq3e5 n≤3e5的仙人掌,然后求问有多少种删边的方案,使得这个仙人掌变成一个森林,仙人掌保证一条边不会被两个简单环共用。 找出所有的环,那么环中的边只要至少删掉一条即可满足,而剩下所有的非环的边则可删可不删,直接求出所有的点双连通分量,答案为 ∏ ( 2 s − 1 ) 2 t \prod(2^{s}-1)2^{t} ∏(2s−1)2t,s是每个点双中的边

 相关资料
  • 简介 在过去,开发者必须在服务器上为每个任务生成单独的 Cron 项目。而令人头疼的是任务调度不受源代码控制,而且必须通过 SSH 连接到服务器上来增加 Cron 项目。 Laravel 的命令调度程序允许你在 Laravel 中对命令调度进行清晰流畅的定义。并且在使用调度程序时,只需要在服务器上增加一条 Cron 项目即可。调度是在 app/Console/Kernel.php 文件的 sche

  • 基本任务调度 方案1: 通过 @Cron 注解,这个需要依赖 cron4j 框架: //1分钟执行一次 @Cron("*/1 * * * *") public class MyTask implements Runnable { @Override public void run() { System.out.println("task running...");

  • 在这最后一章中,我们将回到:kv应用程序,给它添加一个路由层,使之可以根据桶的名字,在各个节点间分发请求。 路由层会接收一个如下形式的路由表: [{?a..?m, :"foo@computer-name"}, {?n..?z, :"bar@computer-name"}] 路由者(负责转发请求的角色,可能是个节点)将根据桶名字的第一个字节查这个路由表, 然后根据路由表所示将用户对桶的请求发给相应

  • 写了个基于kratos的服务,基本需求是:可以增删管理定时任务(如配置每天、每周发个统计报告),支持分布式结构,持久化任务。加分项包括:注册回调、结果和日志记录、失败重试等。 看kratos已经支持的transport有两个:asynq和machinery,但似乎都不满足需要基本的持久化任务需求,machinery甚至还不能删除已经添加的任务。 考虑到服务可能会重启,那么添加过的任务如何恢复呢?如

  • 每隔一段时间需要调度任务执行,也许你想注册一个任务在客户端完成连接5分钟后执行,一个常见的用例是发送一个消息“你还活着?”到远端通,如果远端没有反应,则可以关闭通道(连接)和释放资源。 本节介绍使用强大的 EventLoop 实现任务调度,还会简单介绍 Java API的任务调度,以方便和 Netty 比较加深理解。 使用普通的 Java API 调度任务 在 Java 中使用 JDK 提供的 S

  • ShardingSphereTransactionManager SPI 名称 详细说明 ShardingSphereTransactionManager 分布式事务管理器 已知实现类 详细说明 XAShardingSphereTransactionManager 基于 XA 的分布式事务管理器 SeataATShardingSphereTransactionManager 基于 Seata 的分