[redisson]阿里云加锁问题

2024-07-18 302 views
8

在阿里云Redis环境下 采用SingleServerConfig配置 使用RLock锁时,会出一定机率的解锁问题: 多线程模式下, 对同一个key进行加锁, A线程加锁成功, B线程等待, A线程解锁, B线程继续等待直到30秒默认时间才能加锁成功.

public class RLockTest extends BaseTest {
    @Autowired
    private RedissonClient redissonClient;

    private List<String> lockKeys = new ArrayList<>();
    private Logger log= LoggerFactory.getLogger(getClass());

    @Before
    public void init() {
        for (int i = 0; i < 10; i++) {
            lockKeys.add("lock_key_" + i);
        }
    }

    @Test
    public void test() {
        List<Thread> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            list.add(new Thread(() -> {
                for (int j = 0; j < 10; j++) {
                    LogRequestIdPlugin.setRequestId(LogRequestIdPlugin.newRequestId());
                    doLock(finalI);
                    LogRequestIdPlugin.setRequestId(null);
                }
            }));
        }
        for (Thread t : list) {
            t.start();
        }
        for (Thread t : list) {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void doLock(int i) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        RLock lock = redissonClient.getLock(lockKeys.get(((int) (Math.random() * 10000) % lockKeys.size())));
        try {
            log.info("thread:" + i + " start locking");
            long s = System.currentTimeMillis();
            lock.lock();
            if (System.currentTimeMillis() - s > 10000) {
                log.error("加锁异常!!!");
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("thread:" + i + " locked");
        } finally {
            lock.unlock();
        }
    }
}

15:15:27.923 [B5oYGRb11f8524b] [Thread-29] INFO cn.com.sjfx.account.RLockTest - thread:3 start locking 15:15:27.926 [B5oYGRb11f8524b] [Thread-29] DEBUG org.redisson.command.CommandAsyncService - acquired connection for command (EVAL) and params [if (redis.call('exists', KEYS[1]) == 0) then redis.call('hset', KEYS[1], ARGV[2], 1); redis.call('pe..., 1, lock_key_5, 30000, 30e213ca-fbb8-49b7-a6a2-45fe94e15ec7:292] from slot NodeSource [slot=null, addr=null, redisClient=null, redirect=null, entry=MasterSlaveEntry [masterEntry=[freeSubscribeConnectionsAmount=0, freeSubscribeConnectionsCounter=value:49:queue:0, freeConnectionsAmount=4, freeConnectionsCounter=value:58:queue:0, freezed=false, freezeReason=null, client=[addr=redis://192.168.1.26:6379], nodeType=MASTER, firstFail=0]]] using node 192.168.1.26/192.168.1.26:6379... RedisConnection@154358690 [redisClient=[addr=redis://192.168.1.26:6379], channel=[id: 0xcaa97c72, L:/192.168.1.26:37308 - R:192.168.1.26/192.168.1.26:6379], command=null] 15:15:28.014 [B5oYGRb11f8524b] [Thread-29] DEBUG org.redisson.command.CommandAsyncService - acquired connection for command (EVAL) and params [if (redis.call('exists', KEYS[1]) == 0) then redis.call('hset', KEYS[1], ARGV[2], 1); redis.call('pe..., 1, lock_key_5, 30000, 30e213ca-fbb8-49b7-a6a2-45fe94e15ec7:292] from slot NodeSource [slot=null, addr=null, redisClient=null, redirect=null, entry=MasterSlaveEntry [masterEntry=[freeSubscribeConnectionsAmount=0, freeSubscribeConnectionsCounter=value:49:queue:0, freeConnectionsAmount=8, freeConnectionsCounter=value:62:queue:0, freezed=false, freezeReason=null, client=[addr=redis://192.168.1.26:6379], nodeType=MASTER, firstFail=0]]] using node 192.168.1.26/192.168.1.26:6379... RedisConnection@792711111 [redisClient=[addr=redis://192.168.1.26:6379], channel=[id: 0x00f6d3b9, L:/192.168.1.26:37324 - R:192.168.1.26/192.168.1.26:6379], command=null]

15:15:57.966 [B5oYGRb11f8524b] [Thread-29] DEBUG org.redisson.command.CommandAsyncService - acquired connection for command (EVAL) and params [if (redis.call('exists', KEYS[1]) == 0) then redis.call('hset', KEYS[1], ARGV[2], 1); redis.call('pe..., 1, lock_key_5, 30000, 30e213ca-fbb8-49b7-a6a2-45fe94e15ec7:292] from slot NodeSource [slot=null, addr=null, redisClient=null, redirect=null, entry=MasterSlaveEntry [masterEntry=[freeSubscribeConnectionsAmount=0, freeSubscribeConnectionsCounter=value:49:queue:0, freeConnectionsAmount=9, freeConnectionsCounter=value:63:queue:0, freezed=false, freezeReason=null, client=[addr=redis://192.168.1.26:6379], nodeType=MASTER, firstFail=0]]] using node 192.168.1.26/192.168.1.26:6379... RedisConnection@792711111 [redisClient=[addr=redis://192.168.1.26:6379], channel=[id: 0x00f6d3b9, L:/192.168.1.26:37324 - R:192.168.1.26/192.168.1.26:6379], command=null]

15:15:58.008 [B5oYGRb11f8524b] [Thread-29] ERROR cn.com.sjfx.account.RLockTest - 加锁异常!!!

回答

8

My redis server info is : 实例ID: r-bp15293fccccc784 可用区: 杭州 多可用区9 (可用区G+H) | 网络类型: VPC网络 实例规格 8G集群版(2节点) 版本: Redis 4.0

Sorry can not give your the host because it is in use.

3

这个问题可能需要你跟阿里云方面提交一个工单。

8

提交了,但他们要我自己去查,意思是程序代码不是他们的售后服务范围 但我对redisson底层并不了解,也没有太多时间去查 我现在是使用了一个自己布署的redis服务来单独做锁操作 - -

9

这个是redis4 中有几个 命令不支持

4

加锁相关命令都是支持的

4

我最近也遇到了类似的问题,但是我这边有两个节点使用RLock锁时,会出一定机率的解锁问题: 对同一个key进行加锁, A服务线程加锁成功, B服务线程等待, A服务线程解锁, B服务线程继续等待直到默认时间才能加锁成功。(生产/阿里云)服务器会出现,(开发/本地机房)的服务器不会出现

4

@Huile3344 有可能是节点同步延迟造成的

9

我也同样在阿里云碰到这个问题。A线程锁定后,其余线程进入等待。A线程释放后,其余线程继续挂起等待,直到锁最大超时时间后才正常使用。 如下图事例,每个线程运行时间是1s左右,但除了第一个线程,其余线程均运行超过30S image

8

怎么解决这个问题啊,我也出现了这个问题

2

是版本问题,还是服务区问题,我们公司有两个redis,就服务区不同

8

大哥,你这个问题怎么解决

3

我这边最后是轮询tyrlock判断解决的,也就是相当于不使用它自身的解锁通知,而是尝试不停的锁定

··· //单次锁定最长5ms long waitTime = 5; //最长锁定时间 long allWaitTime = 0; boolean isLocked = false; do { //当前系统时间 long st = System.currentTimeMillis(); //最大锁定5ms isLocked = lock.tryLock(waitTime, TimeUnit.MILLISECONDS); allWaitTime += System.currentTimeMillis() - st; } while (!isLocked && allWaitTime < config.getLockedWaitTime().toMillis()); return isLocked; ···

8

最后没有使用阿里云redis,用的自建redis。 这个有没有可能是订阅/通知的问题,订阅不成功或者通知失败?

8

自己新建了一个redis专门用来加锁,只使用阿里云的做缓存

3

这样比较浪费时间和资源,当两个线程竞争的时候,使用通知机制会快很多