[Redisson] 分散ロックのソースコード解析による複数アプリケーションインスタンスの相互排除の実現方法

エントリーorg.redisson.api.RedissonClient

@Resource
private RedissonClient redissonClient;
...

RLock rLock = redissonClient.getLock(lockName);

lockName は Redis に保存されたキーです

「org.redisson.Redisson.getLock」と入力します。

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

org.redisson.RedissonLock を入力してください

build メソッド内で直接super(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();
  • これは次idのとおりですUUIDthis.id = getServiceManager().getId();
  • このentryNameは、UUIDによってどのアプリケーション・インスタンスであるかを識別できます。
  • entryName+threadId により、どのアプリケーション インスタンスのどのプロセスがロックを保持しているかを識別できます

rLock.tryLock(60, TimeUnit.SECONDS);

ロックを取得してみます

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())、このパラメータは Redis のキーです
  • unit.toMillis(leaseTime)、このパラメータは Lua スクリプトの最初のパラメータです。ARGV[1]
  • getLockName(threadId)、このパラメータは Lua スクリプトの 2 番目のパラメータです。ARGV[2]
  • この Lua スクリプトの意味の分析
  • (redis.call('exists', KEYS[1]) == 0)、ロックは存在しません
  • or (redis.call('hexists', KEYS[1], ARGV[2]) == 1))、ロックは存在しますが、現在のインスタンス スレッドがロックを所有しています。
  • 上記 2 つの場合、ロックが成功したことを意味し、null が返されます。
  • それ以外の場合は、このロックに対応する TTL 時間を返します
  • したがって、外側の層が呼び出される場所は、返された ttl が null かどうかに従ってロックが成功したかどうかを判断することになります。
        Long ttl = tryAcquire(waitTime, leaseTime, unit, threadId);
        // lock acquired
        if (ttl == null) {
            return true;
        }

Lua スクリプトの 2 番目のパラメーター getLockName を入力します。

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

この ID は前述の UUID であり、スレッド ID と組み合わせることで、どのアプリケーション インスタンスのどのプロセスがロックを保持しているかを特定できます。

おすすめ

転載: blog.csdn.net/friendlytkyj/article/details/131341990