前言
本文主要对 redis 的分布式锁的原理及实现进行深入讲解。
以后,再针对 redis 分布式锁相关的问题都有据可查。
一、背景
说说我们为什么需要分布式锁?
当多个线程同时操作同个资源的时候,我们通常会使用例如 synchronized 来保证同一时刻只能有一个线程获取到对象锁进而处理资源。而在分布式条件下,各个服务独立部署,此时锁服务的对象就变为当前应用服务,即其他服务仍然可以执行这块代码,导致服务出现问题,那么如果我们想让多个服务独立部署时,也能控制资源的单独执行,那么就需要引入分布式锁来解决这种场景。
什么是分布式锁?
分布式锁。就是控制分布式系统中不同进程共同访问同一共享资源的一种锁的实现。
分布式锁,可以理解为“总部“ 的概念。
总部来控制锁的占有和通知其他服务等待。各个独立的部署都从总部这里获取锁的消息,从而避免了各地为政的可能。分布式锁就是这种思想。
我们可以使用一个第三方组件(例如redis、zookeeper、数据库)进行全局锁的监控,控制锁的持有和释放。
二、分布式锁原理及使用
setnx 是[set if not exists] 的简写。
将 key 的值设为 value,当且仅当 key 不存在,若给定的 key 已经存在,则 setnx 不做任何动作。
接下来,我们使用这个命令来看下分布式锁使用的简单案例,了解其内在原理。
2.1 分布式锁演进:阶段1
代码demo 如下:
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111");
if(lock){
// 加锁成功
Map<String, List<Catelog2VO>> stringListMap = getStringListMap();
redisTemplate.delete("lock");// 删除锁
return stringListMap;
}else{
// 加锁失败: 重试 (自旋锁)
return getCatalogJsonFromRedis();
}
复制代码
问题:
这是最原始的锁使用问题,但这里明显有一个问题,如果锁占用后在执行业务的过程中,程序宕机,此时这个锁就会永远在redis中存在。
解决办法:
- 设置锁的过期时间,即使没有删除,会自动删除。
2.2 分布式锁演进:阶段2
代码 demo 如下:
Boolean lock = redisTemplate.opsForValue().setIfAbsent("