基于 Redis 的分布式锁 Redlock

这篇文章主要是对 Redis 官方网站刊登的 Distributed locks with Redis 部份内容的总结和翻译。程序员

什么是 RedLock

Redis 官方站这篇文章提出了一种权威的基于 Redis 实现分布式锁的方式名叫 Redlock,此种方式比原先的单节点的方法更安全。它能够保证如下特性:redis

  1. 安全特性:互斥访问,即永远只有一个 client 能拿到锁
  2. 避免死锁:最终 client 均可能拿到锁,不会出现死锁的状况,即便本来锁住某资源的 client crash 了或者出现了网络分区
  3. 容错性:只要大部分 Redis 节点存活就能够正常提供服务

怎么在单节点上实现分布式锁

SET resource_name my_random_value NX PX 30000算法

主要依靠上述命令,该命令仅当 Key 不存在时(NX保证)set 值,而且设置过时时间 3000msPX保证),值 my_random_value 必须是全部 client 和全部锁请求发生期间惟一的,释放锁的逻辑是:安全

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

上述实现能够避免释放另外一个 client 建立的锁,若是只有 del 命令的话,那么若是 client1 拿到 lock1 以后由于某些操做阻塞了很长时间,此时 Redislock1 已通过期了而且已经被从新分配给了 client2,那么 client1 此时再去释放这把锁就会形成 client2 本来获取到的锁被 client1 无端释放了,但如今为每一个 client 分配一个 uniquestring 值能够避免这个问题。至于如何去生成这个 unique string,方法不少随意选择一种就好了。网络

Redlock 算法

算法很易懂,起 5master 节点,分布在不一样的机房尽可能保证可用性。为了得到锁,client 会进行以下操做:dom

  1. 获得当前的时间,微秒(ms)单位
  2. 尝试顺序地在 5 个实例上申请锁,固然须要使用相同的 keyrandom value,这里一个 client 须要合理设置与 master 节点沟通的 timeout 大小,避免长时间和一个 fail 了的节点浪费时间
  3. client 在大于等于 3master 上成功申请到锁的时候,且它会计算申请锁消耗了多少时间,这部分消耗的时间采用得到锁的当下时间减去第一步得到的时间戳获得,若是锁的持续时长(lock validity time)比流逝的时间多的话,那么锁就真正获取到了。
  4. 若是锁申请到了,那么锁真正的 lock validity time 应该是 origin(lock validity time) - 申请锁期间流逝的时间
  5. 若是 client 申请锁失败了,那么它就会在少部分申请成功锁的 master 节点上执行释放锁的操做,重置状态

失败重试

若是一个 client 申请锁失败了,那么它须要稍等一会在重试避免多个 client 同时申请锁的状况,最好的状况是一个 client 须要几乎同时向 5master 发起锁申请。另外就是若是 client 申请锁失败了它须要尽快在它曾经申请到锁的 master 上执行 unlock 操做,便于其余 client 得到这把锁,避免这些锁过时形成的时间浪费,固然若是这时候网络分区使得 client 没法联系上这些 master,那么这种浪费就是不得不付出的代价了。分布式

放锁

放锁操做很简单,就是依次释放全部节点上的锁就好了性能

性能、崩溃恢复和 fsync

若是咱们的节点没有持久化机制,client5master 中的 3 个处得到了锁,而后其中一个重启了,这时注意:网站

整个环境中又出现了 3 个 master 可供另外一个 client 申请同一把锁!lua

这违反了互斥性。

若是咱们开启了 AOF 持久化那么状况会稍微好转一些,由于 Redis 的过时机制是语义层面实现的,因此在 server 挂了的时候时间依旧在流逝,重启以后锁状态不会受到污染。可是考虑断电以后呢,AOF 部分命令没来得及刷回磁盘直接丢失了,除非咱们配置刷回策略为 fsnyc = always,但这会损伤性能。解决这个问题的方法是,当一个节点重启以后,咱们规定在max TTL 期间它是不可用的,这样它就不会干扰本来已经申请到的锁,等到它 crash 前的那部分锁都过时了,环境不存在历史锁了,那么再把这个节点加进来正常工做。

写在最后

这是一个不定时更新的、披着程序员外衣的文青小号。既分享极客技术,也记录人间烟火。

相关文章
相关标签/搜索