跳至主要內容

Redis分布式锁

tommy大约 3 分钟Redis

Redis分布式锁

什么是分布式锁?

分布式锁,是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。

基于Redis 实现一个简单的分布式锁

加锁,使用setNX lockKey UniqueValue上锁,只有当前的lockKey在Redis中不存在时才能put成功,这样就能保证同一个 lockKey只被添加一次。

释放,使用 del lockKey 删除锁,删除后下一个线程进来就能成功上锁,访问共享资源。在Redis中使用Lua脚本执行一系列操作,让这一系列操作具有原子性。

// 释放锁时,先比较锁对应的 value 值是否相等,避免锁的误释放
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

虽然这种实现方式很简单并且容易理解,在大多数情况下不会出现问题,但是如果释放锁的逻辑没有执行,则锁永远不会被释放,其他的线程永远无法获取到锁,永远无法访问共享资源。所以应当为锁设置一个超时时间,这样当长时间经过后,超过了超时时间锁会自动被释放掉,从而不会影响其他线程的访问。

基于Redis实现一个带有超时时间的分布式锁

为什么要保证Redis的分布式锁要有超时时间?因为我们要考虑锁的释放逻辑无法正常执行的情况,超时应主动释放。

 SET lockKey uniqueValue EX 3 NX

EX:代表设置一个超时时间

NX:代表lockKey当且仅当不存在时才能添加成功

uniqueValue:保证是唯一的字符串

并且必须保证上述的操作都是原子的,否则还会出现锁无法释放的问题。

但是当我们访问的共享资源的时间大于锁超时时间时,导致共享资源访问还没结束锁就被释放了,其他线程进来获取到锁,此时就会出现严重的线程安全问题,例如典型的超买超卖问题。

必须保证当加锁的线程仍然在访问共享资源时,自动为锁续期一段时间,这样才能保证不会在访问中途自动释放,并且保证这些操作的原子性。

如何实现锁的续期?

锁的续期通过现有的框架Redisson,其中框架内部集成了很多Redis分布式锁的解决方案供选择。

Redisson中的分布式锁自带自动续期功能,其续期操作是通过一个专门用来监控和续期的Watch Dog实现的,如果共享资源在锁到期后仍未执行完,则Watch Dog 自动为这把锁进行续期,而不会将锁释放掉。

Redis实现分布式锁的文章

上次编辑于:
贡献者: zazhang