题目
设计高并发场景下的分布式锁服务,并解决锁超时与续约问题
信息
- 类型:问答
- 难度:⭐⭐⭐
考点
分布式锁原理,高可用设计,锁超时与续租机制,死锁预防
快速回答
在高并发分布式系统中实现分布式锁需解决以下核心问题:
- 互斥性:确保同一时刻只有一个客户端持有锁
- 锁超时:通过TTL避免死锁,需设置合理过期时间
- 续约机制:使用看门狗线程或租约续期保证长任务执行
- 高可用:基于Redis Cluster/Redlock或ZooKeeper实现
- 容错处理:处理网络分区、节点故障等异常场景
1. 核心设计原理
分布式锁需满足:互斥性、避免死锁、容错性。常用实现方案:
- Redis方案:SET key random_value NX PX 30000
- ZooKeeper方案:创建有序临时节点
- ETCD方案:基于租约(Lease)的KV存储
2. 锁超时与续约机制
问题场景:任务执行时间超过锁TTL导致锁失效
解决方案:
// Redis看门狗示例(Redisson实现)
RLock lock = redisson.getLock("orderLock");
lock.lock(30, TimeUnit.SECONDS); // 设置初始TTL
// 后台线程每10秒续期
Thread watchdog = new Thread(() -> {
while (isRunning) {
if (lock.isHeldByCurrentThread()) {
// 异步续期
redis.expire(lockKey, 30, TimeUnit.SECONDS);
}
Thread.sleep(10000);
}
});
watchdog.start();续约要点:
- 续期操作需保证幂等性
- 客户端崩溃时自动释放锁(通过TTL)
- 续期失败应主动中断任务
3. 高可用架构设计
Redis Redlock算法:
- 向5个独立Redis实例发送加锁请求
- 当获得≥3个成功响应时认为加锁成功
- 总耗时需小于锁TTL的1/3
ZooKeeper方案优势:
- 临时节点自动删除保障锁释放
- Watcher机制实现阻塞等待
- ZAB协议保证强一致性
4. 常见错误与防御
| 错误类型 | 后果 | 解决方案 |
|---|---|---|
| 未设置唯一标识 | 误删其他客户端锁 | 使用UUID/ThreadID作为value |
| 未处理网络延迟 | 锁失效后仍操作资源 | 增加fencing token机制 |
| 单点故障 | 服务不可用 | 采用多节点部署+故障转移 |
5. 最佳实践
- 锁粒度控制:按资源ID细分锁(如order_123)
- 超时时间:设置TTL为平均任务耗时的2-3倍
- 降级方案:锁服务不可用时切本地锁+告警
- 监控:锁等待时间、续约失败率等关键指标
6. 扩展知识:脑裂问题处理
当发生网络分区时:
- Redis Redlock依赖NTP时间同步
- ZooKeeper通过epoch机制拒绝旧leader请求
- ETCD使用Raft算法保证分区容错性
推荐方案选择:
- CP场景:ZooKeeper/ETCD
- AP场景:Redis Cluster
- 超高并发:Redis分片+Redlock