你的Redis分布式锁真的用对了吗?

本引用仅用学习,禁用商用
引用自 https://mp.weixin.qq.com/s/fJsYrkBIN6QEK_Xwzsz0eg

 

你的 Redis 锁方案能否通过以下考验:

  • 业务处理时间超过锁超时时间怎么办?
  • 主从切换时是否可能双写?
  • 时钟回拨会导致 RedLock 失效吗?

上周我在美团技术面中被这些问题连环追问。接下来,我将复盘这场让我收获颇丰的面试,带你深入拆解 Redis 分布式锁在大厂高并发场景中的 6 层关键考量,掌握设计分布式锁的核心要点 。

第1问:什么是分布式锁?为什么需要它?

面试官:先说说分布式锁解决什么问题?

在分布式集群中,多个服务实例可能并发操作共享资源(如库存扣减、订单状态变更)。

分布式锁需要满足三个核心特性: 

1️⃣ 互斥性:同一时刻只能有一个客户端持有锁; 

2️⃣ 防死锁:即使客户端崩溃或网络异常,锁也能被释放 ;

3️⃣ 容错性:在部分节点故障时,锁服务仍能正常运作。

🌰 典型应用场景:

  • 电商秒杀:防止超卖;
  • 支付系统:避免重复扣款;
  • 定时任务:防止多节点重复执行。

第2问:基础实现的陷阱

面试官:Redis锁的基础实现是什么?

我:

错误示范❌:分步执行SETNX + EXPIRE

SETNX lock_key 1    # 加锁  
EXPIRE lock_key 30  # 设置过期时间  

致命风险:若执行完SETNX后Redis宕机,锁将永不释放!

正确姿势✅:原子性单命令

SET lock_key $uuid NX PX 30000  # 一步到位:不存在时设值,过期时间30秒  
  • NX:Key不存在才设值,确保互斥性;
  • PX 30000:30秒自动过期,避免死锁;
  • $uuid:唯一标识,防止误删别人的锁。

第3问:锁释放的安全性保证

面试官:如何安全释放锁?直接DEL有什么问题?

我:

血案现场🩸:

  1. 客户端A持有锁,但处理时间超过了锁的过期时间;
  2. 锁自动释放,客户端B获取了锁;
  3. 客户端A完成操作,直接删除锁 —— 这时删除的是客户端B的锁!

终极防御🛡️:Lua脚本原子校验

if redis.call("GET", KEYS[1]) == ARGV[1] then  
    return redis.call("DEL", KEYS[1])  
else  
    return 0  
end  

第4问:锁续期的时间博弈论

面试官:业务处理时间不可控,如何避免锁提前释放?

我:(果然问到这儿了!)这就是锁续期问题。比如电商扣库存,锁30秒过期,但业务卡了40秒,这时锁提前释放,其他线程进来重复扣减——直接超卖!

解决方案:

  • 自动锁续期机制(推荐方案):通过后台线程定期检测业务状态,动态延长锁的持有时间。比如:Redisson的看门狗,加锁成功后,它会启动一个后台线程,默认每隔锁有效期的三分之一时间(如锁有效期为 30 秒,则每隔 10 秒)检查一次业务是否完成,若未完成则把锁过期时间重置为 30 秒。
  • 合理预估超时时间:可以进行大量的压测,记录业务的最长耗时、平均耗时等数据。一般来说,设置超时时间为平均耗时加上一定倍数的标准差能较好地应对业务的波动。如平均耗时为 20 秒,标准差为 5 秒,可设置超时时间为 20 + 3×5 = 35 秒,可以应对大多数的业务处理情况。

 

Redisson神技:

RLock lock = redisson.getLock("lock_stock");
lock.lock();  // 自动启动看门狗
try {
    // 业务逻辑
} finally {
    lock.unlock(); // 释放锁并停止续期
}

第5问:高可用场景下的挑战

面试官:如果Redis是主从架构,主节点宕机会怎样?

我:主从异步复制可能导致锁丢失!

例如:

  • 客户端A在主节点加锁成功;
  • 主节点宕机,锁未同步到从节点;
  • 从节点升级为主节点,这个锁在新的主库上,丢失了!

针对这个问题,有一个解决方案是使用 RedLock 算法,它要求在多个独立的 Redis 实例上加锁,只有半数以上的实例加锁成功才算加锁成功。

不过,这个算法也存在争议,Redis 作者 Antirez 认为 RedLock 是安全的,但《分布式系统》作者 Martin 指出它会受到时钟漂移的影响。

面试官:既然RedLock有争议,生产环境到底用不用?

我:慎用! 原因有三点:

  • 性能差:需操作多个Redis实例;
  • 复杂性高:需处理节点故障、时钟同步;
  • 多数场景不需要极端安全:Redis集群+Redisson足够应对99%的业务。

结论:除非是银行转账等业务对锁的正确性和可靠性要求极高,否则不建议用 RedLock。

第6问:突破思维:无锁设计

面试官:最后一个问题——能不能不用分布式锁?

我:能!

锁的本质缺陷:

  • 性能瓶颈:锁粒度越粗,吞吐量越低
  • 复杂度高:需处理网络抖动、脑裂等问题

无锁架构三剑客🗡️: 

1️⃣ 乐观锁(数据库层):

UPDATE order SET status=1, version=version+1 WHERE id=100 AND version=5;

2️⃣  唯一索引:防止重复提交(如订单号唯一索引)

INSERT INTO order (id, user_id) VALUES (1001) 
ON DUPLICATE KEY UPDATE status=1;

3️⃣ 消息队列: 用户请求 → MQ队列 → 单线程消费 → 顺序处理

 

面试官(点头):不错,看得出来你对 Redis 锁研究得十分透彻,回去等通知吧。

最佳实践建议

  1. 技术选型:
    • 一般业务:Redis集群 + Redisson
    • 极高安全要求:考虑RedLock或其他方案
  2. 实践要点:
    • 合理设置锁粒度:按业务ID加锁,而非全局锁
    • 建立监控告警机制:锁等待时间、锁持有时间、死锁检测
    • 完善异常处理流程
  3. 架构建议:
    • 优先考虑无锁设计
    • 在确实需要锁时,使用成熟的实现(如Redisson)
    • 关注业务场景,不过度设计

 

posted @ 2025-05-25 21:35  IT6889  阅读(44)  评论(0)    收藏  举报