如何正确实施redis分布式锁
点关注不迷路,欢迎再访!
精简博客内容,尽量已行业术语来分享。
努力做到对每一位认可自己的读者负责。
帮助别人的同时更是丰富自己的良机。
应用场景
集群下部署多个应用,定时任务就会出现重复执行的问题,为了避免资源浪费和脏数据的问题出现,借助redis分布式锁解决
redis实现分布式锁用到的几个命令:setnx、get、getset、expire
redis分布式锁实现
基于Redis实现的分布式锁其实很简单,底层就是使用redis的setnx指令来实现的加锁,我们来看看官方对setnx的定义:
SETNX key value
将 key 的值设为 value ,当且仅当 key 不存在。
若给定的 key 已经存在,则 SETNX 不做任何动作。
死锁问题
既然setnx这么强大,还需考虑一些极端场景。
比如如果一台机器在运行状态中突然宕机没有设置锁的过期时间无法自动释放锁,那么另一台应用会一直认为有机器占用着分布式锁执行任务,此时实际是没有执行的,而导致死锁问题。
死锁问题解决方法
在这里我们给分布式锁设置一个过期时间,能够在开始执行任务后自动释放分布式锁
具体实现代码
/**
* @author ex_sunqi
* 分布式锁控制schedule
*/
@Component
@Configuration
@EnableScheduling
public class fileScheduleTask {
private final Log logger = LogFactory.getLog(getClass());
private static final String LOCK = "job-lock";
private static final String KEY = "fileTasklock";
//单位为秒 默认10分钟
private long redis_time = 60 * 10;
@Scheduled(cron = "0 0/30 * * * ?")
public void fileConvertJob() {
boolean lock = false;
try {
lock = redisTemplate.opsForValue().setIfAbsent(KEY, LOCK);
logger.info("是否获取到锁:" + lock);
if (lock) {
//设置分布式锁的过期时间
redisTemplate.expire(KEY, redis_time , TimeUnit.SECONDS);
//代码核心逻辑
} else {
logger.info("没有获取到锁,不执行任务!");
return;
}
} finally {
if (lock) {
redisTemplate.delete(KEY);
logger.info("任务结束,释放锁!");
} else {
logger.info("没有获取到锁,无需释放锁!");
}
}
}
}