Redisson分布式锁

 RFuture tryLockInnerAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand command) {    return evalWriteAsync(getName(), LongCodec.INSTANCE, command,                          "if (redis.call('exists', KEYS[1]) == 0) then " +                          "redis.call('hincrby', 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]);",                          Collections.singletonList(getName()), unit.toMillis(leaseTime), getLockName(threadId)); }

此处的LockName UUID是基于当前时间、计数器(counter)和硬件标识(通常为无线网卡的MAC地址)等数据计算生成的。

protected String getLockName(long threadId) {    return id + ":" + threadId;}this.id = commandExecutor.getConnectionManager().getId();// debug 发现id是一个 uuid// 所以不会出现不同服务相同线程id对redis分布式锁上锁成功的情况

加锁流程图

Redisson Lock的效果

watchdog 锁自动续期(默认每次续30s)

private void renewExpiration() {    ExpirationEntry ee = EXPIRATION_RENEWAL_MAP.get(getEntryName());    if (ee == null) {        return;    }    Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {        @Override            public void run(Timeout timeout) throws Exception {            ExpirationEntry ent = EXPIRATION_RENEWAL_MAP.get(getEntryName());            if (ent == null) {                return;            }            Long threadId = ent.getFirstThreadId();            if (threadId == null) {                return;            }                // 锁续期            RFuture future = renewExpirationAsync(threadId);            future.onComplete((res, e) -> {                // 异常                if (e != null) {                    log.error("Can't update lock " + getName() + " expiration", e);                    EXPIRATION_RENEWAL_MAP.remove(getEntryName());                    return;                }                if (res) {                    // reschedule itself                    // 续期成功,再提交一个任务                    renewExpiration();                }            });        }    }, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);    ee.setTimeout(task);}// 主要判断就是 这个锁是否在 redis 中存在,如果存在就进行 pexpire 延期protected RFuture renewExpirationAsync(long threadId) {    return evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,                          "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +                          "redis.call('pexpire', KEYS[1], ARGV[1]); " +                          "return 1; " +                          "end; " +                          "return 0;",                          Collections.singletonList(getName()),                          internalLockLeaseTime, getLockName(threadId));}

总结

Redisson分布式锁安全的原因: 首先锁的lockName是根据uuid+当前线程id组合生成,不可能存在重复 同时还有一个watch dog自动续期的机制

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章