通常,我们在公司里的部分对外服务都是多集群多节点部署的。同时我们可能一些拆分的不是很细的服务,里面混杂着一些定时任务。
而定时任务中,有些业务为了防止同一时间并发操作,我们就用到了“分布式锁
”。
一般最简单的方法我们就是使用redis加锁机制来实现分布式锁
。
这里我我们使用ShedLock
来在定时任务
中实现分布式锁
。
maven
<dependency><groupId>net.javacrumbs.shedlock</groupId><artifactId>shedlock-spring</artifactId><version>4.3.0</version></dependency><dependency><groupId>net.javacrumbs.shedlock</groupId><artifactId>shedlock-provider-redis-jedis</artifactId><version>4.3.0</version></dependency>
配置LockProvider
单节点测试
@Beanpublic JedisPool createJedisCluster() {// 因为我是本地测试的代码,所以使用的是jedisPoolJedisCluster jedisCluster = new JedisCluster(hostAndPorts);JedisPool jedisPool = new JedisPool();return jedisPool;}@Beanpublic LockProvider createLockProvider(JedisPool jedisPool) {JedisLockProvider jedisLockProvider = new JedisLockProvider(jedisPool);return jedisLockProvider;}
集群测试
@Beanpublic JedisCluster createJedisCluster() {HashSet<HostAndPort> hostAndPorts = new HashSet<>();hostAndPorts.add(new HostAndPort("ip", port));JedisCluster jedisCluster = new JedisCluster(hostAndPorts);return jedisCluster;}@Beanpublic LockProvider createLockProvider(JedisCluster jedisCluster) {JedisLockProvider jedisLockProvider = new JedisLockProvider(jedisCluster);return jedisLockProvider;}
开启SchedLock
@SpringBootApplication
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class Application {public static void main(String[] args) {SpringApplication.run(SpringApplication.class, args);}
}
创建定时任务
@Component
class BaeldungTaskScheduler {@Scheduled(cron = "0 0/15 * * * ?")@SchedulerLock(name = "TaskScheduler_scheduledTask", lockAtLeastForString = "PT5M", lockAtMostForString = "PT14M")public void scheduledTask() {// ...}
}
参数说明
@SchedulerLock注解主要参数:
name
:锁的名称,必须保证唯一;
lockAtMostFor
:成功执行任务的节点所能拥有的独占锁的最长时间,设置的值要保证比定时任务正常执行完成的时间大一些;
lockAtLeastFor
:成功执行任务的节点所能拥有的独占锁的最短时间,其主要目的是任务执行时间可能很短,防止多个节点执行。
@EnableSchedulerLock注解主要参数:
defaultLockAtMostFor
:lockAtMostFor
的默认时间;
defaultLockAtLeastFor
:lockAtLeastFor
的默认时间。
ISO8601时间格式
格式解析
R2/2023-06-04T20:15:14.765432+08:00/P1DT10S
上面的字符串通过"/"分为了三部分即:
重复次数/开始时间/运行间隔
重复次数
R - 将永远重复
R1 - 将重复一次
R23 - 将重复23次。
开始时间
其中"T"用来分割日期和时间,时间后面跟着的"+08:00"表示东八区,注意"+"是连字符,不是加号。
时区默认是0时区,可以用"Z"表示,也可以不写。
上面的字符串表示 2023年6月4日,20点15分14秒765432纳秒,东八区。
运行间隔
运行间隔以"P"开始,和上面一样也是用"T"分割日期和时间,如P2Y2M10DT2H30M15S
-
P 开始标记
-
2Y 两年
-
2M 两个月
-
10D 十天
-
T 时间和日期分的割标记
-
2H 两个小时
-
30M 三十分钟
-
15S 十五秒钟
例子,注意如果没有年月日,"T"也不能省略
P1DT1M 一天一分钟执行一次
P1W 一周执行一次
PT1H 一小时执行一次
PT10S 十秒执行一次