【redis】redis加锁的几种思路及试验

基于redis的分布式锁,其根基就在于redis的锁。基于文章[1],本文进行了命令的测试。
下面几种方法中,获取锁、释放锁等操作,凡是涉及到两条及以上的命令的,都需要确保原子性,也就是说在项目里的方法上要加事务。

1,基于incr

思路简述
这种加锁的思路是, key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作进行加一。
然后其它用户在执行 INCR 操作进行加一时,如果返回的数大于 1 ,说明这个锁正在被使用当中。[1]

测试
1、 客户端A请求服务器获取key的值为1表示获取了锁。注意要加过期时间。

//初始化
127.0.0.1:6379> set 'key 1' 0
OK
//获取锁
127.0.0.1:6379> incr 'key 1'
(integer) 1
127.0.0.1:6379> expire 'key 1' 3000
(integer) 1

2、 客户端B也去请求服务器获取key的值为2表示获取锁失败。获取锁失败则不加过期时间

127.0.0.1:6379> incr 'key 1'
(integer) 2

3、 客户端A执行代码完成,删除锁

127.0.0.1:6379> set 'key 1' 0
OK

4、 客户端B在等待一段时间后在去请求的时候获取key的值为1表示获取锁成功

127.0.0.1:6379> incr 'key 1'
(integer) 1
127.0.0.1:6379> expire 'key 1' 3000
(integer) 1

5、 客户端B执行代码完成,删除锁

127.0.0.1:6379> set 'key 1' 0
OK

`

2,SETNX

思路简述
这种加锁的思路是,如果 key 不存在,将 key 设置为 value,并返回1.
如果 key 已存在,则 SETNX 不做任何动作,并返回0.

测试
1、 客户端A请求服务器设置key的值,如果设置成功就表示加锁成功。注意要加过期时间。

127.0.0.1:6379> setnx 'key 2' 'value 2'
(integer) 1
127.0.0.1:6379> expire 'key 2' 3000
(integer) 1

2、 客户端B也去请求服务器设置key的值,如果返回失败,那么就代表加锁失败。获取锁失败则不加过期时间

127.0.0.1:6379> setnx 'key 2' 'value 3'
(integer) 0

3、 客户端A执行代码完成,删除锁

127.0.0.1:6379> del 'key 2'
(integer) 1

4、 客户端B在等待一段时间后在去请求设置key的值,设置成功

127.0.0.1:6379> setnx 'key 2' 'value 3'
(integer) 1
127.0.0.1:6379> expire 'key 2' 3000
(integer) 1

5、 客户端B执行代码完成,删除锁

127.0.0.1:6379> del 'key 2'
(integer) 1

3,GET SET

思路简述
上面两种方法都有一个问题,会发现,都需要设置 key 过期。那么为什么要设置key过期呢?如果请求执行因为某些原因意外退出了,导致创建了锁但是没有删除锁,那么这个锁将一直存在,以至于以后缓存再也得不到更新。于是乎我们需要给锁加一个过期时间以防不测。
但是借助 Expire 来设置就不是原子性操作了。所以还可以通过事务来确保原子性,但是还是有些问题,所以官方就引用了另外一个,使用 SET 命令本身已经从版本 2.6.12 开始包含了设置过期时间的功能。

测试
1、 客户端A请求服务器设置key的值,如果设置成功就表示加锁成功

//get值为空,表示锁未被获取
127.0.0.1:6379> get 'key 3'
(nil)
//EX表示过期时间单位为s,PX为ms
127.0.0.1:6379> set 'key 3' 'value 3' EX 15
OK

2、 客户端B也去获取服务器设置key的值,如果返回不为空,那么就代表获取锁失败

127.0.0.1:6379> get 'key 3'
"value 3"

3、 客户端A执行代码完成,删除锁

127.0.0.1:6379> del 'key 3'
(integer) 1

4、 客户端B在等待一段时间后在去请求设置key的值,设置成功

127.0.0.1:6379> get 'key 3'
(nil)
127.0.0.1:6379> set 'key 3' 'value 4' EX 15
OK

5、 客户端B执行代码完成,删除锁

127.0.0.1:6379> del 'key 3'
(integer) 1

参考文献
[1],高并发下的redis加锁的几种实现方式

你可能感兴趣的