Light-task-scheduler (LTS) is used to solve distributed task scheduling and supports real-time tasks, scheduled tasks, and Cron tasks. It has good scalability, scalability, robustness and stability and is used by many companies, but also hope open source enthusiasts to contribute together.

##1.7.2-SNAPSHOT(master

  1. Optimization of JobContext BizLogger, from removing the threadlocal, solve the problem of taskTracker multithreading, remove LtsLoggerFactory. GetLogger () usage

Framework profiles

LTS has the following four types of nodes:

  • JobClient: submits tasks and receives task execution feedback.
  • JobTracker: Responsible for receiving and assigning tasks and task scheduling.
  • TaskTracker: Perform tasks and send feedback to JobTracker.
  • Lts-admin :(management background) manages nodes, task queues, and monitoring.

JobClient, JobTracker, and TaskTracker are stateless. Multiple deployment and dynamic deletion can be implemented to achieve load balancing and a larger load. In addition, the framework adopts FailStore strategy to make LTS have good fault tolerance.

LTS registries provide a variety of implementations (Zookeeper, Redis, etc.), registries for node information exposure, master election. (Mongo or Mysql) stores the task queue and task execution log, Netty or MINA does the underlying communication, and provides various serialization methods such as Fastjson, Hessian2, Java, etc.

LTS supports the following types of tasks:

  • Real-time task: A task to be executed immediately after submission.
  • Timed task: A task to be performed at a specified time point, such as 3 o ‘clock today (single).
  • Cron task: CronExpression, similar to Quartz (but not implemented using Quartz) such as 0/1 * * *?

Support dynamic modification of task parameters, task execution time and other Settings, support for background dynamic addition of tasks, support for Cron task suspension, support for manually stopping the task being executed (conditional), support for task monitoring statistics, support for each node task execution monitoring,JVM monitoring and so on.

Architecture diagram

! Use LTS to help you solve distributed task scheduling problems! (https://p1-tt.byteimg.com/origin/pgc-image/1530776305077b9b6967f0a?from=pc)

The concept that

# # # node group

  1. NodeGroup: a NodeGroup is equivalent to a small cluster. All nodes in a NodeGroup are equivalent and provide the same services externally.
  2. Each node group has a master node, which is dynamically selected by LTS. When a master node fails, LTS will immediately select another master node. The framework provides API listening interface for users.

###FailStore

  1. As the name implies, this is mainly used for failed storage, mainly used for node fault tolerance, when the remote data exchange fails, the storage is stored locally, waiting for the remote communication to resume, and then the data is submitted.
  2. In the scenario of submitting JobClient tasks, receiving TaskTracker tasks, and transferring TaskTracker service logs, the main user of FailStore submits JobClient tasks, receives TaskTracker tasks, and sends TaskTracker service logs.
  3. FailStore currently offers several implementation: leveldb rocksdb, berkeleydb, mapdb, LTSDB, used are free to choose what kind of, the user can also use SPI extension using your own implementation.

The flow chart

Below is a standard real-time task execution flow.

! Use LTS to help you solve distributed task scheduling problems! (https://p6-tt.byteimg.com/origin/pgc-image/1530779139311649ef41942?from=pc)

Preview the new lTS-admin interface

! Use LTS to help you solve distributed task scheduling problems! (https://p6-tt.byteimg.com/origin/pgc-image/15307763087877d099ad4c2?from=pc)

Currently there is a simple authentication function provided by Ztajy in the background. User name and password in auth. CFG, you can change the password by yourself.

LTS does not need to use the Spring framework at all, but since most user projects use the Spring framework, LTS also provides support for Spring, including Xml and annotations, including lTS-spring.jar. The task log can be submitted to JobTracker. The business log can be connected by the task ID. The execution progress of the task can be viewed in real time in lTS-admin. SPI extension support SPI extension can achieve zero intrusion, only need to achieve the corresponding interface, and implementation can be used by LTS, currently open out of the extension interface

  1. Users can choose not to use mysql or Mongo as queue storage, or they can implement the extension of the task queue.
  2. An extension to the business logger, which currently supports Console, mysql, and Mongo, gives users the option to send logs elsewhere.

When the TaskTracker is down, JobTracker immediately reassigns all the tasks assigned to the down TaskTracker to other normal TaskTracker nodes. 5. Node monitoring can monitor JobTracker and TaskTracker nodes for resource monitoring, task monitoring, etc. It can be viewed in the LTS-Admin management background in real time, so as to allocate resources reasonably. The LTS framework supports four types of execution results: EXECUTE_SUCCESS, EXECUTE_FAILED, EXECUTE_LATER, and EXECUTE_EXCEPTION, and applies a mechanism for each result, such as retry.

  • EXECUTE_SUCCESS: Execution succeeds, in which case the client is reported directly (if the task is set).
  • EXECUTE_FAILED: indicates that the execution fails. In this case, the information is directly reported to the client without retry.
  • EXECUTE_LATER: execute the command later (retry required). In this case, no feedback is received to the client and the retry policy is 1 minute, 2 minutes, or 3 minutes. The default maximum number of retries is 10.
  • EXECUTE_EXCEPTION: Executes an exception, which is also retried (retry policy, ditto)

The FailStore mechanism is adopted to implement node fault tolerance. Fail And Store will not affect the current application operation because of the instability of remote communication. For details about FailStore, see FailStore in Concept Description.

The project is mainly built using Maven and currently provides shell script packaging. Environment dependency: Java(jdk1.6+) Maven

You can upload LTS jars to a local repository using Maven commands. Add the appropriate repository to the parent pom.xml and upload it using the deploy command. For details, refer to the LTS example. Direct Jar references require packaging LTS modules into separate JARS and importing all LTS dependencies. You can refer to the LTS example to see which JAR packages are referenced.

##JobTracker and LTS-Admin deployment provide (CMD) Windows and (shell) Linux versions of scripts for compilation and deployment:

  1. Run the sh build.sh or build. CMD script in the root directory to generate the LTS -{version}-bin folder in the dist directory

  2. Here is its directory structure, where the bin directory is mainly the startup script for JobTracker and LTS-admin. Jobtracker indicates the JobTracker configuration file and jar package to be used. Lts-admin indicates the WAR package and configuration file related to LTS-admin. LTS -{version}-bin Specifies the file structure

    — lts-${version}-bin |– bin | |– jobtracker.cmd | |– jobtracker.sh | |– lts-admin.cmd | |– lts-admin.sh | |– lts-monitor.cmd | |– lts-monitor.sh | |– tasktracker.sh |– conf | |– log4j.properties | |– lts-admin.cfg | |– lts-monitor.cfg | |– readme.txt | |– tasktracker.cfg | |– zoo | |– jobtracker.cfg | |– log4j.properties | |– lts-monitor.cfg |– lib | |– *.jar |– war |– jetty | |– lib | |– *.jar |– lts-admin.war

  3. The JobTracker. If you want to start a node, just modify the conf/zoo configuration file and run sh jobtracker. Sh zoo start. Then you need to make a copy of the zoo, say zoo2, modify the configuration file for zoo2, and run sh jobtracker.sh zoo2 start. Generate jobtracker-zoo.out log under logs folder.

  4. LTS – Admin start. CFG and conf/lts-admin. CFG, and then run the sh lts-admin.sh or lts-admin. CMD script in bin. Lts-admin. out logs are generated in the logs folder. The access address is printed in the log after the startup is successful.

Lts-jobclient -{version}. Jar, lTS-core -{version}. Jar, and other third-party dependent jars. ###API start

JobClient jobClient = new RetryJobClient(); jobClient.setNodeGroup("test_jobClient"); jobClient.setClusterName("test_cluster"); JobClient. SetRegistryAddress (" zookeeper: / / 127.0.0.1:2181 "); jobClient.start(); Job Job = new Job(); job.setTaskId("3213213123"); job.setParam("shopId", "11111"); job.setTaskTrackerNodeGroup("test_trade_TaskTracker"); // job.setCronExpression("0 0/1 * * * ?" ); Job.settriggertime (new Date()); job.settriggerTime (new Date()); Response Response = jobClient.submitJob(job);Copy the code

###Spring XML

<bean id="jobClient" class="com.github.ltsopensource.spring.JobClientFactoryBean"> <property name="clusterName" Value = "test_cluster" / > < property name = "registryAddress" value = "zookeeper: / / 127.0.0.1:2181" / > < property name = "nodeGroup." value="test_jobClient"/> <property name="masterChangeListeners"> <list> <bean class="com.github.ltsopensource.example.support.MasterChangeListenerImpl"/> </list> </property> <property name="jobFinishedHandler"> <bean class="com.github.ltsopensource.example.support.JobFinishedHandlerImpl"/> </property> <property name="configs"> <props> <! - parameter - > < prop key = "job. Fail. Store" > leveldb < / prop > < / props > < / property > < / bean >Copy the code

###Spring full annotation

@Configurationpublic class LTSSpringConfig { @Bean(name = "jobClient") public JobClient getJobClient() throws Exception { JobClientFactoryBean factoryBean = new JobClientFactoryBean(); factoryBean.setClusterName("test_cluster"); FactoryBean. SetRegistryAddress (" zookeeper: / / 127.0.0.1:2181 "); factoryBean.setNodeGroup("test_jobClient"); factoryBean.setMasterChangeListeners(new MasterChangeListener[]{ new MasterChangeListenerImpl() }); Properties configs = new Properties(); configs.setProperty("job.fail.store", "leveldb"); factoryBean.setConfigs(configs); factoryBean.afterPropertiesSet(); return factoryBean.getObject(); }}Copy the code

Lts-tasktracker -{version}. Jar, lTS-core -{version}. Jar, and other third-party dependent jars. ### Define your own task execution class

public class MyJobRunner implements JobRunner { @Override public Result run(JobContext jobContext) throws Throwable { Try {// TODO business logic // will be sent to LTS (JobTracker) jobContext.getBizLogger().info(" test, business log ahhhh "); } catch (Exception e) { return new Result(Action.EXECUTE_FAILED, e.getMessage()); } return new Result(action.execute_success, "execute successfully, ha ha "); }}Copy the code

###API start

TaskTracker taskTracker = new TaskTracker(); taskTracker.setJobRunnerClass(MyJobRunner.class); TaskTracker. SetRegistryAddress (" zookeeper: / / 127.0.0.1:2181 "); taskTracker.setNodeGroup("test_trade_TaskTracker"); taskTracker.setClusterName("test_cluster"); taskTracker.setWorkThreads(20); taskTracker.start();Copy the code

###Spring XML

<bean id="taskTracker" class="com.github.ltsopensource.spring.TaskTrackerAnnotationFactoryBean" init-method="start"> <property name="jobRunnerClass" value="com.github.ltsopensource.example.support.MyJobRunner"/> <property name="bizLoggerLevel" value="INFO"/> <property name="clusterName" value="test_cluster"/> <property Name = "registryAddress" value = "zookeeper: / / 127.0.0.1:2181" / > < property name = "nodeGroup" value = "test_trade_TaskTracker" / > <property name="workThreads" value="20"/> <property name="masterChangeListeners"> <list> <bean class="com.github.ltsopensource.example.support.MasterChangeListenerImpl"/> </list> </property> <property name="configs"> <props> <prop key="job.fail.store">leveldb</prop> </props> </property></bean>Copy the code

Start with ###Spring annotations

@Configurationpublic class LTSSpringConfig implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Bean(name = "taskTracker") public TaskTracker getTaskTracker() throws Exception { TaskTrackerAnnotationFactoryBean factoryBean = new TaskTrackerAnnotationFactoryBean(); factoryBean.setApplicationContext(applicationContext); factoryBean.setClusterName("test_cluster"); factoryBean.setJobRunnerClass(MyJobRunner.class); factoryBean.setNodeGroup("test_trade_TaskTracker"); factoryBean.setBizLoggerLevel("INFO"); FactoryBean. SetRegistryAddress (" zookeeper: / / 127.0.0.1:2181 "); factoryBean.setMasterChangeListeners(new MasterChangeListener[]{ new MasterChangeListenerImpl() }); factoryBean.setWorkThreads(20); Properties configs = new Properties(); configs.setProperty("job.fail.store", "leveldb"); factoryBean.setConfigs(configs); factoryBean.afterPropertiesSet(); // factoryBean.start(); return factoryBean.getObject(); }}Copy the code

## Parameter description

In general, only one JobClient instance is needed in a JVM. Do not create a JobClient instance for each task. This is a huge waste of resources, because a JobClient can submit multiple tasks. The same JVM generally tries to have only one TaskTracker instance, too many can be a waste of resources. When you encounter a TaskTracker that runs multiple tasks, see “A TaskTracker that performs multiple tasks” below. Sometimes, business scenarios require multiple tasks to be performed, and some people ask if there should be a TaskTracker for each task type. My answer is no, it is better to use a Single TaskTracker to run multiple tasks in a SINGLE JVM, because it is a waste of resources to use multiple TaskTracker instances in a single JVM (of course, if you have a large number of tasks, This task can be performed using a TaskTracker node alone). So how do you implement a TaskTracker to perform multiple tasks? Here are my reference examples.

/** * main entrance, In taskTracker. SetJobRunnerClass (JobRunnerDispatcher. Class) * JobClient submit tasks in the Job. The Job type setParam (" type ", "aType") */public class JobRunnerDispatcher implements JobRunner { private static final ConcurrentHashMap<String/*type*/, JobRunner> JOB_RUNNER_MAP = new ConcurrentHashMap<String, JobRunner>(); static { JOB_RUNNER_MAP.put("aType", new JobRunnerA()); // You can also take job_runner_map. put("bType", new JobRunnerB()); } @Override public Result run(JobContext jobContext) throws Throwable { Job job = jobContext.getJob(); String type = job.getParam("type"); return JOB_RUNNER_MAP.get(type).run(job); }}class JobRunnerA implements JobRunner { @Override public Result run(JobContext jobContext) throws Throwable { // TODO Logical return null for A Job. }}class JobRunnerB implements JobRunner { @Override public Result run(JobContext jobContext) throws Throwable { // TODO Logical return null for B Job; }}Copy the code

When writing TaskTracker, you only need to test JobRunner’s implementation logic. You don’t want to start LTS for remote testing. To facilitate testing, LTS provides JobRunner’s quick test method. Your test class integration com. Making. Ltsopensource. Tasktracker. Runner. JobRunnerTester can, and implement initContext and newJobRunner method. Examples in lTS-examples:

public class TestJobRunnerTester extends JobRunnerTester { public static void main(String[] args) throws Throwable { // Mock Job data Job Job = new Job(); job.setTaskId("2313213"); JobContext jobContext = new JobContext(); jobContext.setJob(job); JobExtInfo jobExtInfo = new JobExtInfo(); jobExtInfo.setRetry(false); jobContext.setJobExtInfo(jobExtInfo); TestJobRunnerTester = new TestJobRunnerTester(); Result result = tester.run(jobContext); System.out.println(JSON.toJSONString(result)); } @override protected void initContext() {// TODO initializes the Spring container} @override protected JobRunner newJobRunner() {return new TestJobRunner(); }}Copy the code

Quartz Cron tasks can be accessed from the LTS platform by adding code to the Spring configuration

<bean class="com.github.ltsopensource.spring.quartz.QuartzLTSProxyBean"> <property name="clusterName" Value = "test_cluster" / > < property name = "registryAddress" value = "zookeeper: / / 127.0.0.1:2181" / > < property name = "nodeGroup." value="quartz_test_group"/></bean>Copy the code

# # Spring Boot support

@SpringBootApplication@EnableJobTracker // Start JobTracker@EnableJobClient // Start JobClient@EnableTaskTracker // TaskTracker@EnableMonitor // Monitorpublic Class Application {public static void main(String[] args) { SpringApplication.run(Application.class, args); }}Copy the code

Just in application. The rest have to do is add the corresponding configuration properties, specific see LTS – example of com. Making. Ltsopensource. Examples. Examples under springboot package

When the machine has two network cards on the Intranet, sometimes the user wants the LTS traffic to go through the external network card, so you need to change the mapping address of the host name to the external network card address in the host, the same as the internal network card address.

If the node id is set when the node is started,LTS will set a UUID as the node ID by default, which will be less readable, but can ensure the uniqueness of each node. If the user can guarantee the uniqueness of the node id, you can use setIdentity For example, if each node is deployed on a machine (a virtual machine), then identity can be set to the host name

SPI extensions support JobLogger,JobQueue, etc

## lts-admin starts with Jetty (default) and hangs the solution irregularly

If the LTS admin user is not used for a long time, the user will hang up at intervals.

Jetty will unzip LTS Admin’s war package to/TMP in the root directory. If the TMP directory is not updated for a long time, it will be periodically deleted by cron task. After deletion, the page will be opened only with text, js and CSS cannot be loaded.

Solution:

Change the lts-admin.sh script, where the start section is changed to the following, add a -d parameter, to ensure that war is unzipped to this directory and not deleted.

Nohup “JAVA” − djava.io. Tmpdir =/home/work/ TMP −cp”JAVA” -djava.io. Tmpdir =/home/work/ TMP -cp Djava.io. Tmpdir =/home/work/ TMP −cp”CLASSPATH” JVMFLAGSJVMFLAGS JVMFLAGSLTS_MAIN “CONFHOME”>”CONF_HOME” > “CONFHOME”>”_LTS_DAEMON_OUT” 2>&1 < /dev/null &