分布式Redis的分布式锁 Redlock

连接html

Distributed locks with Redisgit

引言

以前本身在用redis来实现分布式锁的时候都是基于单个Redis实例,也就是说Redis自己是有单点故障的,Redis的官方文档介绍了一种"自认为"合理的算法,Redlock来实现分布式Redis下的分布式锁。github

Martin Kleppmann写了一篇文章分析Redlock。而后redis的做者写了一篇反驳的文章这里。加油。redis

Redlock实现库

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

单点Redis锁

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

获取锁

SET resource_name my_random_value NX PX 30000

客户端A在Redis上设置一个特定的键值对,同时给一个超时时间(避免死锁)。其余客户端在访问的时候先看看这个key是否已经存在,而且值等于my_random_value。若是已存在就等待,不然就获取成功,执行业务代码。resource_namemy_random_value是全部客户端都知道而且共享的。服务器

释放锁

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

对比key获取到的对应的value是否相等,若是相等,就删除(释放),不然就返回失败。架构

以前也写过一篇文章dom

单点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,毫秒数。
  2. 使用相同的key和value依次向5个实例获取锁。客户端在获取锁的时候自身设置一个远小于业务锁须要的持续时间的超时时间。举个例子,假设锁须要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就好。

相关文章
相关标签/搜索