Redis分布式锁
前言
之前写了关于Redis中的缓存击穿,缓存雪崩,缓存穿透的文章中,提到了分布式的情况下如果需要加锁就需要使用分布式锁,于是填坑来了😅
什么是分布式锁
对于一些数据安全要求较高的应用,我们在进行数据访问处理的时候,需要让线程依次排起队处理,不然就会出现数据的错误,如果是单机应用我们可以使用Snchronized和ReentrantLock来实现并发操作,但是在分布式应用不可行,因为分布式应用是将应用散列分布在不同机器上面的,不是在同一个JVM中,所以就会导致原有的锁策略失效,于是就需要引用一个全局的,大叫都可以使用的锁,这个就是分布式锁
分布式锁的实现方式
对于实现一个分布式锁,常见的方式有三种:
- 基于数据库的分布式锁
- 基于缓存的分布式锁
- 基于
Zookeeper的分布式锁
基于数据库的分布式锁实现
这个很好理解,核心思想就是在数据库中新建一张表用来存储锁信息,当我们需要获取锁的时候,就向表中插入(或者更新)数据,这个时候如果其他线程去尝试获取锁的时候,就会去数据库中操作数据,当它发现操作不成功的时候就清楚当前资在被其他线程使用,这个操作可以是插入或者更新,这就需要我们在建表的时候加上唯一索引,当插入或者更新的操作返回值为0时就说明操作失败了,并且需要对操作加上事务保证操作的原子性
**缺点:**因为是基于数据库的所以对于数据库的高可用和性能会有要求,如果没有进行限流处理,在遭到缓存雪崩时,这个时候锁就会迟迟获取不到,并且数据库锁不具备可重入性,因为数据被操作一次后,记录会一直存在,直到锁被释放之前,任何线程都不可以再次获取
基于Redis的分布式锁
Redis的分布式锁是主流的方案,因为Redis的性能较高,所以在高并发分布式的场景下能够更快的处理锁数据,使用RedisTemplate来实现一个简单的分布式锁,在Redis中的缓存击穿,缓存雪崩,缓存穿透已经操作过了,这次我们需要使用的就是Redission来实现分布式锁
- 配置类
@Configuration
public class RedissonConfig {
@Value("${redis.host}")
private String redisHost;
@Value("${redis.password}")
private String password;
@Value("${redis.host}")
private String host;
@Value("${redis.port}")
private String port;
@Bean
public RedissonClient getRedisson() {
Config config = new Config();
config.useSingleServer().
setAddress("redis://" + host + ":" + port).
setPassword(password);
return Redisson.create(config);
}
}
- 业务使用
@Resource
private RedissonClient redissonClient;
public void lock(){
RLock rLock = redissonClient.getLock("lockName");
try {
boolean flag = rLock.tryLock(100, TimeUnit.SECONDS);
if (flag){
//TODO 获取锁,处理业务
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
//释放锁
rLock.unlock();
}
}
当然,我们还可以自己将redissonClient的方法再次封装
**缺点:**当然Redis分布式锁也不是完美的,如果在Redis主从复制的时候,master宕机之后,主备切换,slave变为master,其他的线程此时对同一个资源加锁,因为数据没有同步完成,其他的线程也是能够加锁成功
基于Zookeeper的分布式锁
ZooKeeper是一个为分布式应用提供一致性服务的开源组件,它内部是一个分层的文件系统目录树结构,规定同一个目录下只能有一个唯一文件名。基于ZooKeeper实现分布式锁的步骤如下:
- 创建一个目录lock;
- 线程A想获取锁就在lock目录下创建临时顺序节点;
- 获取lock目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁;
- 线程B获取所有节点,判断自己不是最小节点,设置监听比自己次小的节点;
- 线程A处理完,删除自己的节点,线程B监听到变更事件,判断自己是不是最小的节点,如果是则获得锁。
**缺点:**需要频繁删除和创建节点,性能比Redis稍差
总结
对于开发人员来说,使用Redisson感觉是比较简单的方式,但是每种方式都有优缺点,总之选择符合实际业务需求的就可以了,这次只了解了基础的使用,后面再来讲理论原理😂
