Redisson锁(RLock)在Redis中的结构本质上是一个Hash类型,通过对这个Hash结构中的key-value以及相应的过期机制进行管理,实现了可靠的分布式锁。
一、结构示例:
假设我们使用Redisson的RLock
来对资源myLock
加锁,那么Redis中对应的key结构类似:
127.0.0.1:6379> type myLock
hash
127.0.0.1:6379> hgetall myLock
1) "e4c1f2a0-3db6-4a3e-a78b-8efb33bcf0df:1"
2) "1"
二、结构解析:
Key:用户在代码中定义的锁的名字,例如
myLock
。类型:Redis中的数据类型为
Hash
。Hash中的字段(field):
格式为:
UUID:threadId
UUID
:每个Redisson客户端实例的唯一标识。threadId
:加锁的线程ID。
Hash中的值(value):
表示当前线程对此锁的重入次数,初始为
1
,如果同一线程多次加锁,则次数会递增。
例如:
key: myLock
field: e4c1f2a0-3db6-4a3e-a78b-8efb33bcf0df:1
value: 1
以上含义为:客户端实例e4c1f2a0-3db6-4a3e-a78b-8efb33bcf0df
的线程ID为1
的线程当前占有该锁,且持有次数为1。
三、Redisson如何实现锁的原理
Redisson加锁过程本质上是执行Lua脚本,通过原子操作完成以下几个步骤:
尝试获取锁:
检查当前Hash key是否存在:
若不存在,则创建并设置
field
为当前客户端UUID+线程ID,值为1
,设置TTL。若存在且属于当前线程,则递增计数器,并重置TTL。
若属于其他线程,则获取失败。
释放锁:
检查Hash中field是否属于当前线程:
若属于当前线程,则递减计数器。
如果计数器减为0,则删除field并删除key。
如果计数器大于0,则重置TTL。
若不属于当前线程,则释放失败,返回错误。
四、锁的过期时间(TTL)
Redisson锁在Redis中的key有一个TTL(过期时间),默认值为30秒
。
在锁未释放之前,客户端有一个后台线程会不断对锁的TTL进行续期(默认每10秒检查续期一次),以防止业务线程长时间执行导致锁提前过期(这称为看门狗机制,watchdog机制)。
五、举例
假设某个客户端(UUID为
abc-123
)线程ID为5
加锁成功:
myLock:
abc-123:5 -> 1
TTL: 30秒(每10秒自动续期)
如果同一线程再次调用
lock()
:
myLock:
abc-123:5 -> 2
TTL重置:30秒
当释放锁(调用
unlock()
)一次:
myLock:
abc-123:5 -> 1
TTL重置:30秒
再释放一次:
myLock 被删除
六、总结(关键点回顾)
数据结构:Redis Hash
Key:锁的标识
Field:客户端UUID:线程ID
Value:锁的重入次数
TTL续期机制:看门狗自动续期,防止误释放
Lua脚本:保证加锁、释放锁的原子性