Redis分布式锁(二)基于Redis的分布式锁

发布时间:2024年01月08日

一、redis锁

1、思路

  • 利用set nx ex获取锁,并设置过期时间,保存线程标识
  • 释放锁时先判断线程标识是否与自己一致,一致则删除

2、特性

  • 利用set nx满足互斥性
  • 利用set ex保证故障时锁依然能释放,避免死锁,提高安全性
  • 利用Redis集群保证高可用和高并发特性

3、redis实现加锁的几种命令:redis能用的的加锁命令分表是INCR、SETNX、SET

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

1、 客户端A请求服务器获取key的值为1表示获取了锁 
2、 客户端B也去请求服务器获取key的值为2表示获取锁失败
3、 客户端A执行代码完成,删除锁
4、 客户端B在等待一段时间后在去请求的时候获取key的值为1表示获取锁成功
5、 客户端B执行代码完成,删除锁

$redis->incr($key);
$redis->expire($key, $ttl); //设置生成时间为1秒

?(2)SETNX:这种加锁的思路是,如果 key 不存在,将 key 设置为 value;如果 key 已存在,则 SETNX 不做任何动作

 1、 客户端A请求服务器设置key的值,如果设置成功就表示加锁成功
 2、 客户端B也去请求服务器设置key的值,如果返回失败,那么就代表加锁失败
 3、 客户端A执行代码完成,删除锁
 4、 客户端B在等待一段时间后在去请求设置key的值,设置成功
 5、 客户端B执行代码完成,删除锁   


$redis->setNX($key, $value);
$redis->expire($key, $ttl);

(3)SET:上面两种方法都需要设置 key 过期,这是防止意外情况锁无法释放。但是借助 Expire 来设置就不是原子性操作了,所以官方就引用了另外一个,使用 SET 命令本身已经从版本 2.6.12 开始包含了设置过期时间的功能。

1、 客户端A请求服务器设置key的值,如果设置成功就表示加锁成功
2、 客户端B也去请求服务器设置key的值,如果返回失败,那么就代表加锁失败
3、 客户端A执行代码完成,删除锁
4、 客户端B在等待一段时间后在去请求设置key的值,设置成功
5、 客户端B执行代码完成,删除锁


$redis->set($key, $value, array('nx', 'ex' => $ttl)); //ex表示秒

redis自身也存在单节点和redis分布式,下面看下redis单节点和分布式模式下锁的应用:

二、redis单节点锁

三、redis分布式锁:

1、介绍:RedLock是Redis之父Salvatore Sanfilippo提出来的基于多个Redis实例的分布式锁的实现方案。其核心思想就在于使用多个Redis冗余实例来避免单Redis实例的不可靠性。

2、RedLock采用的就是依据法团准则的方案:

400

3、redis分布式锁的过程分析:redis分布式锁就几个方法:

① setnx(key,value) 返回boolean 1为获取锁 0为没获取锁

② expire() 设置锁的有效时间

③ getSet(key,value) 获取锁当前key对应的锁的有效时间

④ deleteKey() 删除锁

(1)setnx(lockkey, 当前时间+过期超时时间),如果返回 1,则获取锁成功;如果返回 0 则没有获取到锁,转向 2;

(2)get(lockkey) 获取值 oldExpireTime ,并将这个 value 值与当前的系统时间进行比较,如果小于当前系统时间,则认为这个锁已经超时,可以允许别的请求重新获取,转向 3;

(3)计算 newExpireTime = 当前时间+过期超时时间,然后 getset(lockkey, newExpireTime) 会返回当前 lockkey 的值currentExpireTime。判断 currentExpireTime 与 oldExpireTime 是否相等,如果相等,说明当前 getset 设置成功,获取到了锁。如果不相等,说明这个锁又被别的请求获取走了,那么当前请求可以直接返回失败,或者继续重试。
(4)在获取到锁之后,当前线程可以开始自己的业务处理,当处理完毕后,比较自己的处理时间和对于锁设置的超时时间,如果小于锁设置的超时时间,则直接执行 delete 释放锁;如果大于锁设置的超时时间,则不需要再锁进行处理。

4、实现分布式锁:主要就两个方法:

(1)getlock() 获取锁方法

(2)releaselock()释放锁方法

文章来源:https://blog.csdn.net/w_t_y_y/article/details/135342764
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。