一、为什么需要分布式锁
1. 单机锁局限
synchronized、Lock 属于JVM 本地锁,只在单个 JVM 进程内生效。 集群部署,多个服务实例(多个 JVM),本地锁互相感知不到,锁失效。
业务场景:一人一单,集群环境下本地锁无法拦截,用户可以重复下单优惠券。
2. 分布式锁定义
分布式锁:集群 / 分布式环境,多进程之间可见、能够实现互斥的锁。 核心五大特性:
- 多进程可见:不同服务实例都能访问锁
- 互斥:同一时刻,只允许一个客户端拿到锁
- 高性能:获取、释放锁速度快,支持高并发
- 高可用:锁服务故障不能直接导致业务瘫痪
- 安全性:锁可以释放,不会死锁
二、分布式锁三种实现方案对比
表格
| 方案 | 互斥实现 | 高可用 | 高性能 | 安全(死锁防护) |
|---|---|---|---|---|
| MySQL | 数据库锁机制 | 好 | 一般 | 断开数据库连接自动释放锁 |
| Redis | SETNX互斥命令 |
好 | 好 | 设置锁超时时间,到期自动释放 |
| Zookeeper | 临时有序节点 | 好 | 一般 | 客户端断开连接,临时节点自动删除释放锁 |
- MySQL:性能偏弱,适合并发不高场景
- Redis:性能最优,互联网项目最常用
- Zookeeper:可靠性强,性能一般
三、Redis 实现基础分布式锁
1. 获取锁
- 命令:
SET key value NX EX 过期时间 NX:互斥,key 不存在才创建,存在直接失败,实现非阻塞;尝试一次,成功拿到锁,失败直接返回,不等待EX:设置锁超时时间,防止服务宕机锁无法释放,造成死锁
2. 释放锁
- 手动释放:删除锁 key
- 自动释放:达到 EX 设置的超时时间,Redis 自动删除 key
3. 基础执行流程
- 尝试获取锁
- 获取失败 → 直接结束业务
- 获取成功 → 执行业务逻辑
- 业务完成 → 手动释放锁