Giter Club home page Giter Club logo

antares's Introduction

分布式任务调度平台(Distributed Job Schedule Platform)Build Status

Antares特性

基于Quartz的分布式调度

  • 一个任务仅会被服务器集群中的某个节点调度,调度机制基于成熟的Quartz,antares内部会重写执行逻辑;

并行执行

  • 用户可通过对任务预分片,有效提升任务执行效率;

失效转移

  • 客户端实效转移:当某个客户端实例在执行任务中宕机时,其正在执行的分片将重新由其他客户端实例执行;

  • 服务器失效转移:当服务器集群中某个节点宕机时,其正在调度的任务将转移到其他节点去调度;

弹性扩容

  • 客户端扩容:客户端可通过增加应用实例,提升任务执行的效率;
  • 服务器扩容:服务器集群可通过增加节点,提升集群任务调度的服务能力;

进程级的应用实例

  • antares通过ip+进程号标识客户端应用实例,因此支持单机多应用实例部署;

任务依赖

  • antares支持树形任务依赖,当某任务执行完成后,会通知其后置任务执行;

任务报警

  • antares支持基本的任务超时报警失败报警等;

管理控制台

  • 用户可通过控制台antares-tower对任务进行基本操作,如触发暂停监控等。

Demo

在线Demo(用户名/密码:admin/admin123)。

名称术语

  • 应用(App)

    用于标识分组,如用户服务订单服务等;

  • 应用实例(App Instance)

    某应用下的客户端实例,即某个进程实例

  • 任务(Job)

    即被调度的实体,仅会由某一服务器节点调度;

  • 任务实例(Job Instance)

    每当任务被触发时,则会生产一个任务实例,执行完成后,则为任务历史

  • 任务分片(Job Instance Shard)

    即任务的预分片配置,包含分片数分片参数,用户可通过客户端实例执行任务时被分配的分片项及其分片参数,自己实现分片逻辑;

  • 分片项(shardItem)、分片参数(shardParam)

    分片项(shardItem),即当应用实例任务执行时,被分配的任务下标,从0开始;分片参数,即任务下标对应的配置参数

应用场景

通常,对于有以下场景或需求时,可以考虑使用分布式任务调度

  • 需要保证任务执行的高可用性:即当执行任务的应用实例崩溃后,其他应用实例可以继续执行该任务;

  • 要求任务执行效率足够高:在业务数据量级比较大时,可以使用预分片配置来将数据进行逻辑分片,使得多个应用实例能并行执行任务分片,以提升任务的执行效率。

Antares架构

Antares整体架构

antares-arch.png

Antares中的任务状态机

job-state-machine.png

快速开始

环境准备

编译打包

  • 下载最新的压缩包;

  • 或者通过源码构建:

     mvn clean package -DskipTests -Prelease

安装服务器(antares-server)

  • 解压安装包:

     tar zxf antares-server-{version}.tar.gz
     ll antares-server-{version}
     bin		# 执行脚本
     conf	# 配置目录
     lib		# 依赖包
  • 编辑配置文件antares.conf

     # 服务器绑定的IP
     BIND_ADDR=127.0.0.1
     
     # 服务器的监听端口
     LISTEN_PORT=22122
     
     # Redis主机地址
     REDIS_HOST=127.0.0.1
     
     # Redis主机端口
     REDIS_PORT=6379
     
     # Redis的数据键前缀
     REDIS_NAMESPACE=ats
     
     # 日志目录,相对或绝对路径
     LOG_PATH=./logs
     
     # Zookeeper地址
     ZK_SERVERS=127.0.0.1:2181
     
     # Zookeeper命名空间
     ZK_NAMESPACE=ats
     
     # 服务器宕机后,启动Failover前的等待时间(单位为秒,通常大于服务器正常重启的时间,避免因为重启服务器,导致不必要的Failover)
     SERVER_FAILOVER_WAIT_TIME=30
     
     # 调度器的线程数
     SCHEDULE_THREAD_COUNT=32
     
     # JVM堆参数
     JAVA_HEAP_OPTS="-Xms512m -Xmx512m -XX:MaxNewSize=256m"
  • 启动/关闭/重启服务器:

     ./bin/antares.sh start
     ./bin/antares.sh stop
     ./bin/antares.sh restart

安装控制台(antares-tower)

  • 解压安装包:

     tar zxf antares-tower-{version}.tar.gz
     ll antares-tower-{version}
     bin		# 执行脚本
     conf	# 配置目录
     lib		# 依赖包
  • 编辑配置文件antares.conf

     # 控制台绑定的IP
     BIND_ADDR=127.0.0.1
     
     # 控制台的监听端口
     LISTEN_PORT=22111
     
     # Redis的主机地址
     REDIS_HOST=127.0.0.1
     
     # Redis的端口
     REDIS_PORT=6379
     
     # Redis的数据键前缀
     REDIS_NAMESPACE=ats
     
     # 日志目录,相对或绝对路径
     LOG_PATH=./logs
     
     # Zookeeper地址127.0.0.1
     ZK_SERVERS=127.0.0.1:2181
     
     # Zookeeper命名空间
     ZK_NAMESPACE=ats
     
     # 控制台用户名
     TOWER_USER=admin
     
     # 控制台密码
     TOWER_PASS=admin
     
     # JVM堆参数配置
     JAVA_HEAP_OPTS="-Xms512m -Xmx512m -XX:MaxNewSize=256m"
     
     # 是否开启报警
     ALARM_ENABLE=false
     
     ## 若ALARM_ENABLE=false,下面的配置可以忽略
     
     # 通知类型(暂仅支持邮件)
     # 1:邮件
     ALARM_NOTIFY_TYPE=1
     
     # 报警标题
     ALARM_SUBJECT=Antares任务报警
     
     # 任务超时报警模版,以下四个变量可用,使用{}开头结尾
     ALARM_TEMPLATE_JOB_TIMEOUT=应用【{appName}】的任务【{jobClass}】执行超时,调度服务器为【{scheduler}】:{detail}.
     
     # 任务失败报警模版,以下四个变量可用,使用{}开头结尾
     ALARM_TEMPLATE_JOB_FAILED=应用【{appName}】的任务【{jobClass}】执行失败,调度服务器为【{scheduler}】:{detail}.
     
     ### 邮件配置
     # 邮箱主机
     MAIL_HOST=192.168.0.1
     
     # 发件人邮箱
     [email protected]
     
     # 发件人用户名
     MAIL_FROM_USER=haolin.h0
     
     # 发件人密码
     MAIL_FROM_PASS=123456
     
     # 收件人列表,逗号隔开
     [email protected]
  • 启动/关闭/重启控制台:

     ./bin/antares.sh start
     ./bin/antares.sh stop
     ./bin/antares.sh restart
  • 这样便可以进入控制台(如http://127.0.0.1:22111),在控制台事先添加应用及任务:

    • 编辑应用:

      app_edit.png

    • 编辑任务:

      job_edit.png

客户端使用

基础知识

  • Job类型:antares支持两种Job类型,DefaultJobScriptJob:

    • DefaultJob为最常用的Job类型,开发人员只需要实现该接口即可,如:

       public class DemoJob implements DefaultJob {
       
           @Override
           public JobResult execute(JobContext context) {
               
               // 可以获取到当前应用实例被分配的分片信息
               // 分片号,从0开始
               context.getShardItem(); 
               // 分片号对应的分片参数
               context.getShardParam();
               
               // 执行任务逻辑...
               // 如有需要,可通过分片信息处理不同的数据集
               // 注意catch异常
               		    
               return JobResult;
           }
       }
    • 实现DefaultJob的任务类的返回结果有三种类型:

      • JobResult.SUCCESS:分片执行成功;

      • JobResult.FAIL:分片执行失败,可以通过JobResult.failed(error)返回,可记录对应的错误信息,便于排查问题;

      • JobResult.LATER:重新分配,这将使得当前分片会重新被分配执行。

    • ScriptJob脚本任务,开发人员只需要继承该类,不需要具体的实现代码,然后配置Job的自定义参数,即为需要执行的命令,如:

       /**
        * 只需继承ScriptJob即可
        */
       public class MyScriptJob extends ScriptJob {
       
       }

      script_job_edit.gif

  • Job分片配置:Job分片配置,主要用于将业务数据进行逻辑分片,需要开发人员自行实现分片逻辑,分片配置只是协助开发人员进行分片,这些配置通常比较有规律,同一应用实例同一时刻只会分配到其中一片,执行完,再拉取其他剩余的任务分片,直到任务执行完成,如:

    job_shard_edit.png

    分片参数由分号隔开,从0开始,每个参数可以是数字,字母或是JSON字符串,比如上面将任务分为3片,这3片对应的参数为0,1,2,我们可以假定将业务数据分为三份,第1份表示记录id % 3 = 0的数据,第2份为记录id % 3 = 1的数据,第3份为记录id % 3 = 2的数据。更常见的场景可能是在分库分表时,同分片参数去划分不同的库或表,当然,如果数据量不大任务执行的时间可接受,也不用分片。

客户端使用(编程模式)

  • 引入maven包:

     <dependency>
         <groupId>me.hao0</groupId>
         <artifactId>antares-client</artifactId>
         <version>1.4.0</version>
     </dependency>
  • antares-client日志处理使用的是slf4j-api,开发人员只需额外引入其实现即可,如log4j,log4j2,logback等,zookeeper操作主要依赖curator,若有版本冲突,注意解决。

  • 启动SimpleAntaresClient

     SimpleAntaresClient client = 
     		new SimpleAntaresClient(
     			"dev_app", 			// 应用名称
     			"123456", 			// 应用密钥
     			"127.0.0.1:2181",	// zookeeper地址 
     			"ats"               // zookeeper命名空间
     		);				
     
     // 执行任务的线程数
     client.setExecutorThreadCount(32);
     
     // 启动客户端			
     client.start();
     
     // 创建job实例,需要实现DefaultJob或ScriptJob
     DemoJob demoJob = new DemoJob();
     
     // 注册job
     client.registerJob(demoJob);
     
  • 具体可见单元测试

客户端使用(Spring模式)

  • 引入maven包:

     <dependency>
         <groupId>me.hao0</groupId>
         <artifactId>antares-client-spring</artifactId>
         <version>1.4.0</version>
     </dependency>
  • 在Spring上下文配置SpringAntaresClient,及其Job实例即可:

     <!-- Spring Antares Client -->
     <bean class="me.hao0.antares.client.core.SpringAntaresClient">
     	<!-- 应用名称 -->
     	<constructor-arg index="0" value="dev_app" />
     	<!-- 应用密钥 -->
     	<constructor-arg index="1" value="123456" />
     	<!-- zookeeper地址 -->
     	<constructor-arg index="2" value="127.0.0.1:2181" />
     	<!-- zookeeper命名空间 -->
     	<constructor-arg index="3" value="ats" />
     	<!-- 执行job的线程数 -->
     	<property name="executorThreadCount" value="32" />
     </bean>
    
     <!-- Job实例 -->
     <bean class="me.hao0.antares.demo.jobs.DemoJob" />
     
     <!-- ... -->
     
  • 具体可见单元测试

客户端使用(Spring Boot Starter模式)

  • 引入maven包:

     <dependency>
         <groupId>me.hao0</groupId>
         <artifactId>antares-client-spring-starter</artifactId>
         <version>1.4.0</version><!-- 1.3.0+ -->
     </dependency>
  • application.yml中引入antares相关配置即可:

     antares:
       appName: myapp
       appSecret: 123456
       zkServers: localhost:2181
       zkNamespace: ats
       executorThreadCount: 32
  • 具体参考可见antares-demo-spring-starter

Job监听

  • 对于想做一些任务监听的操作,开发人员可选择实现JobListenerJobResultListner,如:

     public class DemoJob implements DefaultJob, JobListener, JobResultListener {
     	
     	@Override
     	public JobResult execute(JobContext context) {
            return ...
     	}
    
         @Override
         public void onBefore(JobContext context) {
             // 任务执行前调用
         }
         
         @Override
         public void onAfter(JobContext context, JobResult res) {
     	     // 任务执行后调用
         }
     
         @Override
         public void onSuccess() {
             // 任务执行成功后调用
         }
     
         @Override
         public void onFail() {
             // 任务执行失败后调用
         }
     }

使用控制台

应用运行过程中,开发人员便可通过控制台作一些基本操作,如:

  • 应用管理:

  • 任务配置:

  • 任务依赖:

  • 任务管控:

  • 任务历史:

  • 集群管理:

最佳实践

  • 应将任务应用业务应用独立部署,这两类系统不应相互影响,无论从其属性还是运行环境(如GC)都是有区别的;

  • 对任务配置合理的cron表达式,应保证任务执行的间隔时间大于任务执行的总时间,以免同一时刻同一任务发生多次触发执行(antares同一任务同一时刻,只会有一个实例在执行),其余情况将取决于Quartz的misfire机制

  • 为了防止任务分片重复执行,应用应尽量保证幂等性

  • 合理划分应用,单个任务应用的任务数量不宜太多(如2 * executorThreadCount),防止单个应用实例执行任务太多,影响任务执行效率。

常见问题

  • 有任何问题,请issue

有事请烧钱

  • 支付宝:

  • 微信:

antares's People

Contributors

ihaolin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

antares's Issues

出版社编辑

您好,我是电子工业出版社博文视点的编辑,请问您有兴趣出版分布式方面的图书吗:)

"服务器失效转移"

服务器失效转移:当服务器集群中某个节点宕机时,其正在调度的任务将转移到其他节点去调度;

是否可以理解为:所有任务是平均分配到server中的,一旦其中一个server宕机了,其他server会接管宕机的server的任务,如果这个宕机的server恢复了,其他server又会把任务还给这个server?
如果是这样的话,这个分布式算法太牛逼了,求教怎么做到的

创建 Job 的 misfire 设置不正确?

JobPool下的createQuartzJob方法

if (jobDetail.getConfig().getMisfire()) {
    // ignore all misfired
    scheduleBuilder.withMisfireHandlingInstructionDoNothing();
} else {
    scheduleBuilder.withMisfireHandlingInstructionFireAndProceed();
}

判断逻辑是不是反了? misfiretrue时才设置为FireAndProceed, 否则为DoNothing ?

添加客户端

你好,请问怎样添加客户端,?
以便于在任务配置列表中,可以对某个任务指定客户端执行

关于指定客户端执行的情况

一个job如果需要指定在某一个客户端执行现在是怎么处理的呢?
比如调用shell,shell脚本是放在某一台主机上的。

server注册ip问题

不指定服务ip,zk上注册ip为-1 建议能修改成获取当前服务器ip。
如果必须显性指定ip 相当不利于容器化 例如像k8s这样内部分配虚拟ip 必须指定会造成扩展困难

任务依赖功能没有实现吧

if (instance != null && finished){ jobSupport.checkJobInstanceFinish(shardFinishDto); }

检查是否job instance完成的时候并没有触发下游啊

Linux下服务启动失败

在windows下,能够正常使用,最近将环境移了Linux-Debian上,如果全部使用127.0.0.1可以启动,但是如果换成本机ip,则会错,报错如下:
java.net.BindException: Cannot assign requested address: bind
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Net.java:433)
at sun.nio.ch.Net.bind(Net.java:425)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:210)
at org.apache.tomcat.util.net.AbstractEndpoint.start(AbstractEndpoint.java:990)
at org.apache.coyote.AbstractProtocol.start(AbstractProtocol.java:635)
at org.apache.catalina.connector.Connector.startInternal(Connector.java:1022)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.StandardService.addConnector(StandardService.java:225)
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.addPreviouslyRemovedConnectors(TomcatEmbeddedServletContainer.java:250)
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.start(TomcatEmbeddedServletContainer.java:193)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.startEmbeddedServletContainer(EmbeddedWebApplicationContext.java:297)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:145)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107)
at me.hao0.antares.server.Bootstrap.main(Bootstrap.java:23)
2017-10-11 14:27:27.541 [main] ERROR - Failed to start connector [Connector[HTTP/1.1-22122]]
org.apache.catalina.LifecycleException: Failed to start component [Connector[HTTP/1.1-22122]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:167)
at org.apache.catalina.core.StandardService.addConnector(StandardService.java:225)
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.addPreviouslyRemovedConnectors(TomcatEmbeddedServletContainer.java:250)
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.start(TomcatEmbeddedServletContainer.java:193)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.startEmbeddedServletContainer(EmbeddedWebApplicationContext.java:297)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:145)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107)
at me.hao0.antares.server.Bootstrap.main(Bootstrap.java:23)
Caused by: org.apache.catalina.LifecycleException: service.getName(): "Tomcat"; Protocol handler start failed
at org.apache.catalina.connector.Connector.startInternal(Connector.java:1029)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 13 common frames omitted
Caused by: java.net.BindException: Cannot assign requested address: bind
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Net.java:433)
at sun.nio.ch.Net.bind(Net.java:425)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:210)
at org.apache.tomcat.util.net.AbstractEndpoint.start(AbstractEndpoint.java:990)
at org.apache.coyote.AbstractProtocol.start(AbstractProtocol.java:635)
at org.apache.catalina.connector.Connector.startInternal(Connector.java:1022)
... 14 common frames omitted
2017-10-11 14:27:27.550 [main] INFO - Pausing ProtocolHandler ["http-nio-47.94.225.72-22122"]
2017-10-11 14:27:27.550 [main] INFO - Stopping service [Tomcat]
2017-10-11 14:27:27.559 [main] INFO - The stop() method was called on component [StandardServer[-1]] after stop() had already been called. The second call will be ignored.
2017-10-11 14:27:27.559 [main] INFO - Stopping ProtocolHandler ["http-nio-47.94.225.72-22122"]
2017-10-11 14:27:27.559 [main] INFO - Destroying ProtocolHandler ["http-nio-47.94.225.72-22122"]
2017-10-11 14:27:27.561 [main] INFO -

Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2017-10-11 14:27:27.566 [main] ERROR -


APPLICATION FAILED TO START


Description:

The Tomcat connector configured to listen on port 22122 failed to start. The port may already be in use or the connector may be misconfigured.

任务调度错误汇总

配置修改,redis配置成redis cluster

  1. 调度服务就会报 has a running instance ,任务就不会再执行
  2. Antares系统报警 elapsedTime 会无限累加 每次都会告警
  3. 停止服务再启动服务,调度已经停止,客户端依旧会执行任务

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.