[Redisson] Distributed lock source code analysis how to realize mutual exclusion of multiple application instances

入口org.redisson.api.RedissonClient

@Resource
private RedissonClient redissonClient;
...

RLock rLock = redissonClient.getLock(lockName);

lockName is the key saved in Redis

Enter org.redisson.Redisson.getLock

    @Override
    public RLock getLock(String name) {
        return new RedissonLock(commandExecutor, name);
    }

Enter org.redisson.RedissonLock

directly in the build methodsuper(commandExecutor, name);

    public RedissonBaseLock(CommandAsyncExecutor commandExecutor, String name) {
        super(commandExecutor, name);
        this.id = getServiceManager().getId();
        this.internalLockLeaseTime = getServiceManager().getCfg().getLockWatchdogTimeout();
        this.entryName = id + ":" + name;
    }
  • org.redisson.connection.ServiceManager: private final String id = UUID.randomUUID().toString();
  • This idis UUID:this.id = getServiceManager().getId();
  • This entryName can distinguish which application instance it is through UUID
  • entryName+threadId can distinguish which process of which application instance holds the lock

rLock.tryLock(60, TimeUnit.SECONDS);

try to acquire the lock

Enter org.redisson.RedissonLock

    <T> RFuture<T> tryLockInnerAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
        return commandExecutor.syncedEval(getRawName(), LongCodec.INSTANCE, command,
                "if ((redis.call('exists', KEYS[1]) == 0) " +
                            "or (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(getRawName()), unit.toMillis(leaseTime), getLockName(threadId));
    }
  • Collections.singletonList(getRawName()), this parameter is the key of Redis
  • unit.toMillis(leaseTime), this parameter is the first parameter of the Lua script, namelyARGV[1]
  • getLockName(threadId), this parameter is the second parameter of the Lua script, namelyARGV[2]
  • Analysis of the meaning of this Lua script
  • (redis.call('exists', KEYS[1]) == 0), the lock does not exist
  • or (redis.call('hexists', KEYS[1], ARGV[2]) == 1)), the lock exists, but the current instance thread owns the lock
  • In the above two cases, it means that the locking is successful, and null is returned
  • Otherwise, return the TTL time corresponding to this lock
  • So the place where the outer layer is called is to judge whether the locking is successful according to whether the returned ttl is null
        Long ttl = tryAcquire(waitTime, leaseTime, unit, threadId);
        // lock acquired
        if (ttl == null) {
            return true;
        }

Enter the second parameter getLockName of the Lua script

    protected String getLockName(long threadId) {
        return id + ":" + threadId;
    }

This id is the UUID mentioned above. Combined with the thread ID, it can be determined which process of which application instance holds the lock.

Guess you like

Origin blog.csdn.net/friendlytkyj/article/details/131341990