Redisson 实现分布式锁
锁的获取:Redisson 通过发送一个包含 NX(只有键不存在时才设置)、PX(设置键的过期韶光)选项的 SET 命令来考试测验获取锁。如果该命令实行成功(即之前锁不存在),则表示锁被成功获取。KEYS[1] 锁的KEY, ARGV[2] 客户端IDif (redis.call('exists', KEYS[1]) == 0) then redis.call('hset', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end;if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then redis.call('hincrby', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end;return redis.call('pttl', KEYS[1]);
锁的自动续期:为了防止永劫光操作导致锁过期(客户端崩溃或永劫光运行的任务),Redisson 会在一个后台线程中自动给持有的锁续期,确保在操作进行期间,锁不会失落效。公正锁和非公正锁:Redisson 供应了公正锁(RFairLock)和非公正锁(RLock)的实现。公正锁通过掩护一个要求行列步队来担保获取锁的顺序性,而非公正锁则不担保这一点。公正锁的实现更加繁芜,须要更多的 Redis 操作。锁的开释:开释锁时,Redisson 通过实行一个 Lua 脚本来确保操作的原子性。该脚本会检讨当前锁是否仍旧由当前哨程持有(通过比对一个唯一标识符),如果是,则开释锁。KEYS[1] 锁的KEY, ARGV[2] 客户端ID
if (redis.call('exists', KEYS[1]) == 0) then redis.call('publish', KEYS[2], ARGV[1]); return 1; end;if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then return nil; end;local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1);if (counter > 0) then redis.call('pexpire', KEYS[1], ARGV[2]); return 0;else redis.call('del', KEYS[1]); redis.call('publish', KEYS[2], ARGV[1]); return 1; end;return nil;
两点解释为什么要用lua 脚本 + hset 客户端id number 命令来实现?(1)setnx key value(客户端id) + pexpire。 pexpire实行失落败,回造成锁无法开释。(2)set key value(客户端Id) nx expx time。 没有(1)的问题,但不可重入。(3)lua脚本 + hset key 客户端id number。没有(1)(2)的问题,可实现可重入锁。为什么要设置客户端id?(1)删除时,可判断是否是自己加的锁,防止误删除。(2)实现锁的可重入。优点易用性:Redisson 供应了丰富的高层抽象,使得在 Java 运用中实现分布式锁变得非常大略。高性能:基于 Redis 的实现担保了高性能,特殊是在锁操作须要快速相应的场景中。自动续期:自动续期机制防止了因任务运行韶光过长而导致的锁过期问题。支持公正锁和非公正锁:供应了更灵巧的锁策略选择。可重入:一个客户端加锁成功后,可多次加锁。缺陷依赖于 Redis 的可用性:如果 Redis 做事不可用,基于 Redisson 的分布式锁也会受到影响。资源花费:自动续期机制虽然可以防止锁过期,但也意味着额外的资源花费和网络通信。Redis 的持久性问题:在 Redis 配置为非持久化模式时,可能会在 Redis 重启后丢失锁信息,只管这在分布式锁的利用场景中常日不是紧张问题。
Redisson 的分布式锁供应了一个在 Java 中易于利用、性能良好的办理方案,适宜须要快速开拓分布式运用的团队。然而,选择利用 Redisson 时,还须要考虑到运用对 Redis 做事的依赖以及干系的资源花费。
RedLock 算法是由 Redis 的创始人 Antirez 提出的一种分布式锁的实现算法,旨在提高分布式系统中锁的可靠性。该算法紧张用于办理在分布式环境下单个 Redis 实例可能涌现的单点故障问题,通过组合多个 Redis 实例来达到更高的可靠性。

RedLock 算法的核心思想是同时利用多个独立的 Redis 实例来获取锁,只有昔时夜多数的 Redis 实例都成功得到锁时,锁才被认为是成功获取的。算法的基本步骤如下:
获取锁:客户端考试测验在 N 个 Redis 实例上创建锁,每个实例都设置一个相同的锁ID(由客户端天生,担保唯一性)和锁的有效韶光。客户端须要在给定的韶光内(比如10毫秒内)从大多数(大于 N/2)的 Redis 实例上成功得到锁。如果客户端从大多数实例上成功获取了锁,那么认为锁获取成功。客户端打算获取锁的有效韶光,这个有效韶光是原始有效韶光减去获取锁所花费的韶光。开释锁:客户端在完成操作后,须要开释在所有 Redis 实例上的锁。这常日通过发送一个解锁脚本来实现,该脚本会检讨锁ID是否匹配,以确保只有锁的持有者能开释锁。优点避免单点故障:通过利用多个 Redis 实例,RedLock 算法减少了因单个 Redis 实例故障导致的锁失落效风险。容错能力:纵然部分 Redis 实例不可用,只要大多数实例可用,锁操作仍旧可以成功进行。较高的可靠性:相较于单个 Redis 实例的锁实现,RedLock 供应了更高的可靠性,适用于对锁准确性哀求较高的场景。缺陷繁芜性:实现 RedLock 算法须要掩护多个 Redis 实例,增加了支配和管理的繁芜性。性能开销:与单个 Redis 实例比较,RedLock 须要在多个实例上进行锁操作,可能会增加延迟和网络开销。争媾和风险:关于 RedLock 算法的安全性和可靠性有一定的争议。一些专家认为纵然利用多个实例,也难以完备担保分布式锁的安全性,由于网络分区和时钟漂移等问题仍旧可能导致锁的禁绝确行为。只管存在争议,RedLock 算法在一定条件下可以供应比单个 Redis 实例更高的可靠性,特殊是在须要避免单点故障且可以接管一定的性能开销的运用处景中。然而,设计和履行 RedLock 方案时,须要仔细考虑其繁芜性和潜在的风险。
3.基于Etcd的分布式锁Etcd 是一个高可用的分布式键值存储,常用于配置管理和做事创造。它供应了同等性担保,使其成为实现分布式锁的空想选择。基于 Etcd 的分布式锁利用 Etcd 的事务和租约(Lease)机制来实现。
实现事理Etcd 实现分布式锁
全体实现办法类似于Zookeeper
租约创建:客户端首先创建一个租约(Lease),租约在一定韶光后会过期。租约的存在韶光便是锁的最大持有韶光,以防止客户端在持有锁时发生故障导致锁无法开释。锁的获取:客户端考试测验在 Etcd 中创建一个带有租约的键。这个键的存在代表着锁的占用。如果键已经存在,表示锁被其他客户端持有。客户端可以选择等待或重试。锁的等待:如果锁已被其他客户端持有,当前客户端可以通过不雅观察(watch)该键的变革来等待锁被开释。Etcd 的不雅观察机制许可客户端被动地吸收键值变革的关照。锁的开释:锁的持有者通过删除对应的键或让租约过期来开释锁。其他客户端可以通过不雅观察到这一变革来重新考试测验获取锁。优点强同等性:Etcd 利用 Raft 协议来担保数据的同等性,这意味着基于 Etcd 的分布式锁在分布式系统中非常可靠。容错性:由于 Etcd 是一个集群,它能够处理节点故障,保持高可用性和持久性。自动锁开释:通过租约机制,纵然锁的持有者发生故障,锁也会在租约过期后自动开释,防止去世锁。缺陷性能开销:与基于内存的锁(如 Redis 锁)比较,基于 Etcd 的锁可能会有更高的延迟,由于它依赖于网络和磁盘 I/O。繁芜性:实现和管理基于 Etcd 的锁相对繁芜,须要对 Etcd 的事情机制有一定理解。资源花费:Etcd 集群的运行须要花费系统资源,特殊是在高负载环境下,可能须要优化 Etcd 集群的配置和支配。基于 Etcd 的分布式锁因其强同等性和高可用性而受到青睐,特殊适用于对锁准确性和系统稳定性哀求较高的场景。然而,设计时须要权衡其性能开销和管理繁芜性。
开源客户端Jetcd工具推举
RedissonCuratorJetcd