分布式锁
架构设计原则:能不用分布式锁就不用。
但这句话不能停在“经验之谈”,必须理解背后的系统理论。
我给你一个架构级判断框架。
一、先明确:分布式锁的本质是什么?
分布式锁本质是:
在多个进程 / 多实例之间实现互斥访问
它解决的不是一致性问题,而是:
- 资源竞争协调问题
- 并发访问冲突问题
二、为什么“能不用就不用”?
因为分布式锁有天然成本:
|
成本类型
|
说明
|
|
可用性降低
|
锁服务挂了,业务全阻塞
|
|
性能下降
|
所有请求串行化
|
|
死锁风险
|
续期失败或异常
|
|
复杂度
|
需要处理过期、误删、主从切换
|
|
CAP影响
|
Redis锁不保证强一致
|
你加锁,本质是:
主动降低系统吞吐换取互斥
架构设计第一原则是:
提升并发能力,而不是压制并发
三、什么时候必须用分布式锁?
只有在以下三种场景之一成立时。
① 跨资源协调(无法通过数据库事务解决)
例如:
- 同时操作数据库 + 文件系统
- 数据库 + 第三方接口
- 数据库 + MQ
例如:
扣库存发送短信调用外部支付接口
你无法用一个本地事务包住。
必须通过“互斥”避免重复执行。
② 全局唯一执行任务
典型场景:
- 定时任务集群
- 批处理Job
- 数据迁移脚本
例如:
10个服务实例
只允许1个执行定时任务
这时分布式锁是合理的。
③ 非结构化共享资源
例如:
- 生成全局编号
- 操作共享缓存结构
- 操作共享内存结构
数据库无法约束时。
四、什么时候不应该使用分布式锁?
这是架构师必须掌握的。
❌ 1. 可以用数据库唯一索引解决
例如:
防止重复订单
UNIQUE(userId, productId)
强一致
无锁
高可靠
优于Redis锁。
❌ 2. 可以用状态机 + 乐观锁解决
例如库存扣减:
update stockset count = count - 1where id = 1 and count > 0
这是CAS模式。
比加锁高效。
核心思想:
用“当前状态”作为并发控制条件
比如:
update Expenseset Status = 'Processing'where BusinessId = @idand Status = 'Init'
影响行数:
- =1 → 成功(说明没人改过)
- =0 → 失败(说明已被修改)
这就天然实现了:
- 并发控制
- 幂等
- 互斥
而且没有真正“锁住”任何东西。
❌ 3. 可以用幂等设计解决
前端给唯一id 后端数据库表增加唯一约束 通过数据库来解决
这是金融系统标准方案。
❌ 4. 高并发场景
秒杀系统如果加分布式锁:
直接废掉吞吐。
应该使用:
- 预扣库存
- 队列削峰
- 原子扣减
五、架构判断流程(建议你记住)
当你遇到并发问题时:
第一步:能不能用数据库约束?
- 唯一索引?
- 行级锁?
- 乐观锁?
如果能,用数据库。
第二步:能不能用幂等?
- Token
- 状态机
- 版本号
如果能,用幂等。
第三步:是否必须跨实例互斥?
如果必须:
再考虑分布式锁。
六、架构师级认知
分布式锁不是一致性工具。
真正的一致性靠:
- 事务
- 唯一约束
- 状态机
- 消息最终一致性
分布式锁只是:
降低冲突概率的协调机制
这点非常重要。
七、你现在销账系统的情况
你当前:
- 单数据库
- 强一致要求
- 业务ID唯一
结论:
你根本不需要 Redis 分布式锁。
数据库已经是最强锁。
八、什么时候我会用Redis锁?
我会用在:
- 集群定时任务
- 防止缓存击穿
- 防止某段代码并发执行
而不会用在:
- 金融核心交易
- 强一致账务系统
九、面试高级回答模板
如果面试官问:
架构设计时是否必须用分布式锁?
你可以回答:
分布式锁属于最后手段。
优先考虑数据库约束、乐观锁或幂等设计。
只有在跨实例、跨资源、无法通过事务解决的互斥场景下才会使用。
并且根据一致性要求选择 Redis 或 ZooKeeper。
这就是架构思维。
十、送你一句核心判断
如果你的系统还能用数据库事务解决问题,就不要引入分布式锁。
本文来自博客园,作者:12不懂3,转载请注明原文链接:https://www.cnblogs.com/LZXX/p/19673692

浙公网安备 33010602011771号