### **1. 数据库实现分布式锁**
#### **核心原理**
1. **基于唯一约束的悲观锁**
- 创建一张锁表(如 `distributed_lock`),字段包含锁名称(`lock_key`)和唯一索引。
- 客户端尝试插入一条记录(如 `INSERT INTO distributed_lock (lock_key) VALUES ('order_lock')`)。
- 若插入成功,表示获取锁;若插入失败(唯一约束冲突),表示锁已被占用。
2. **基于乐观锁(版本号或 CAS)**
- 使用版本号字段,更新锁时检查版本号是否匹配:
```sql
UPDATE distributed_lock SET version = version + 1
WHERE lock_key = 'order_lock' AND version = current_version;
```
- 若影响行数大于 0,表示获取锁成功。
3. **超时机制**
- 为锁记录添加过期时间字段,通过定时任务清理超时锁。
#### **优缺点**
- **优点**:
- 实现简单,依赖现有数据库,无需额外组件。
- 强一致性(基于事务)。
- **缺点**:
- 性能差(频繁的数据库 I/O)。
- 死锁风险(客户端崩溃后锁未释放)。
- 需额外处理锁超时和续约逻辑。
---
### **2. Redis 实现分布式锁**
#### **核心原理**
1. **SETNX + EXPIRE(单节点)**
- 使用 `SET key value NX PX milliseconds` 命令原子性地设置键值对和过期时间。
```redis
SET lock:order 12345 NX PX 30000 # 仅当 key 不存在时设置,过期时间 30 秒
```
- 释放锁时通过 Lua 脚本验证值匹配后删除:
```lua
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
```
2. **RedLock 算法(多节点)**
- 向多个 Redis 节点(奇数个)依次申请锁,超过半数节点成功且总耗时小于锁超时时间才算成功。
- 解决单点故障问题,但实现复杂(需处理时钟漂移、节点崩溃等边界条件)。
#### **优缺点**
- **优点**:
- 高性能(内存操作,微秒级响应)。
- 支持自动过期,避免死锁。
- **缺点**:
- 单节点 Redis 存在脑裂风险(主从切换时锁丢失)。
- RedLock 算法争议较大(时钟同步、GC 停顿等问题)。
- 最终一致性模型,极端场景可能锁失效。
---
### **3. ZooKeeper 实现分布式锁**
#### **核心原理**
1. **临时顺序节点(Fair Lock)**
- 客户端在锁路径下创建临时顺序节点(如 `/locks/order_lock_00000001`)。
- 获取所有子节点,检查自己是否为最小节点。若是,则获得锁;否则监听前一个节点的删除事件。
2. **临时节点(Non-Fair Lock)**
- 客户端直接创建临时节点(如 `/locks/order_lock`),若节点已存在则监听其删除事件。
3. **Watch 机制**
- 通过 ZooKeeper 的 Watcher 监听节点变化,前序节点释放锁后触发回调,重新尝试获取锁。
#### **优缺点**
- **优点**:
- 强一致性(基于 ZAB 协议)。
- 天然避免死锁(临时节点随会话结束自动删除)。
- 公平锁支持(顺序节点)。
- **缺点**:
- 性能较低(需频繁创建节点和触发 Watcher)。
- 实现复杂(需处理网络闪断、会话超时等异常)。
- 依赖 ZooKeeper 集群的稳定性。
---
### **对比总结**
| **特性** | **数据库** | **Redis** | **ZooKeeper** |
|-------------------|---------------------------|----------------------------|----------------------------|
| **一致性** | 强一致性(事务) | 最终一致性 | 强一致性(ZAB 协议) |
| **性能** | 低(依赖磁盘 I/O) | 高(内存操作) | 中(网络通信 + 节点操作) |
| **死锁处理** | 需超时机制或人工干预 | 自动过期 | 临时节点自动删除 |
| **实现复杂度** | 简单 | 中等(需处理原子性) | 复杂(需处理 Watcher 机制)|
| **适用场景** | 低并发、强一致性需求 | 高并发、允许短暂不一致 | 高一致性、分布式协调场景 |
---
### **选择建议**
- **数据库锁**:适合低频操作、强一致性且不想引入新组件的场景。
- **Redis 锁**:适合高频读写、允许最终一致性的缓存或业务场景(如秒杀)。
- **ZooKeeper 锁**:适合需要强一致性、高可靠性的分布式协调场景(如金融系统)。
---
### **注意事项**
1. **锁续约**:若业务执行时间超过锁超时时间,需实现锁续约逻辑(如 Redis 的 `watchdog`)。
2. **网络分区**:Redis 可能因脑裂导致锁失效,ZooKeeper 在集群半数存活时仍可用。
3. **公平性**:ZooKeeper 支持公平锁,Redis 和数据库通常是非公平锁。