Redis RedLock 和 ZooKeeper 分布式锁实现方案
以下是 分布式锁的两种主流实现方案(Redis RedLock 和 ZooKeeper) 的详细对比及适用场景分析:
一、分布式锁的核心要求
- 互斥性:同一时刻只有一个客户端持有锁。
- 容错性:锁服务需具备高可用(即使部分节点宕机,锁功能仍正常)。
- 避免死锁:持有锁的客户端崩溃后,锁能自动释放。
- 可重入性(可选):同一客户端可多次获取同一把锁。
二、Redis RedLock 分布式锁
1. 实现原理
RedLock 算法基于多个独立的 Redis 节点(通常 5 个),通过 多数派原则 确保锁的安全性:
- 获取锁:
- 客户端向所有 Redis 节点发送
SET key random_value NX PX 30000
(随机值 + 超时时间)。 - 若超过半数(N/2 +1)节点成功设置,则视为获取锁成功。
- 释放锁:
- 向所有节点发送 Lua 脚本,仅当值匹配时删除键(避免误删其他客户端的锁)。
2. 关键代码示例
python
# 获取锁
def acquire_lock(servers, resource, ttl):
val = str(uuid.uuid4())
success_count = 0
for server in servers:
if server.set(resource, val, nx=True, px=ttl):
success_count += 1
if success_count > len(servers) // 2:
return val # 锁获取成功
else:
# 释放已获取的锁
release_lock(servers, resource, val)
return None
# 释放锁(Lua 脚本保证原子性)
def release_lock(servers, resource, val):
script = """
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
"""
for server in servers:
server.eval(script, 1, resource, val)
3. 优点
- 高性能:基于内存操作,吞吐量高。
- 容错性:半数节点存活即可工作。
4. 缺点
- 时钟依赖:依赖系统时钟一致性,时钟跳跃可能导致锁失效。
- 网络延迟风险:若客户端因 GC 停顿导致锁过期,可能引发并发问题。
5. 适用场景
- 高并发、低延迟:如秒杀库存扣减、分布式任务调度。
- 允许极低概率的锁冲突:对一致性要求稍宽松的场景。
三、ZooKeeper 分布式锁
1. 实现原理
基于 ZooKeeper 的 临时顺序节点(Ephemeral Sequential Node) 和 Watcher 机制:
- 获取锁:
- 客户端在锁路径下创建临时顺序节点(如
/locks/resource_00000001
)。 - 检查自己是否是最小序号节点,若是则获取锁;否则监听前一个节点的删除事件。
- 释放锁:
- 客户端主动删除节点,或会话超时后 ZooKeeper 自动删除临时节点。
2. 关键代码示例(Curator 框架)
java
InterProcessMutex lock = new InterProcessMutex(client, "/locks/resource");
try {
if (lock.acquire(30, TimeUnit.SECONDS)) {
// 执行业务逻辑
}
} finally {
lock.release();
}
3. 优点
- 强一致性:ZooKeeper 的 Zab 协议保证数据一致性。
- 无时钟依赖:基于会话机制,避免时钟问题。
- 自动释放:客户端崩溃后,临时节点自动删除。
4. 缺点
- 性能较低:写操作需集群同步,吞吐量低于 Redis。
- 运维复杂度:需维护 ZooKeeper 集群。
5. 适用场景
- 强一致性要求:如金融交易、配置管理。
- 长事务场景:客户端需长时间持有锁(依赖会话心跳机制)。
四、对比总结
维度 | Redis RedLock | ZooKeeper |
---|---|---|
一致性 | 最终一致性(可能锁冲突) | 强一致性(CP 系统) |
性能 | 高(10k+ QPS) | 中(1k~5k QPS) |
容错性 | 半数节点存活即可工作 | 半数节点存活即可工作 |
锁释放机制 | 依赖超时自动释放 | 临时节点自动释放 + 客户端主动释放 |
实现复杂度 | 需处理时钟漂移、锁续期 | 依赖 ZooKeeper 原生特性,实现简单 |
适用场景 | 高并发、允许偶发锁失效 | 强一致性、长事务、复杂协调场景 |
五、选型建议
- 优先选择 Redis RedLock:
- 需要高吞吐、低延迟。
- 接受极小概率的锁失效(如缓存更新、限流控制)。
- 优先选择 ZooKeeper:
- 要求强一致性、锁绝对可靠(如订单支付、库存扣减)。
- 需要监听锁状态变化(如 Master 选举)。
- 混合使用:
- 核心业务用 ZooKeeper 保证强一致性。
- 非核心业务用 Redis 提升性能。
六、避坑指南
1. Redis RedLock 注意事项
- 时钟同步:确保所有 Redis 节点使用 NTP 同步时钟。
- 锁续期:通过看门狗线程(如 Redisson 的
lockWatchdogTimeout
)定期续期,避免业务未完成锁过期。
2. ZooKeeper 注意事项
- 会话超时:合理设置
sessionTimeout
(默认 60s),避免网络波动导致锁释放。 - 重试策略:处理
ConnectionLossException
等异常,确保锁操作幂等性。
3. 通用建议
- 锁粒度:尽量细化锁的粒度(如按资源 ID 加锁)。
- 监控告警:跟踪锁等待时间、持有时间,及时发现死锁或性能瓶颈。