In the previous article, we introduced how to use Spring Boot's built-in @Scheduled
annotation to realize the timing task . The limitations of this approach are also mentioned at the end of the article. When in a cluster environment, if the execution or operation of the task relies on some shared resources, there will be competition. If you do not introduce mechanisms such as distributed locks for scheduling, unexpected execution results may occur. Therefore, the @Scheduled
annotation is more reasonable for some timed tasks related to the maintenance of the single instance itself, such as regularly cleaning files in a certain directory of the service instance, and regularly uploading some statistical data of this instance.
So, when the business logic is actually implemented, there is no better timing task plan? Today we will introduce an old distributed timing task framework, a use case under Spring Boot.
Elasitc Job
The predecessor of Elastic Job was Dangdang's open source distributed task scheduling framework, and it has now joined the Apache Foundation.
There are two branches under this project: ElasticJob-Lite and ElasticJob-Cloud. ElasticJob-Lite is a lightweight task management solution. The following cases in this article will use this to achieve. and
ElasticJob-Cloud is relatively heavier because it uses containers to manage tasks and isolate resources.
For more information about ElasticJob, you can also to go directly to the official website for more information.
Try it
Say so much, let's try it together!
first step : Create a basic Spring Boot project, if not yet? Then take a look at this Quick Start .
Step : pom.xml
added starter elasticjob-lite of
<dependencies>
<dependency>
<groupId>org.apache.shardingsphere.elasticjob</groupId>
<artifactId>elasticjob-lite-spring-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
// ...
</dependencies>
third step : Create a simple task
@Slf4j
@Service
public class MySimpleJob implements SimpleJob {
@Override
public void execute(ShardingContext context) {
log.info("MySimpleJob start : didispace.com {}", System.currentTimeMillis());
}
}
Fourth step : Edit the configuration file
elasticjob.reg-center.server-lists=localhost:2181
elasticjob.reg-center.namespace=didispace
elasticjob.jobs.my-simple-job.elastic-job-class=com.didispace.chapter72.MySimpleJob
elasticjob.jobs.my-simple-job.cron=0/5 * * * * ?
elasticjob.jobs.my-simple-job.sharding-total-count=1
There are two main parts here:
The first part: elasticjob.reg-center
, mainly configure the registration center and namespace of elastic job
The second part: task configuration, elasticjob.jobs
, where my-simple-job
is the name of the task, you can name it according to your preference, but don't repeat it. The configuration elastic-job-class
under the task is the implementation class of the task, cron
is the execution regular expression, and sharding-total-count
is the total number of task fragments. We can use this parameter to split the task and achieve parallel processing. Set it to 1 here first, and we will talk about the use of fragmentation later.
Run and test
When all the above operations are completed, we can try to run the above application, because ZooKeeper is needed to coordinate task scheduling in a distributed environment. So, you need to install ZooKeeper locally and then start it. Note: The above elasticjob.reg-center.server-lists
configuration should be modified according to the ZooKeeper address and port you actually use.
After starting the above Spring Boot application, we can see the following log output:
2021-07-20 15:33:39.541 INFO 56365 --- [ main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler 'my-simple-job' initialized from an externally provided properties instance.
2021-07-20 15:33:39.541 INFO 56365 --- [ main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler version: 2.3.2
2021-07-20 15:33:39.551 INFO 56365 --- [ main] org.apache.curator.utils.Compatibility : Using org.apache.zookeeper.server.quorum.MultipleAddresses
2021-07-20 15:33:40.067 INFO 56365 --- [ main] c.d.chapter72.Chapter72Application : Started Chapter72Application in 3.25 seconds (JVM running for 4.965)
2021-07-20 15:33:40.069 INFO 56365 --- [ main] .s.b.j.ScheduleJobBootstrapStartupRunner : Starting ElasticJob Bootstrap.
2021-07-20 15:33:40.078 INFO 56365 --- [ main] org.quartz.core.QuartzScheduler : Scheduler my-simple-job_$_NON_CLUSTERED started.
2021-07-20 15:33:40.078 INFO 56365 --- [ main] .s.b.j.ScheduleJobBootstrapStartupRunner : ElasticJob Bootstrap started.
2021-07-20 15:33:45.157 INFO 56365 --- [le-job_Worker-1] com.didispace.chapter72.MySimpleJob : MySimpleJob start : didispace.com 1626766425157
2021-07-20 15:33:50.010 INFO 56365 --- [le-job_Worker-1] com.didispace.chapter72.MySimpleJob : MySimpleJob start : didispace.com 1626766430010
2021-07-20 15:33:55.013 INFO 56365 --- [le-job_Worker-1] com.didispace.chapter72.MySimpleJob : MySimpleJob start : didispace.com 1626766435013
Since it is a distributed task scheduling, let's start another one (note that when the same machine is started, there will be port conflicts, you can add -Dserver.port=8081
to the start command to distinguish the ports), and the second started service log is also printed Similar content
2021-07-20 15:34:06.430 INFO 56371 --- [ main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler 'my-simple-job' initialized from an externally provided properties instance.
2021-07-20 15:34:06.430 INFO 56371 --- [ main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler version: 2.3.2
2021-07-20 15:34:06.436 INFO 56371 --- [ main] org.apache.curator.utils.Compatibility : Using org.apache.zookeeper.server.quorum.MultipleAddresses
2021-07-20 15:34:06.786 INFO 56371 --- [ main] c.d.chapter72.Chapter72Application : Started Chapter72Application in 1.446 seconds (JVM running for 1.884)
2021-07-20 15:34:06.787 INFO 56371 --- [ main] .s.b.j.ScheduleJobBootstrapStartupRunner : Starting ElasticJob Bootstrap.
2021-07-20 15:34:06.792 INFO 56371 --- [ main] org.quartz.core.QuartzScheduler : Scheduler my-simple-job_$_NON_CLUSTERED started.
2021-07-20 15:34:06.792 INFO 56371 --- [ main] .s.b.j.ScheduleJobBootstrapStartupRunner : ElasticJob Bootstrap started.
2021-07-20 15:34:10.182 INFO 56371 --- [le-job_Worker-1] com.didispace.chapter72.MySimpleJob : MySimpleJob start : didispace.com 1626766450182
2021-07-20 15:34:15.010 INFO 56371 --- [le-job_Worker-1] com.didispace.chapter72.MySimpleJob : MySimpleJob start : didispace.com 1626766455010
2021-07-20 15:34:20.013 INFO 56371 --- [le-job_Worker-1] com.didispace.chapter72.MySimpleJob : MySimpleJob start : didispace.com 1626766460013
At this point, after looking back at the first application started before, the log output stopped. Since we set the total number of shards to 1, after this task is started, only one instance will take over the execution. This avoids the problem of multiple simultaneous and repeated execution of the same logic. At the same time, this also supports the high availability of task execution. For example: you can try to terminate the second started application (which is printing logs). It can be found that the first application started (which has stopped outputting the log before) continues to print the task log.
In the entire implementation process, we did not manually write any distributed locks and other codes to implement the task scheduling logic. We only need to pay attention to the task logic itself, and then control the division of the task by configuring the fragmentation method, which can be easily Realize timing task management in distributed cluster environment. Is it more convenient to implement this method in complex scenarios than @Scheduled
Remember to write by yourself, so that you will have a deeper experience! If you encounter a problem, you can pull the code example at the end of the article to compare whether there is a difference in configuration. In the next article, we will continue to introduce some advanced content about timed tasks. If you are interested in this content, you can bookmark this series of tutorial "Spring Boot 2.x Basic Tutorial" and click directly! . If you encounter difficulties in the learning process, you can join our Spring technical exchange group , participate in exchanges and discussions, and better study and progress!
Code example
The complete project of this article can be viewed in the chapter7-2
directory in the following warehouse:
- Github:https://github.com/dyc87112/SpringBoot-Learning/
- Gitee:https://gitee.com/didispace/SpringBoot-Learning/
If you think this article is good, welcome Star
support, your attention is my motivation for persistence!
Welcome to pay attention to my public account: Program Ape DD, share knowledge and thoughts that can’t be seen elsewhere
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。