Single point scheduled task

The JDK native

Since JDK1.5, ScheduledExecutorService is provided to perform scheduled tasks instead of TimerTask, providing good reliability.

Public class SomeScheduledExecutorService {public static void main (String [] args) {/ / create a task queue, A total of 10 threads ScheduledExecutorService ScheduledExecutorService = Executors. NewScheduledThreadPool (10); // Execute a task: 1 second after the start, once every 30 seconds to perform scheduledExecutorService. ScheduleAtFixedRate (() - > {System. Out. Println (" mission: "+ new Date ()); }, 10, 30, TimeUnit.SECONDS); }}Copy the code

Spring Task

The Spring Framework comes with scheduled tasks and provides cron expressions to implement rich scheduled task configuration. Beginners are recommended to use https://cron.qqe2.com/ to match your cron expressions.

@Configuration @EnableScheduling public class SomeJob { private static final Logger LOGGER = LoggerFactory.getLogger(SomeJob.class); /** ** Scheduled(cron = "Scheduled 1 ** *? *") public void someTask() { //... }}Copy the code

Single point timing service in the current micro-service environment, the application scenario is more and more limited, so try distributed timing task.

Based on Redis implementation

Compared with the previous two methods, this Redis based implementation can increase scheduled tasks and multi-point consumption through multi-point. But be prepared to guard against repeat spending.

Through ZSet

The scheduled task is stored in the ZSet set, and the expiration time is stored in the Score field of the ZSet. Then, a loop is used to determine whether there are scheduled tasks to be executed in the current time. If there are, the scheduled task will be executed.

The specific implementation code is as follows:

/** * Description: * * @author mxy */ @configuration @enablesCheduling public class RedisJob {public static final String JOB_KEY = "redis.job.task"; private static final Logger LOGGER = LoggerFactory.getLogger(RedisJob.class); @Autowired private StringRedisTemplate stringRedisTemplate; ** @param task */ public void addTask(String task, Instant instant) { stringRedisTemplate.opsForZSet().add(JOB_KEY, task, instant.getEpochSecond()); } /** * Scheduled task queue consumption * consumption per minute (can shorten the interval to 1s) */ @scheduled (cron = "0/1 ** *? *") public void doDelayQueue() { long nowSecond = Instant.now().getEpochSecond(); / / query the current time of all tasks Set < String > strings. = stringRedisTemplate opsForZSet (). The range (JOB_KEY, 0, nowSecond); For (String task: strings) {// Start consuming Task Logger. info(" Execute task :{}", task); } / / delete has performed tasks stringRedisTemplate. OpsForZSet (), remove (JOB_KEY, 0, nowSecond); }}Copy the code

The application scenarios are as follows:

  • 15 minutes after the order is placed, the system automatically cancels the order if the user has not paid for it.
  • Red envelope is not checked for 24 hours, need to delay the return business;
  • An activity is specified to take effect & expire at a certain time;

Advantages are:

  • MySQL query operation is omitted, and Redis with higher performance is used instead.
  • The tasks to be performed will not be missed due to downtime and other reasons;

Key space notification

We can implement scheduled tasks through Redis key space notification. Its implementation idea is to set an expiration time for all scheduled tasks. When the expiration time is reached, we can sense that the scheduled task needs to be executed by subscriing to the expiration message, so we can execute the scheduled task.

By default, Redis does not enable keyspace notification. You need to run the config set notify-keyspace-events Ex command to manually enable keyspace notification. The code for the scheduled task is as follows:

Custom listeners
 /**   * 自定义监听器.   */
public class KeyExpiredListener extends KeyExpirationEventMessageListener {
    public KeyExpiredListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    @Override
    public void onMessage(Message message, byte[] pattern) {
        // channel
        String channel = new String(message.getChannel(), StandardCharsets.UTF_8);
        // 过期的key
        String key = new String(message.getBody(), StandardCharsets.UTF_8);
        // todo 你的处理
    }
}
Copy the code
Set the listener
/** * Description: Implement scheduled tasks by subscribes to Redis expiration notifications.<br> * * @author mxy */ @Configuration Public class RedisExJob {@autoWired private RedisConnectionFactory redisConnectionFactory; @Bean public RedisMessageListenerContainer redisMessageListenerContainer() { RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer(); redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory); return redisMessageListenerContainer; } @Bean public KeyExpiredListener keyExpiredListener() { return new KeyExpiredListener(this.redisMessageListenerContainer()); }}Copy the code

Spring listens for Redis messages that conform to the following format

private static final Topic TOPIC_ALL_KEYEVENTS = new PatternTopic("__keyevent@*");
Copy the code

Redis-based timed task can be applied to a limited number of scenarios, but it is relatively simple to implement, but it has great requirements for functional idempotent. In terms of usage scenarios, it should be called delayed task.

Scenario Example:

  • 15 minutes after the order is placed, the system automatically cancels the order if the user has not paid for it.
  • Red envelope is not checked for 24 hours, need to delay the return business;

Advantages and disadvantages:

  • Passive trigger, less resource consumption for services;
  • Redis Pub/Sub is not reliable, no ACK mechanism, etc., but generally tolerable;
  • Keyspace notification can be CPU intensive

Distributed scheduled Task

Introduce distributed timing task component or middleware

Having scheduled tasks as a separate service prevents repeated consumption, and a separate service also facilitates expansion and maintenance.

quartz

Depending on MySQL, it is relatively simple to use, can be deployed on multiple nodes, by competing for database locks to ensure that only one node performs tasks. No graphical management page, relatively cumbersome to use.

elastic-job-lite

Based on Zookeeper, you can dynamically add servers by registering and discovering Zookeeper.

  • Multiple modes of operation
  • Failure to transfer
  • Health collection
  • Multithreading data processing
  • idempotence
  • Fault-tolerant processing
  • Support for spring namespaces
  • There is a graphical management page

LTS

Based on Zookeeper, servers can be added dynamically in cluster deployment. You can manually add scheduled tasks, start or suspend tasks.

  • Service logger
  • SPI extension support
  • failover
  • Node monitoring
  • Diversified task execution results support
  • FailStore fault-tolerant
  • Dynamic capacity
  • Relatively spring friendly
  • There are graphical interfaces for monitoring and management

xxl-job

Domestic, dependent on MySQL, based on competitive database lock to ensure that only one node to perform tasks, support horizontal expansion. You can manually add scheduled tasks, start or suspend tasks.

  • The elastic expansion
  • Subdivision radio
  • failover
  • Rolling real-time log
  • GLUE (online code editing, publish-free)
  • Task progress monitoring
  • Task dependent on
  • Data encryption
  • Email alert
  • Run the report
  • Elegant downtime
  • Internationalization (Chinese friendly)

conclusion

In microservices, it is recommended to use component services such as XXl-job to manage scheduled tasks in a reasonable and effective manner. The single-point scheduled task has its limitations and is suitable for small scale services with low requirements for future expansion.

Spring Task-based scheduled tasks are relatively simple and quick, while xxL-Job is difficult to integrate and debug. Whatever the timing task, you need to make sure that:

  • Tasks are not executed multiple times because of cluster deployment.
  • Task exceptions are handled effectively
  • Slow processing of tasks leads to a large backlog
  • Tasks should be executed at the expected point in time

Middleware can decouple services, but adds complexity

Source: juejin. Cn/post / 6930912870058328071


Recommend 3 original Springboot +Vue projects, with complete video explanation and documentation and source code:

Build a complete project from Springboot+ ElasticSearch + Canal

  • Video tutorial: www.bilibili.com/video/BV1Jq…
  • A complete development documents: www.zhuawaba.com/post/124
  • Online demos: www.zhuawaba.com/dailyhub

【VueAdmin】 hand to hand teach you to develop SpringBoot+Jwt+Vue back-end separation management system

  • Full 800 – minute video tutorial: www.bilibili.com/video/BV1af…
  • Complete development document front end: www.zhuawaba.com/post/18
  • Full development documentation backend: www.zhuawaba.com/post/19

【VueBlog】 Based on SpringBoot+Vue development of the front and back end separation blog project complete teaching

  • Full 200 – minute video tutorial: www.bilibili.com/video/BV1af…
  • Full development documentation: www.zhuawaba.com/post/17

If you have any questions, please come to my official account [Java Q&A Society] and ask me