Redis中分布式锁Redlock的示例分析

编辑: admin 分类: mysql 发布时间: 2023-06-10 来源:互联网

Redlock实现库

  • Java Redisson Star 9458

  • C# RedLock.net Star 259

  • Go redsync.go Star 249

虽然后面的算法是一样的,不过这个点赞数确实服。

单点Redis锁

先简单回顾一下单点的Redis锁是怎么实现的。

获取锁

SET resource_name my_random_value NX PX 30000
登录后复制

客户端A使用Redis设置一个键值对,并指定超时时间以避免死锁。在其他客户端访问时,它们首先会检查该键是否已存在,且其值是否为“my_random_value”。如果已存在就等待,否则就获取成功,执行业务代码。所有客户端共享且已知的对象包括resource_name和my_random_value。

释放锁

if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1])else return 0end
登录后复制

对比key获取到的对应的value是否相等,如果相等,就删除(释放),否则就返回失败。

单点Redis锁的缺陷

只有一个Redis实例时,出现故障会导致所有依赖它的服务都崩溃,这个缺陷异常明显。显然不太适合大型的应用。

简单的Redis主从架构碰到的问题

为了避免单点故障,我们给Redis做一个Master/Slave的主从架构,一个Master,一台Slave。下面就会碰到这么一个问题。下面是使用场景。

  1. 客户端A在Master上获取到一个锁。

  2. Master把这个数据同步到Slave的时候挂了(因为Master和Slave之间同步是异步的)。

  3. Slave变成了Master。

  4. 客户端B通过相同的key,和value获取到锁。分布式锁失效

Redlock算法

假设我们有N(假设5)个Redis master实例,所有节点相互独立,并且业务系统也是单纯的调用,并没有什么其他的类似消息重发之类的辅助系统。下面来模拟一下算法:

1.客户端获取服务器当前的的时间t0,毫秒数。

在5个实例中使用相同的key和value获取锁。在获取业务锁时,客户端会设置一个持续时间远小于业务锁需要的超时时间。举个例子,假设锁需要10秒钟,可以将超时时间设置在5-50毫秒之间。重写后的句子: 为了避免客户端在尝试获取锁时出现Redis已经故障的情况,需要采取措施。超时了之后就直接跳到下一个节点。

3.客户端通过当前时间(t1)减去t0,计算获取锁所消耗的时间t2(=t1-t0)。只有t2小于锁的业务有效时间(也就是第二步的10秒),并且,客户端在至少3(5/2+1)台上获取到锁我们才认为锁获取成功。

4.如果锁已经获取,那么锁的业务有效时间为10s-t2。

5.如果客户端没有获取到锁,可能是没有在大于等于N/2+1个实例上获取锁,也可能是有效时间(10s-t2)为负数,我们就尝试去释放锁,即使是并没有在那个节点上获取到。

锁的释放

释放比较简单,直接删除所有实例上对应的key就好。

【文章转自高防服务器 http://www.558idc.com 复制请保留原URL】