Redis笔记-Redisson实现分布式锁

Redis在项目中除了用作session共享、缓存静态数据等用途外,还有一个比较常见的用途就是实现分布式锁,一般在java中,我们除了自己代码实现,还可以用Redisson来实现分布式锁,也是官方比较推荐的一种方案。实现分布式锁需要考虑以下几个问题:

1、分布式锁实际就是实现互斥

2、需要防止死锁,需要有对应的方案来防止死锁

3、如何标记加锁和释放锁的是同一个进程

4、如果在指定过期时间内程序未处理完,如何实现续期

Redisson基本实现了以上要求。互斥主要利用redis存储key的唯一性来实现,防止死锁只需要给定指定的过期时间即可,加锁和释放锁通过在程序中传入线程ID来标记是否同一进程,并且如果程序未显示指定过期时间,Redisson提供了默认过期时间+WatchDog机制,实现续期功能。这里通过Redisson3.5.4版本,来分析具体实现,核心代码在RedissonLock类:

 

 加锁的源码如上,如果直接能上锁,则返回,如果so被占用,则尝试重复获取锁。接下来看看具体的加锁逻辑:

 

看看具体的加锁过程:

 

加锁过程通过一段LUA脚本实现,其中参数含义如下:

KEYS[1]表示的是加锁的key

ARGV[1]表示的是锁的过期事件

ARGV[2]表示的是加锁的客户端ID

所以,当前锁没被占用的情况,执行流程是,判断当前key是否存在,不存在,则set当前key,value是程序线程ID经过处理后的一个标识客户端的ID,1可以理解为锁被占用的次数,并返回空。此时,如果另外一个进程尝试对这个key加锁,则不满足条件,同时判断书否满足第二个条件,也不满足,则放回锁被占用的时间信息。

如果当前锁被占用,第二个进程对这个key加锁,分两种情况,一是与被占用的锁不是同一个进程,则直接返回;二是尝试加锁的是和之前已经占用锁的是同一个进程,则会进入第二个判断语句,执行流程为对当前占用锁的 占用次数加1,这里其实就是锁可重入的机制,然后更新过期时间,并返回空。

 

WatchDog实现续期的逻辑如下:

 

 

Redisson实现分布式锁需要注意的问题,如果Redis是Master-Slave模式,可能会出现不同客户端同时获取锁的情况,主要场景是在一个客户端获取了锁,并尝试同步信息到Slave时,这个时候Master如果出现异常挂机,此时其他Salve就会升级为Master,然后其他客户端尝试对相同key加锁,在在新的Master上再次上锁,从而出现同时加锁的情况。

 

posted on 2021-08-29 23:36  funnyboy0128  阅读(390)  评论(0编辑  收藏  举报

导航