侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

如何基于Redis实现高可用的分布式锁并解决锁失效问题?

2025-12-12 / 0 评论 / 4 阅读

题目

如何基于Redis实现高可用的分布式锁并解决锁失效问题?

信息

  • 类型:问答
  • 难度:⭐⭐

考点

分布式锁原理,Redis实现方案,锁续期机制,高可用设计,原子性操作

快速回答

实现高可用Redis分布式锁的核心要点:

  • 使用SET key random_value NX PX 30000原子命令加锁
  • 通过Lua脚本保证解锁操作的原子性
  • 引入看门狗线程自动续期锁过期时间
  • 使用Redlock算法应对Redis主从故障场景
  • 设置唯一随机值防止误删其他客户端锁
## 解析

一、核心原理

分布式锁需满足:互斥性防死锁容错性。Redis实现依赖:

  • SET NX PX:原子性设置键值+过期时间
  • Lua脚本:保证解锁操作的原子性
  • Redlock:在多个Redis实例上获取锁解决单点故障

二、代码实现示例

1. 加锁实现

public boolean tryLock(Jedis jedis, String lockKey, String clientId, int expireTime) {
    String result = jedis.set(lockKey, clientId, "NX", "PX", expireTime);
    return "OK".equals(result);
}

2. 解锁实现(Lua脚本)

if redis.call("get", KEYS[1]) == ARGV[1] then
    return redis.call("del", KEYS[1])
else
    return 0
end

3. 锁续期(看门狗)

// 后台线程定期续期
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
    if (jedis.get(lockKey).equals(clientId)) {
        jedis.pexpire(lockKey, expireTime); // 重置过期时间
    }
}, 0, expireTime / 3, TimeUnit.MILLISECONDS); // 1/3周期续期

三、最佳实践

  • 唯一客户端ID:使用UUID等随机值,避免误删其他客户端锁
  • 锁续期周期:设置续期间隔 ≤ 过期时间的1/3
  • 超时控制:加锁操作设置网络超时时间
  • Redlock使用场景:在5个独立Redis主节点上获取锁,当≥3个成功时视为加锁成功

四、常见错误

  • 错误1:解锁时未校验客户端ID → 导致误删其他客户端锁
  • 错误2:未设置锁超时 → 客户端崩溃导致死锁
  • 错误3:业务执行时间超过锁过期时间 → 锁提前释放
  • 错误4:单点Redis故障时未启用Redlock → 锁状态不一致

五、扩展知识

  • Redlock算法流程
    1. 获取当前毫秒级时间戳T1
    2. 在N个实例上顺序执行加锁命令
    3. 计算加锁总耗时 = T2 - T1
    4. 当成功数≥N/2+1 且 耗时 < 锁有效时间时加锁成功
  • 其他方案对比
    • Zookeeper:通过临时顺序节点实现,强一致性但性能较低
    • etcd:基于Raft协议,适合CP场景
  • 锁粒度优化:对非冲突资源使用细粒度锁提升并发度