记录工作问题 -- 解决多实例情况下:定时任务重复执行的问题
多实例情况下:定时任务重复执行的问题前言一、不使用自动生效的定时任务二、使用redis 创建一个标识来判断(此处引用同事的想法)三、使用XXLJOB四、使用ShedLock + redis最后说明前言场景:现在集群越来越普及,一个服务拥有多个实例时,何如避免定时任务重复执行?一、不使用自动生效的定时任务详见:https://blog.csdn.net/qq_37700773/article/det
前言
场景:现在集群越来越普及,一个服务拥有多个实例时,何如避免定时任务重复执行?
一、不使用自动生效的定时任务
详见:https://blog.csdn.net/qq_37700773/article/details/109385361?spm=1001.2014.3001.5501
但是不建议使用,原因是不方便。
。
二、使用redis 创建一个标识来判断(此处引用同事的想法)
定时任务启动的时候,先去redis查询是指定key是否存在值(这里使用reids 的AtomicLong)
这里使用的是redission,实质上执行的这句代码:
// CacheUtil.incrAtomicLong(Key)这句代码的底层
public long incrAtomicLong(String key) {
return redissonClient.getAtomicLong(key).incrementAndGet();
}
三、使用XXLJOB
xxljob是一个单独的服务,思路是:
1:业务系统内没有定时任务,而是将定时任务逻辑写成一个接口
2:在xxljob服务端管理台配置好参数,由xxljob服务定时调用业务系统
3:xxljob服务调用业务集群(xxljob请求网关/ng,最终请求哪个业务实例,由网关/ng规则决定)
xxljob这种模式,还是有点麻烦。而且我经常会忘记:还有xxljob?部署在哪?地址多少?
四、使用ShedLock + redis
推荐使用这个。对性能要求不是特别高的(性能要求在比肩某东、某宝的…这款肯定也不合适)
这个只是日常开发使用,执行任务的服务实例在十几个以内的,应该没啥问题。
推荐的主要原因是:很简单
spring项目中引入依赖:
<!-- 分布式定时任务锁 shedlock支持 Mongo,Redis,Hazelcast,ZooKeeper,JDBC,这里使用redis -->
<!-- https://mvnrepository.com/artifact/net.javacrumbs.shedlock/shedlock-spring -->
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>4.0.4</version>
</dependency>
<!-- 使用redis做分布式任务 -->
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-redis-spring</artifactId>
<version>2.5.0</version>
</dependency>
增加shedLock的配置,使用的redis
package com.tao.scheduled.shedLock;
import net.javacrumbs.shedlock.core.LockProvider;
import net.javacrumbs.shedlock.provider.redis.spring.RedisLockProvider;
import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
/**
* 分布式定时调度配置
* <p>
* SchedulerLock 注解一共支持五个参数,分别是
* name 用来标注一个定时服务的名字,被用于写入数据库作为区分不同服务的标识,如果有多个同名定时任务则同一时间点只有一个执行成功
* lockAtMostFor 成功执行任务的节点所能拥有独占锁的最长时间,单位是毫秒ms
* lockAtMostForString 成功执行任务的节点所能拥有的独占锁的最长时间的字符串表达,例如“PT14M”表示为14分钟
* lockAtLeastFor 成功执行任务的节点所能拥有独占锁的最短时间,单位是毫秒ms
* lockAtLeastForString 成功执行任务的节点所能拥有的独占锁的最短时间的字符串表达,例如“PT14M”表示为14分钟
*/
@Configuration
@EnableSchedulerLock(defaultLockAtMostFor = "PT30M")
public class ShedLockConfig {
@Bean
public LockProvider lockProvider(RedisTemplate redisTemplate) {
return new RedisLockProvider(redisTemplate.getConnectionFactory());
}
}
最简单的定时任务代码
package com.tao.scheduled.shedLock;
import lombok.extern.slf4j.Slf4j;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @Describe 避免定时调度重复执行
**/
@Slf4j
@Component
public class ShedLockDemo {
// @Scheduled(cron = "0/2 * * * * ?") 每2秒执行一次
@Scheduled(cron = "0/2 * * * * ?")
@SchedulerLock(name = "scheduleDemo01")
public void ScheduleDemo01() {
log.info("开启定时任务......");
}
}
启动类加上注:@EnableScheduling
//@EnableFeignClients//开启feign
@EnableSwagger2 //开启 Swagger
@SpringBootApplication
@EnableScheduling//开启定时任务
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class);
System.out.println("======......项目启动成功......======"+ServerPortConfig.host+":"+ ServerPortConfig.serverPort);
}
}
测试方法:
idea启动两个实例,直接观察日志…
最后说明
这篇文章,记录的是工作中遇到的问题,写的比较水。主要用于工作总结和记录
更多推荐
所有评论(0)