需求
当我们项目在服务器上部署了多个节点时我们期望只能有一个节点开跑
解决方案
目前有很多的方案,比如用xxljob
等定时任务框架,但如果是小项目,也不想搭那么多服务,毕竟服务多维护成本也高,应该怎么弄呢?
以下方案基于springboot+redis
1. 引入redisson
xml
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.17.5</version>
</dependency>
2. 写RedissonConfig bean
java
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
@Value("${spring.redis.password}")
private String redisPassword;
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer().setAddress(String.format("redis://%s:%d", redisHost, redisPort)).setPassword(redisPassword);
return Redisson.create(config);
}
}
3. 启动定时任务时增加获取锁逻辑
java
RedissonClient redissonCache = SpringUtils.getBean(RedissonClient.class);
String key = "jobName: " + job.getJobName();
//定时任务执行周期较短,为防止数据重复修改,加入锁
RLock lock = redissonCache.getLock(key);
try {
// 执行任务
log.info("任务准备执行,尝试获取锁 - 名称:{} 方法:{}", job.getJobName(), job.getMethodName());
// 尝试获取锁并设定锁的过期时间
boolean acquired = false;
try {
acquired = lock.tryLock(0, LOCK_KEY_TIME, TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.info("tryLock异常", e);
}
if (acquired) {
log.info("任务获取锁成功,开始执行 - 名称:{} 方法:{}", job.getJobName(), job.getMethodName());
// todo 此处写定时任务执行方法
}
}catch (Exception e) {
log.info("任务执行失败 - 名称:{} 方法:{}", job.getJobName(), job.getMethodName());
log.error("任务执行异常 - :", e);
} finally {
// 释放锁
try {
log.info("准备释放锁 - 名称:{} 方法:{}", job.getJobName(), job.getMethodName());
lock.unlock();
log.info("释放锁成功 - 名称:{} 方法:{}", job.getJobName(), job.getMethodName());
}catch (Exception e){
}
}