1. Kaito 是否可以使用 SETNX + EXPIRE 来完成加锁操作? 30 | 如何使用Redis实现分布式锁?-极客时间 不可以这么使用。使用 2 个命令无法保证操作的原子性,在异常情况下,加锁结果会不符合预期。异常情况主要分为以下几种情况: 1、SETNX 执行成功,执行 EXPIRE 时由于网络问题设置过期失败 2、SETNX 执行成功,此时 Redis 实例宕机,EXPIRE 没有机会执行 3、SETNX 执行成功,客户端异常崩溃,EXPIRE 没有机会执行 如果发生以上情况,并且客户端在释放锁时发生异常,没有正常释放锁,那么这把锁就会一直无法释放,其他线程都无法再获得锁。 下面说一下关于 Redis 分布式锁可靠性的问题。 使用单个 Redis 节点(只有一个master)使用分布锁,如果实例宕机,那么无法进行锁操作了。那么采用主从集群模式部署是否可以保证锁的可靠性? 答案是也很难保证。如果在 master 上加锁成功,此时 master 宕机,由于主从复制是异步的,加锁操作的命令还未同步到 slave,此时主从切换,新 master 节点依旧会丢失该锁,对业务来说相当于锁失效了。 所以 Redis 作者才提出基于多个 Redis 节点(master节点)的 Redlock 算法,但这个算法涉及的细节很多,作者在提出这个算法时,业界的分布式系统专家还与 Redis 作者发生过一场争论,来评估这个算法的可靠性,争论的细节都是关于异常情况可能导致 Redlock 失效的场景,例如加锁过程中客户端发生了阻塞、机器时钟发生跳跃等等。 感兴趣的可以看下这篇文章,详细介绍了争论的细节,以及 Redis 分布式锁在各种异常情况是否安全的分析,收益会非常大:http://zhangtielei.com/posts/blog-redlock-reasoning.html。 简单总结,基于 Redis 使用分布锁的注意点: 1、使用 SET $lock_key $unique_val EX $second NX 命令保证加锁原子性,并为锁设置过期时间 2、锁的过期时间要提前评估好,要大于操作共享资源的时间 3、每个线程加锁时设置随机值,释放锁时判断是否和加锁设置的值一致,防止自己的锁被别人释放 4、释放锁时使用 Lua 脚本,保证操作的原子性 5、基于多个节点的 Redlock,加锁时超过半数节点操作成功,并且获取锁的耗时没有超过锁的有效时间才算加锁成功 6、Redlock 释放锁时,要对所有节点释放(即使某个节点加锁失败了),因为加锁时可能发生服务端加锁成功,由于网络问题,给客户端回复网络包失败的情况,所以需要把所有节点可能存的锁都释放掉 7、使用 Redlock 时要避免机器时钟发生跳跃,需要运维来保证,对运维有一定要求,否则可能会导致 Redlock 失效。例如共 3 个节点,线程 A 操作 2 个节点加锁成功,但其中 1 个节点机器时钟发生跳跃,锁提前过期,线程 B 正好在另外 2 个节点也加锁成功,此时 Redlock 相当于失效了(Redis 作者和分布式系统专家争论的重要点就在这) 8、如果为了效率,使用基于单个 Redis 节点的分布式锁即可,此方案缺点是允许锁偶尔失效,优点是简单效率高 9、如果是为了正确性,业务对于结果要求非常严格,建议使用 Redlock,但缺点是使用比较重,部署成本高 2020-10-28 网友补充
凯文小猪
这里老师漏了一点 就是session timeout处理 在分布式锁的场景中就是: 一个key过期了 但是代码还没处理完 此时就发生了重复加锁的问题。 通常我们有两种方式处理: 1. 设置看门狗 也就是redision的处理方式 2. 设置状态机 由最后的业务层来做代码回溯

2.Darren 其实分布式锁选择Etcd的话,可能会更好。 Etcd 支持以下功能,正是依赖这些功能来实现分布式锁的: 1、Lease 即租约机制(TTL,Time To Live)机制: Etcd 可以为存储的 KV 对设置租约,当租约到期,KV 将失效删除;同时也支持续约,即 KeepAlive; Redis在这方面很难实现,一般假设通过SETNX设置的时间10S,如果发生网络抖动,万一业务执行超过10S,此时别的线程就能回去到锁; 2、Revision 机制: Etcd 每个 key 带有一个 Revision 属性值,每进行一次事务对应的全局 Revision 值都会加一,因此每个 key 对应的 Revision 属性值都是全局唯一的。通过比较 Revision 的大小就可以知道进行写操作的顺序。 在实现分布式锁时,多个程序同时抢锁,根据 Revision 值大小依次获得锁,可以避免 “惊群效应”,实现公平锁; Redis很难实现公平锁,而且在某些情况下,也会产生 “惊群效应”; 3、Prefix 即前缀机制,也称目录机制: Etcd 可以根据前缀(目录)获取该目录下所有的 key 及对应的属性(包括 key, value 以及 revision 等); Redis也可以的,使用keys命令或者scan,生产环境一定要使用scan; 4、Watch 机制: Etcd Watch 机制支持 Watch 某个固定的 key,也支持 Watch 一个目录(前缀机制),当被 Watch 的 key 或目录发生变化,客户端将收到通知; Redis只能通过客户端定时轮训的形式去判断key是否存在; 网友评论  |
所有评论(0)