美文网首页
Redission分布式锁实现原理

Redission分布式锁实现原理

作者: 任未然 | 来源:发表于2023-04-05 16:16 被阅读0次

一、概述

redission分布式锁的特点有可重入、自动续费等,本文通过方法RedissonLock#lock()一步步介绍redission分布式锁如何获取锁、锁自动续费及锁释放

二、获取锁

  1. lock()获取锁有两种方式,可以指定锁的最大时长,不指定会默认最大时长为-1
    方法定位:org.redisson.RedissonLock#lock()

    image.png
  2. 设置锁的时候,如果设置了最大有效时长会获取锁后直接返回,而没有设置最大有效时长的会把时间设为看门狗配置的时间,默认30s,并且获取锁成功后会启动看门狗,
    方法定位:org.redisson.RedissonLock#tryAcquireOnceAsync

    image.png
  3. 通过LUA脚本争抢锁
    代码定位:org.redisson.RedissonLock#tryLockInnerAsync

    image.png
if (redis.call('exists', KEYS[1]) == 0) then  -- 判断锁是否存在
redis.call('hincrby', KEYS[1], ARGV[2], 1); -- 保持锁的信息,数据结构为map,并且value是自增的,value表示重入锁的次数
redis.call('pexpire', KEYS[1], ARGV[1]); -- 设置锁的有效期
return nil; 
end;  -- 返回结束

if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then -- 当锁存在时,判断通过map的key是否存在,存在则是重入锁
redis.call('hincrby', KEYS[1], ARGV[2], 1); -- 重入锁 value自增1,代表重入锁+1
redis.call('pexpire', KEYS[1], ARGV[1]); -- 设置锁的有效期
return nil;
end;  -- 返回结束

return redis.call('pttl', KEYS[1]); -- 如果所存在并且不是重入锁,就直接返回锁的有效时间
  • KEYS[1]:表示自定义锁的key, 例如:RLock myLock = redissonClient.getLock("myLock");, KEYS[1] 就是 myLock
  • ARGV[1]:表示锁的有效期,单位是毫秒
  • ARGV[2]:获取锁线程的唯一标识,后取用来判断是否重入锁
  1. 获取锁不成功会循环获取,直到成功或中断结束


    image.png
  2. 看门狗启动,延时任务递归实现自动续费
    方法定位:org.redisson.RedissonLock#renewExpiration

    image.png
  3. 看门狗通过Lua脚本续费
    代码定位:org.redisson.RedissonLock#renewExpirationAsync

    image.png
  • KEYS[1]:表示自定义锁的key, 例如:RLock myLock = redissonClient.getLock("myLock");, KEYS[1] 就是 myLock
  • ARGV[1]:表示锁的有效期,单位是毫秒
  • ARGV[2]:获取锁线程的唯一标识,后取用来判断是否重入锁
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then -- 判断锁是否存在
redis.call('pexpire', KEYS[1], ARGV[1]); -- 重置锁的有效时间续费
return 1; -- 续费成功返回1
end;
return 0; -- 续费失败返回0

二、释放锁

  1. 通过Lua脚本释放锁
    代码定位:org.redisson.RedissonLock#unlockInnerAsync
    image.png
if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then -- 通过本线程的唯一标识判断本线程的锁是否存在
return nil; -- 不存在本线程的锁, 直接返回
end;
local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); -- 可能重入了多个锁,先执行value-1,去掉一个锁
if (counter > 0) then -- 如果大于0, 表示重入锁还没有释放完
redis.call('pexpire', KEYS[1], ARGV[2]); -- 重置锁的有效期续费
return 0;  -- 返回0标识
else
redis.call('del', KEYS[1]); -- 锁已经释放完了,把锁删除
redis.call('publish', KEYS[2], ARGV[1]); -- 发布消息锁已经释放
return 1; -- 返回1标识
end;
return nil;

相关文章

网友评论

      本文标题:Redission分布式锁实现原理

      本文链接:https://www.haomeiwen.com/subject/gzweddtx.html