闲谈ShedLock解决分布式定时任务重复执行问题

多个服务实例代码是一样,定时任务自然也一样。负载均衡在执行的时候,到达某个节点以后,定时任务都会执行,可以控制的思路就是使用队列的方式去操作。

现有思路有以下两种:

  • 将负载均衡的定时任务,从原先的直接执行业务逻辑修改为先将业务逻辑请求到队列中,然后让空闲的微服务去队列中自动领取。
  • 将负载均衡的定时任务,加锁进行操作。

今天要讲的ShedLock就是实现第二种思路的一种方式,ShedLock采用非侵入式编程的思想,通过注解的方式来实现相应的功能。

ShedLock

ShedLock是一个在分布式环境中使用的定时任务框架,用于解决在分布式环境中的多个实例的相同定时任务在同一时间点重复执行的问题。

解决思路是通过对公用的数据库中的某个表进行记录和加锁,使得同一时间点只有第一个执行定时任务并成功在数据库表中写入相应记录的节点能够成功执行而其他节点直接跳过该任务。

当然不只是数据库,目前已经实现的支持数据存储类型除了经典的关系型数据库,还包括MongoDB,Zookeeper,Redis,Hazelcast。

使用

<dependency>
  <groupId>net.javacrumbs.shedlock</groupId>
  <artifactId>shedlock-spring</artifactId>
  <version>0.18.2</version>
</dependency>
import net.javacrumbs.shedlock.core.SchedulerLock;

@Scheduled(cron = "0 0/10 0 * * ?")
@SchedulerLock(name = "scheduledTaskName", lockAtMostFor = 60 * 1000, lockAtLeastFor = 60 * 1000)
public void scheduledTask() {
   System.out.println("scheduledTask");
}

task 

@Bean
public ScheduledLockConfiguration taskScheduler(LockProvider lockProvider) {
    return ScheduledLockConfigurationBuilder
        .withLockProvider(lockProvider)
        .withPoolSize(10)
        .withDefaultLockAtMostFor(Duration.ofMinutes(10))
        .build();
}

@Bean
public TaskScheduler taskScheduler(ScheduledExecutorService executorService, LockProvider lockProvider) {
    return SpringLockableTaskSchedulerFactory.newLockableTaskScheduler(executorService, lockProvider, Duration.of(10, MINUTES));
}

@SchedulerLock注解

  • name:用来标注一个定时服务的名字,被用于写入数据库作为区分不同服务的标识,如果有多个同名定时任务则同一时间点只有一个执行成功
  • lockAtMostFor:成功执行任务的节点所能拥有独占锁的最长时间,单位是毫秒ms
  • lockAtMostForString:成功执行任务的节点所能拥有的独占锁的最长时间的字符串表达,例如“PT14M”表示为14分钟
  • lockAtLeastFor:成功执行任务的节点所能拥有独占所的最短时间,单位是毫秒ms
  • lockAtLeastForString:成功执行任务的节点所能拥有的独占锁的最短时间的字符串表达,例如“PT14M”表示为14分钟

配置锁

Mongo

<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-provider-mongo</artifactId>
    <version>0.18.2</version>
</dependency>
@Bean
public LockProvider lockProvider(MongoClient mongo) {
    return new MongoLockProvider(mongo, "databaseName");
}

JdbcTemplate

CREATE TABLE shedlock(
  name VARCHAR(64), 
  lock_until TIMESTAMP(3) NULL, 
  locked_at TIMESTAMP(3) NULL, 
  locked_by  VARCHAR(255), 
  PRIMARY KEY (name)
)
<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-provider-jdbc-template</artifactId>
    <version>0.18.2</version>
</dependency>
@Bean
public LockProvider lockProvider(DataSource dataSource) {
    return new JdbcTemplateLockProvider(dataSource);
}

ZooKeeper 

<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-provider-zookeeper-curator</artifactId>
    <version>0.18.2</version>
</dependency>
@Bean
public LockProvider lockProvider(org.apache.curator.framework.CuratorFramework client) {
    return new ZookeeperCuratorLockProvider(client);
}

Redis

<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-provider-redis-spring</artifactId>
    <version>0.18.2</version>
</dependency>
@Bean
public LockProvider lockProvider(JedisPool jedisPool) {
    return new RedisLockProvider(connectionFactory, ENV);
}

Redis (using Jedis)

<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-provider-redis-jedis</artifactId>
    <version>0.18.0</version>
</dependency>
@Bean
public LockProvider lockProvider(JedisPool jedisPool) {
    return new JedisLockProvider(jedisPool, ENV);
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值