Redis 4.0.10 文档(分布式锁)

Redis分布式锁

在许多环境中,分布式锁是一种很是有用的原语,其中不一样的进程必须以互斥的方式与共享资源一块儿运行。php

有许多库和博客文章描述了如何使用Redis实现DLM(分布式锁管理器),可是每一个库都使用不一样的方法,并且许多库使用的是一种简单的方法,与稍微复杂的设计相比,能够得到较低的保障。node

此页面试图提供一种更典型的算法来使用Redis实现分布式锁,咱们提出了一种称为Redlock的算法,它实现了一种咱们认为比vanilla单实例方法更安全的DLM,咱们但愿社区将对其进行分析,提供反馈,并将其做为实施或更复杂或替代设计的起点。git

实现

在描述算法以前,这里有几个已经可用的实现的连接,可用于参考。github

安全性和活性保障

咱们将仅使用三个属性对咱们的设计进行建模,从咱们的角度来看,这些属性是以有效方式使用分布式锁所需的最低保障。面试

  1. 安全属性:相互排斥。在任何给定时刻,只有一个客户端能够持有锁。
  2. 活力属性A:无死锁。最终即便锁定资源的客户端崩溃或被分区,也始终能够获取锁定。
  3. 活力属性B:容错。只要大多数Redis节点启动,客户端就可以获取和释放锁。

为何基于故障转移的实现还不够

为了理解咱们想要改进的内容,让咱们分析大多数基于Redis的分布式锁库的当前状态。redis

使用Redis锁定资源的最简单方法是在实例中建立密钥,密钥一般使用Redis过时功能在有限的生存时间内建立,所以最终它将被释放(咱们列表中的属性2),当客户端须要释放资源时,它会删除密钥。算法

从表面上看,这颇有效,但存在一个问题:这是咱们架构中的单点故障,若是Redis主机出现故障会怎样?好吧,让咱们添加一个从机!若是主服务器不可用,则使用它,遗憾的是,这不可行。经过这样作,咱们没法实现互斥的安全属性,由于Redis主从复制是异步的。安全

这种模式存在明显的竞争条件:服务器

  1. 客户端A获取主服务器中的锁
  2. 在对密钥的写入被传输到从服务器以前,主服务器崩溃了
  3. 从机被提高为主机
  4. 客户端B得到与A已经持有锁的相同资源的锁。安全违反!

有时在特殊状况下,例如在故障期间,多个客户端能够同时保持锁定,这是彻底正常的,若是是这种状况,你可使用基于主从复制的解决方案,不然,咱们建议实施本文档中描述的解决方案。架构

使用单个实例正确实现

在尝试克服上述单实例设置的限制以前,让咱们看看在这个简单的例子中如何正确地作到这一点,由于在时常能够接收竞争条件的应用中,这其实是一个可行的解决方案,由于锁定到单个实例是咱们将用于此处描述的分布式算法的基础。

要得到锁,可采起的方法以下:

SET resource_name my_random_value NX PX 30000

该命令仅在密钥尚不存在时才设置密钥(NX选项),到期时间为30000毫秒(PX选项),键的值设置为“myrandomvalue”,此值必须在全部客户端和全部锁定请求中都是惟一的,基本上使用随机值以便以安全的方式释放锁,使用一个告诉Redis的脚本:只有当密钥存在而且密钥中存储的值正是我指望的那个时才删除密钥,这是经过如下Lua脚本完成的:

if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end
相关文章
相关标签/搜索