分布式系统中,Redis分布式锁超时问题常引发数据不一致,典型如电商促销场景:某商品库存100件,却因下单流程超时导致超卖120件。缘由是促销时数据库压力大,下单流程用了6秒,而锁超时设为5秒——锁提前释放后,另一个请求闯入重复扣减库存,最终20个用户付了钱拿不到货。这种问题本质是锁生命周期与业务执行周期不匹配,具体有三个核心痛点:超时时间难设定,许多开发凭经验拍脑袋,遇到系统压力大就超出预期;锁释放与业务完成不同步,锁释放了业务还在执行,导致其他线程误闯临界区;超时后无补偿机制,没判断业务状态就继续执行,造成数据错误。
Redisson的看门狗机制是解决锁超时的基础方案。当未指定leaseTime获取锁时,Redisson会启动后台线程,默认每30秒将锁超时时间延长至lockWatchdogTimeout(默认30000毫秒)。但需优化配置:列如将lockWatchdogTimeout设为业务平均执行时间的3倍,调整lockWatchdogBatchSize(默认100)应对高并发,避免部分锁无法及时续期;同时通过RedissonMetric监控锁续期成功率,确保机制有效。

对于执行时间波动大的业务,动态超时策略更适配。结合历史执行时间(滑动窗口统计)、系统负载(CPU、内存使用率)、业务优先级(核心业务放宽限制)计算超时时间。列如用动态超时provider,取平均时间的2倍作为基础,乘以负载因子,上限30秒,下限5秒,这样能适应不同场景的执行时间变化。
缩短锁持有时间是根本思路。将业务拆分为核心操作与非核心操作:核心操作如库存扣减、订单状态更新放在锁内执行,非核心操作如发送短信、记录日志放锁外异步处理。列如下单流程,锁内只做库存查询、扣减和订单生成,锁外发通知,这样锁持有时间从6秒缩短到1秒内,大幅降低超时风险。

幂等设计是兜底方案。给每个请求生成唯一ID,扣减库存时先检查该ID是否已处理——处理过直接返回成功,未处理再执行。即使锁超时导致两个线程进入,也不会重复操作。同时要做双重校验:获取锁后再次查询库存,确认没被修改再执行,避免脏数据。
核心业务场景可用MultiLock联锁方案,同时锁定多个Redis节点,只有所有锁都获取成功才算有效。列如创建三个分布在不同节点的RLock,用MultiLock包装,获取锁时等待5秒,自动释放时间10秒。这样能降低单节点故障导致的锁丢失风险,但要注意节点分布在不同物理机,超时时间设为单个锁的N倍。

还要避免常见陷阱:锁必须放在finally块释放,不管业务是否异常都能保证释放;用UUID作为锁值,释放时用Lua脚本验证,避免误释放其他线程的锁;Redis主从架构下,主节点宕机可能导致锁未同步到从节点,强一致场景提议用Zookeeper或Etcd;同一线程多次获取锁需支持重入,Redisson的可重入锁能解决这个问题。
最后提议直接用Redisson、Curator等成熟框架,无需自己实现。Redisson封装了看门狗、续期、原子操作、可重入等细节,列如用RLock调用lock方法自动续期,finally里unlock释放,简单可靠;Curator能轻松实现Zookeeper的分布式锁,减少踩坑概率。
