记录一次使用redisson分布式锁失效的问题

背景

最近有一个减库存的场景,存在并发安全问题,因为redisson客户端对分布式锁的支持比较成熟,所以使用了redisson的分布式锁来保证并发安全问题,避免超卖。代码如下:

@Transactional
public void allot(Param param) {

    RLock lock = redissonClient.getLock(key);
    
    try {
        lock.lock();
        query(param);   // 查询库存是否满足条件,不满足则抛异常,结束
        invoke(param);  // 减库存
        saveLog(param); // 记录出库日志
    } catch (Exception e) {
        log.error("分配失败", e);
        throw e;
    } finally {
        lock.unlock();
    }
}

问题点暴露

测试阶段,测试反馈压测存在超卖问题。我自己也模拟了一下并发请求,发现果真如此。
下面我们从执行流程的角度看分析一下,这段代码存在什么问题

执行流程

注意,spring的@Transactional事务注解,开启事务的时机是在方法中第一条SQL真正执行前。

执行流程如下:
在这里插入图片描述
可以发现,此流程中在事务还未提交的时候,redisson分布式锁 unlock先一步解锁了,数据库此时并未真正的扣减库存,也就是数据并未更新。此时如果有其他线程进入该方法,读取到的当然还是未扣减的库存,再执行扣减操作,当然就有问题了。

解决方案

将加锁解锁的代码 放在事务注解修饰的方法的外层就可以了,代码如下


public void take(Param param){
    RLock lock = redissonClient.getLock(key);
    
    try {
        lock.lock();
        allot(param);
    } catch (Exception e) {
        log.error("分配失败", e);
        throw e;
    } finally {
        lock.unlock();
    }
}

@Transactional
public void allot(Param param) {
    query(param);   // 查询库存是否满足条件,不满足则抛异常,结束
    invoke(param);  // 减库存
    saveLog(param); // 记录出库日志
}

总结

在使用分布式锁时,要注意数据库事务提交与解锁时机,避免分布式锁失效。

Redisson是一个基于Redis分布式锁框架,它提供了可靠的分布式锁实现。如果使用Redisson分布式锁失效,可能有以下几个常见的原因: 1. 锁超时时间设置不合理:在使用Redisson分布式锁时,需要设置一个合理的锁超时时间。如果锁的超时时间设置得太短,可能会导致业务逻辑执行时间超过锁的超时时间,从而使其他节点在业务逻辑还未执行完毕时获取到了锁,造成锁失效。建议根据实际业务情况,合理设置锁的超时时间。 2. 锁释放不正确:在使用Redisson分布式锁时,需要确保在业务逻辑执行完毕后正确释放锁。如果业务逻辑执行过程中发生异常或错误,导致没有进行锁释放操作,那么其他节点将无法获取到该锁,从而使锁失效。建议使用try-finally或try-catch-finally等方式,确保在所有情况下都能够正确释放锁。 3. Redis连接异常或网络故障:Redisson框架内部依赖于Redis作为存储介质,如果Redis连接异常或发生网络故障,可能会导致分布式锁失效。在使用Redisson分布式锁时,应该处理好Redis连接异常和网络故障的情况,例如进行适当的重试或错误处理。 4. Redis节点故障:如果使用的是Redis集群,当Redis集群中的某个节点发生故障或重启时,可能会导致分布式锁失效。这是因为Redisson框架默认使用的是单节点模式,如果节点失效,将无法继续操作锁。可以使用Redisson的集群模式,通过多个Redis节点实现高可用性,并在发生故障时自动切换到其他可用节点。 在使用Redisson分布式锁时,建议仔细阅读其文档并按照最佳实践进行配置和使用。同时,需要注意处理异常情况和错误情况,以确保分布式锁的可靠性和正确性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值