Redlock(redis 分布式锁)原理分析

Redlock:全名叫做 Redis Distributed Lock; 即使用 redis 实现的分布式锁;

使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击);

官网文档地址如下:https://redis.io/topics/distlock

这个锁的算法实现了多 redis 实例的情况,相对于单 redis 节点来说,优点在于 防止了 单节点故障造成整个服务停止运行的情况;并且在多节点中锁的设计,及多节点同时崩溃等各种意外情况有自己独特的设计方法;

此博客或者官方文档的相关概念:

  1. TTL:Time To Live; 只 redis key 的过期时间或有效生存时间

  2. clock drift: 时钟漂移;指两个电脑间时间流速基本相同的情况下,两个电脑(或两个进程间)时间的差值;如果电脑距离过远会造成时钟漂移值 过大

最低保证分布式锁的有效性及安全性的要求如下:

  1. 互斥;任何时刻只能有一个 client 获取锁

  2. 释放死锁;即使锁定资源的服务崩溃或者分区,仍然能释放锁

  3. 容错性;只要多数 redis 节点(一半以上)在使用,client 就可以获取和释放锁

网上讲的基于故障转移实现的 redis 主从无法真正实现 Redlock:

因为 redis 在进行主从复制时是异步完成的,比如在 clientA 获取锁后,主 redis 复制数据到从 redis 过程中崩溃了,导致没有复制到从 redis 中,然后从 redis 选举出一个升级为主 redis, 造成新的主 redis 没有 clientA 设置的锁,这是 clientB 尝试获取锁,并且能够成功获取锁,导致互斥失效;

思考题:这个失败的原因是因为从 redis 立刻升级为主 redis,如果能够过 TTL 时间再升级为主 redis(延迟升级)后,或者立刻升级为主 redis 但是过 TTL 的时间后再执行获取锁的任务,就能成功产生互斥效果;是不是这样就能实现基于 redis 主从的 Redlock;

redis 单实例中实现分布式锁的正确方式(原子性非常重要):

  1. 设置锁时,使用 set 命令,因为其包含了 setnx,expire 的功能,起到了原子操作的效果,给 key 设置随机值,并且只有在 key 不存在时才设置成功返回 True, 并且设置 key 的过期时间(最好用毫秒)
SET key_name my_random_value NX PX 30000                  # NX 表示if not exist 就设置并返回True,否则不设置并返回False   PX 表示过期时间用毫秒级, 30000 表示这些毫秒时间后此key过期
  1. 在获取锁后,并完成相关业务后,需要删除自己设置的锁(必须是只能删除自己设置的锁,不能删除他人设置的锁);

删除原因:保证服务器资源的高利用效率,不用等到锁自动过期才删除;

删除方法:最好使用 Lua 脚本删除(redis 保证执行此脚本时不执行其他操作,保证操作的原子性),代码如下;逻辑是 先获取 key,如果存在并且值是自己设置的就删除此 key; 否则就跳过;

if redis.call("get",KEYS[1]) == ARGV[1] thenreturn redis.call("del",KEYS[1])
elsereturn 0
end

python 代码如下:

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

算法流程图如下:

多节点 redis 实现的分布式锁算法 (RedLock): 有效防止单点故障

假设有 5 个完全独立的 redis 主服务器

  1. 获取当前时间戳

  2. client 尝试按照顺序使用相同的 key,value 获取所有 redis 服务的锁,在获取锁的过程中的获取时间比锁过期时间短很多,这是为了不要过长时间等待已经关闭的 redis 服务。并且试着获取下一个 redis 实例。

比如:TTL 为 5s, 设置获取锁最多用 1s,所以如果一秒内无法获取锁,就放弃获取这个锁,从而尝试获取下个锁

  1. client 通过获取所有能获取的锁后的时间减去第一步的时间,这个时间差要小于 TTL 时间并且至少有 3 个 redis 实例成功获取锁,才算真正的获取锁成功

  2. 如果成功获取锁,则锁的真正有效时间是 TTL 减去第三步的时间差 的时间;比如:TTL 是 5s, 获取所有锁用了 2s, 则真正锁有效时间为 3s (其实应该再减去时钟漂移);

  3. 如果客户端由于某些原因获取锁失败,便会开始解锁所有 redis 实例;因为可能已经获取了小于 3 个锁,必须释放,否则影响其他 client 获取锁

算法示意图如下:

RedLock 算法是否是异步算法??

可以看成是同步算法;因为 即使进程间(多个电脑间)没有同步时钟,但是每个进程时间流速大致相同;并且时钟漂移相对于 TTL 叫小,可以忽略,所以可以看成同步算法;(不够严谨,算法上要算上时钟漂移,因为如果两个电脑在地球两端,则时钟漂移非常大)

RedLock 失败重试

当 client 不能获取锁时,应该在随机时间后重试获取锁;并且最好在同一时刻并发的把 set 命令发送给所有 redis 实例;而且对于已经获取锁的 client 在完成任务后要及时释放锁,这是为了节省时间;

RedLock 释放锁

由于释放锁时会判断这个锁的 value 是不是自己设置的,如果是才删除;所以在释放锁时非常简单,只要向所有实例都发出释放锁的命令,不用考虑能否成功释放锁;

RedLock 注意点(Safety arguments):

  1. 先假设 client 获取所有实例,所有实例包含相同的 key 和过期时间 (TTL) , 但每个实例 set 命令时间不同导致不能同时过期,第一个 set 命令之前是 T1, 最后一个 set 命令后为 T2, 则此 client 有效获取锁的最小时间为 TTL-(T2-T1)- 时钟漂移;

  2. 对于以 N/2+ 1 (也就是一半以 上) 的方式判断获取锁成功,是因为如果小于一半判断为成功的话,有可能出现多个 client 都成功获取锁的情况, 从而使锁失效

  3. 一个 client 锁定大多数事例耗费的时间大于或接近锁的过期时间,就认为锁无效,并且解锁这个 redis 实例 (不执行业务) ; 只要在 TTL 时间内成功获取一半以上的锁便是有效锁;否则无效

系统有活性的三个特征

  1. 能够自动释放锁

  2. 在获取锁失败(不到一半以上),或任务完成后 能够自动释放锁,不用等到其自动过期

  3. 在 client 重试获取哦锁前(第一次失败到第二次重试时间间隔)大于第一次获取锁消耗的时间;

  4. 重试获取锁要有一定次数限制

RedLock 性能及崩溃恢复的相关解决方法

  1. 如果 redis 没有持久化功能,在 clientA 获取锁成功后,所有 redis 重启,clientB 能够再次获取到锁,这样违法了锁的排他互斥性;

  2. 如果启动 AOF 永久化存储,事情会好些, 举例:当我们重启 redis 后,由于 redis 过期机制是按照 unix 时间戳走的,所以在重启后,然后会按照规定的时间过期,不影响业务;但是由于 AOF 同步到磁盘的方式默认是每秒 - 次,如果在一秒内断电,会导致数据丢失,立即重启会造成锁互斥性失效;但如果同步磁盘方式使用 Always (每一个写命令都同步到硬盘) 造成性能急剧下降;所以在锁完全有效性和性能方面要有所取舍;

  3. 有效解决既保证锁完全有效性及性能高效及即使断电情况的方法是 redis 同步到磁盘方式保持默认的每秒,在 redis 无论因为什么原因停掉后要等待 TTL 时间后再重启 (学名: 延迟重启) ; 缺点是 在 TTL 时间内服务相当于暂停状态;

总结:

  1. TTL 时长 要大于正常业务执行的时间 + 获取所有 redis 服务消耗时间 + 时钟漂移

  2. 获取 redis 所有服务消耗时间要 远小于 TTL 时间,并且获取成功的锁个数要 在总数的一般以上:N/2+1

  3. 尝试获取每个 redis 实例锁时的时间要 远小于 TTL 时间

  4. 尝试获取所有锁失败后 重新尝试一定要有一定次数限制

  5. 在 redis 崩溃后(无论一个还是所有),要延迟 TTL 时间重启 redis

  6. 在实现多 redis 节点时要结合单节点分布式锁算法 共同实现

网络上查找的 redis 分布式锁 算法流程图如下(不推荐使用):

不推荐原因:

  1. 根据流程图可看出其流程较为繁琐

  2. 使用较为老式的 setnx 方法获取锁及 expire 方法(无法保证原子操作)

  3. redis 单点,无法做到错误兼容性;

如下为官网解析(英语水平不够,如有理解问题,请指出):

Redlock(redis 分布式锁)原理分析相关推荐

  1. Redis分布式锁原理(一)——redis分布式锁需要注意的问题

    下一篇:Redis分布式锁原理(二)--Redisson分布式锁源码浅析 虽然目前Redisson框架已经帮我们封装好了分布式锁的实现逻辑,我们可以直接像调用本地锁一样使用即可,但本文并不直接剖析Re ...

  2. redis分布式锁原理与实现

    分布式锁原理 分布式锁,是控制分布式系统之间同步访问共享资源的一种方式.在分布式系统中,常常需要协调他们的动作.如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候, ...

  3. Redis分布式锁原理解析

    这章节我们来学习一下,Redis分布式锁的一个原理,首先我们看一下目录,最开始我们要讲一下,Redis分布式锁,相关的一些命令,然后在分布式锁演进的时候呢,还会以时间戳进行一个结合,后边还会讲一下,R ...

  4. redis分布式锁原理及实现

    一.写在前面 现在面试,一般都会聊聊分布式系统这块的东西.通常面试官都会从服务框架(Spring Cloud.Dubbo)聊起,一路聊到分布式事务.分布式锁.ZooKeeper等知识. 所以咱们这篇文 ...

  5. Redis分布式锁原理

    业务背景: 后台定时任务刷新Redis的数据到数据库中,有多台机器开启了此定时同步的任务,但是需要其中一台工作,其他的作为备用,提高可用性.使用Redis分布式锁进行限制,拿到锁的机器去执行具体业务, ...

  6. 拜托,面试官不要在问我Redis分布式锁原理了

    大家好,给大家先做个自我介绍 我是码上代码,大家可以叫我码哥 我也是一个普通本科毕业的最普通学生,我相信大部分程序员或者想从事程序员行业的都是普通家庭的孩子,所以我也是靠自己的努力,从毕业入职到一家传 ...

  7. redis setnx 分布式锁_手写Redis分布式锁

    分布式锁使用场景 现在的系统都是集群部署,每个服务都不是单节点的了.比如库存服务,可能部署到3台机器上分别命名为节点1,节点2,节点3.库存服务需要扣减库存,扣减库存肯定需要锁吧,如果使用Lock或者 ...

  8. redis分布式锁 在集群模式下如何实现_收藏慢慢看系列:简洁实用的Redis分布式锁用法...

    在微服务中很多情况下需要使用到分布式锁功能,而目前比较常见的方案是通过Redis来实现分布式锁,网上关于分布式锁的实现方式有很多,早期主要是基于Redisson等客户端,但在Spring Boot2. ...

  9. 简洁实用的Redis分布式锁用法

    在微服务中很多情况下需要使用到分布式锁功能,而目前比较常见的方案是通过Redis来实现分布式锁,网上关于分布式锁的实现方式有很多,早期主要是基于Redisson等客户端,但在Spring Boot2. ...

  10. 电商项目实战之缓存与Redis分布式锁

    电商项目实战之缓存与Redis分布式锁 缓存失效 缓存穿透 缓存雪崩 缓存击穿 分布式缓存 分布式锁 SpringBoot整合Redisson实现分布式锁 实现过程 缓存和数据库一致性 场景分析 解决 ...

最新文章

  1. “数学不行,啥都干不好!”骨灰级程序员:这比努力重要1000倍
  2. 博士发表2篇以上高水平论文,可直聘为副教授或教授!
  3. bootstrap 弹框使用
  4. 发布json数据_技术分享 | MySQL 8.0.17 GA 发布!
  5. react-native init MyProject之后发生了什么
  6. 警惕开源代码库中的安全隐患
  7. js保存当前html,JavaScript保存当前页面
  8. Python之collections模块详细实例
  9. pandas.DataFrame.append
  10. 上海车展自动驾驶产业链盘点
  11. word参考文献后面空格太大
  12. google hacking 搜索技巧
  13. 实现黑客帝国中的代码雨 快进来学(附源代码)
  14. 这7种类型的食物可能引起 “痘痘”
  15. 上界与下界-- 视图界定--协变与逆变
  16. 汽车之家移动主App服务端架构变迁
  17. _SaveLog.dpr立即备份晓亮的电脑操作记录热键(快捷键) F11由于原来的 AutoIt 杀毒软件总是误报...
  18. 如何通过校园招聘,进入互联网大厂?
  19. js根据日期计算星期几
  20. 如何用matlab中syms建立符号方程,用matlab求解符号方程及符号方程组

热门文章

  1. Linux内核开发者大会 开始报名啦~
  2. oracle数据库导dump,oracle数据导入,导出dump文件
  3. 倒计时按钮_倒计时牌都不会做,妹子何必嫁这货
  4. 【三维路径规划】基于matlab遗传算法无人机三维路径规划【含Matlab源码 1526期】
  5. 【优化算法】吉萨金字塔建造优化算法(GPC)【含Matlab源码 1438期】
  6. 【路径规划】基于matlab GUI蚁群算法求解电动汽车充电站与换电站协调路径规划【含Matlab源码 796期】
  7. 【物理应用】基于matlab车载自组织网络中路边性能及防碰撞算法研究【含Matlab源码 263期】
  8. 【图像融合】基于matlab CBF算法图像融合【含Matlab源码 083期】
  9. 面试问到处理过什么棘手问题_为什么调节人工智能如此棘手?
  10. 自己对行业未来发展的认知_我们正在建立的认知未来