Redis 实现分布式锁
分布式锁是一种用于在分布式系统中实现同步和互斥访问的机制。在分布式系统中,多个节点同时访问共享资源可能会导致数据不一致或竞争条件的发生。分布式锁提供了一种保护共享资源的方式,以确保在任意时刻只有一个节点可以访问该资源,如:同一时刻每个订单只能有一个线程操作取消订单功能。
常见分布式锁实现:
MySQL:MySQL本身就带有锁机制,由于业务特性使用MySQL作为分布式锁并不合适,而且性能一般,一般很少使用MySQL来实现分布式锁。
ZooKeeper:ZooKeeper是企业级开发中较好的一个实现分布式锁的方案,相对于Redis,ZooKeeper的部署和维护复杂一些。此外,ZooKeeper的性能相对较低,适用于对性能要求不高的场景。
Redis:Redis分布式锁的实现通常使用了SETNX(SET if Not eXists)命令和EXPIRE命令。使用SETNX可以尝试将一个键值对设置到Redis中,只有在该键不存在的情况下才能成功。成功获取锁的客户端可以设置一个过期时间,确保即使在发生故障的情况下,锁也能自动释放。
二、分布式锁具备的特点
实现的分布式锁,需要具备一下特征:
Redis 实现分布式锁的几种常见方式:
SETNX 命令实现
-
加锁:使用
SETNX
命令尝试设置锁对应的 key,如果 key 不存在,则设置成功,获取锁。 -
解锁:直接使用
DEL
命令删除对应的 key。但为了避免误删其他线程的锁,建议使用 Lua 脚本,通过 key 对应的 value 值来判断是否是自己的锁。
SET 命令实现
-
加锁:使用
SET
命令,结合NX
和EX
选项,一次性完成设置 key 和设置过期时间的操作。例如:SET resource_1 random_value NX EX 5
,其中resource_1
是锁的 key,random_value
是随机值,EX 5
表示设置过期时间为 5 秒。 -
解锁:使用
DEL
命令删除 key。
Redisson 客户端实现
-
加锁:通过 Redisson 客户端的
RLock
接口获取锁对象,调用lock()
方法获取锁。如果未指定锁超时时间,会使用 Watch Dog 自动续期机制。 -
解锁:调用
unlock()
方法释放锁。
RedLock 算法实现
-
加锁:客户端向 Redis 集群中的多个独立的 Redis 实例依次请求申请加锁,如果客户端能够和半数以上的实例成功地完成加锁操作,则认为客户端成功地获得分布式锁。
-
解锁:如果加锁失败,则要解锁所有的节点,不管该节点加锁时是否成功。