sofastack / sofa-jraft

A production-grade java implementation of RAFT consensus algorithm.
https://www.sofastack.tech/projects/sofa-jraft/
Apache License 2.0
3.57k stars 1.14k forks source link

请教大佬,分布式锁重入的判定为什么不和线程 ID 作对比 #1148

Closed MatthewAden closed 3 weeks ago

MatthewAden commented 3 weeks ago

目前的我们这边的应用需要这样获取锁,相当于我们在上面封装了一层

    @Override
    public boolean acquireLock(String lockKey) {
        final DistributedLock<byte[]> distributedLock = rheaKvStore.getDistributedLock(lockKey,
                3, TimeUnit.MILLISECONDS, WATCH_DOG);

        while (true) {
            if (distributedLock.tryLock()) {
                return true;
            } else {
                // fail to acquire lock
                ThreadUtils.sleep(raftRegistryProperties.getDistributedLockRetryInterval().toMillis());
            }
        }
    }

当同一个线程先后调用 acquireLock 时,期待能够进行锁重入,但是由于会 new 出来两个不同的锁对象,acquire的 id 会不同,而 rheakv 锁重入的原理是进行如下对比

public boolean isSameAcquirer(final Acquirer acquirer) {
    return acquirer != null && this.fencingToken == acquirer.fencingToken
    && Objects.equals(this.id, acquirer.id);
}

在我们的这个场景下锁重入会失效

fengjiachun commented 3 weeks ago
  1. 关于为什么不用 thread id

因为 thread id 在分布式环境的多个进程中并不能保证一定是唯一的

  1. 在你们的这个场景下锁重入会失效

我理解是用法问题,你把锁的实例丢弃了,你的 acquireLock 方法返回锁的实例就可以重入了

MatthewAden commented 3 weeks ago
  1. thread id 的问题 抱歉,我可能没有表达清楚我的意思,我的意思是或许可以像 redis 的客户端 redission 一样,利用一个全局单例每个客户端生成一个唯一 uuid,获取锁时用 thread id + uuid 构成唯一标识,这样即使像我们那样用也可以成功重入
  2. 在你们的这个场景下锁重入会失效 这边抽象出来获取锁的方法就是返回 true 或者 false,不能返回锁的实例,但是用 ThreadLocal 已经解决了
fengjiachun commented 2 weeks ago

抱歉,我可能没有表达清楚我的意思,我的意思是或许可以像 redis 的客户端 redission 一样,利用一个全局单例每个客户端生成一个唯一 uuid,获取锁时用 thread id + uuid 构成唯一标识,这样即使像我们那样用也可以成功重入

id 有的呀,重入就是靠全局唯一 id 来支持的,看下面代码:

https://github.com/sofastack/sofa-jraft/blob/2d0495524d80210e0982c6fb4b0f3de5f17dc6ae/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/util/concurrent/DistributedLock.java#L59