redis分布式锁安全性探讨(一):基于单个redis节点的分布式锁

一、基于单个redis节点的分布式锁
步骤1: 向redis发送命令,获取锁
SET resource_name my_random_value NX PX 30000

解释说明:
my_random_value : 客户端生成的 随机 ,要保证在足够长的时间内所有客户端生成的随机值是 唯一的
NX: 当key为resource_name的值不存在时,才能被成功插入( IF NOT EXISTS )。这一点保证了只有一个客户端能设置成功,换句话说只有一个客户端能拿到锁。
PX: 表示过期时间为30s

步骤2: 获取锁成功后才能访问共享资源
步骤3:释放锁
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end
备注:KEYS[1]为resource_name,ARGV[1]:为my_random_value

二、重点问题分析
1、必须设置过期时间: 防止客户端崩溃或者跟redis通信中断时,导致无法释放锁的问题出现
2、要保持操作的原子性
网络上出现很多介绍redis锁是用以下方式:
1、SETNX resource_name my_random_value
2、EXPIRE resource_name 30

虽然这两个命令跟前面set nx px的效果一样,但是它将 设置key+设置过期时间的操作分开 ,不能保证获取锁操作的原子性。
  • 当客户端执行完setnx后崩溃,那么它就没有机会释放锁
  • 当客户端执行完setnx成功且expire了过期时间,但可能在它访问共享资源时锁过期了,这时可能已经有另外一个客户端也在访问同一个共享资源。

3、客户端生成的 my_random_value随机值是唯一的, 这样才能保证在释放锁时删除的key是自己生成的那一个(不会出现误删)
假如获取锁时SET的不是一个随机字符串,而是一个固定值,那么可能会发生下面的执行序列:

  1. 客户端1获取锁成功。
  2. 客户端1在某个操作上阻塞了很长时间。
  3. 过期时间到了,锁自动释放了。
  4. 客户端2获取到了对应同一个资源的锁。
  5. 客户端1从阻塞中恢复过来,释放掉了客户端2持有的锁。

之后,客户端2在访问共享资源的时候,就没有锁为它提供保护了。

4、释放锁的操作必须使用Lua脚本来实现(为了保证删除操作的原子性)
释放锁其实包含三步操作: 'GET'、判断和'DEL' ,用Lua脚本来实现能保证这三步的原子性。否则,如果把这三步操作放到客户端逻辑中去执行的话,就有可能发生与前面第三个问题类似的执行序列:

  1. 客户端1获取锁成功。
  2. 客户端1访问共享资源。
  3. 客户端1为了释放锁,先执行'GET'操作获取随机字符串的值。
  4. 客户端1判断随机字符串的值,与预期的值相等。
  5. 客户端1由于某个原因阻塞住了很长时间。
  6. 过期时间到了,锁自动释放了。
  7. 客户端2获取到了对应同一个资源的锁。
  8. 客户端1从阻塞中恢复过来,执行DEL操纵,释放掉了客户端2持有的锁。

实际上,在上述第三个问题和第四个问题的分析中,如果不是客户端阻塞住了,而是出现了 大的网络延迟 ,也有可能导致类似的执行序列发生。

三、基于单redis节点无法解决的问题
#若redis没有配置高可用,当redis唯一节点宕机后,那么所有客户端就无法获得锁了,锁机制失效。因此为了提高redis的高可用,设置了主从节点。
也因此产生了另外一个新问题。
#问题描述: 我们可以给这个Redis节点挂一个Slave,当Master节点不可用的时候,系统自动切到Slave上(failover)。但 由于Redis的主从复制(replication)是 异步的 (即主从复制存在一定的时间差,很容易在这个时间差里打擦边球) ,这可能导致在failover过程中丧失锁的安全性。
考虑下面的执行序列:

  1. 客户端1从Master获取了锁。
  2. Master宕机了,存储锁的key还没有来得及同步到Slave上。
  3. Slave升级为Master。
  4. 客户端2从新的Master获取到了对应同一个资源的锁。

于是,客户端1和客户端2同时持有了同一个资源的锁。锁的安全性被打破。针对这个问题,antirez设计了Redlock算法

其它疑问
1、px time设置成多少合适呢? 设置少了可能会导致客户端访问共享资源之前[锁过期],设置太长了呢,可能会导致客户端释放锁失败时,导致其它客户端的长时间等待。

2、可能因为长时间的阻塞(网络延迟),导致客户端获得的锁过期,而使得共享资源失去了保护,那么有没有什么方案来解决这些存在的疑问呢?


请看下一篇文章[ redis分布式锁真的安全吗?(二): 分布式锁Redlock]









猜你喜欢

转载自blog.csdn.net/hh1sdfsf56456/article/details/79474409