回顾分布式锁

Table of Contents

Distributed Lock by redis

一、为什么需要分布式锁?

在分布式系统中,当多个进程/服务需要共享同一资源时,本地锁无法跨进程生效。分布式锁通过一个全局可见的"锁资源"实现互斥访问,保证同一时刻只有一个客户端能操作共享资源。


二、Redis实现分布式锁的核心方法

1. 基本加锁操作

使用SET命令的原子性参数实现:

SET lock_key unique_value EX 30 NX
  • NX:仅当键不存在时设置成功(实现互斥)
  • EX 30:设置30秒自动过期(防止死锁)
  • unique_value:唯一标识(如UUID),用于安全释放锁

2. 释放锁的正确姿势

通过Lua脚本保证原子性验证和删除:

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

避免误删其他客户端的锁(例如:客户端A的锁过期后,B获取锁,此时A误删B的锁)。


三、高级特性与问题解决

1. 锁续期(看门狗机制)

  • 问题:任务执行时间超过锁过期时间,导致锁提前释放。
  • 解决:Redisson等客户端通过后台线程定期续期(如每10秒续期一次)。

2. 可重入锁实现

  • 原理:记录持有锁的客户端和重入次数。
  • 示例
    local counter = redis.call("HGET", KEYS[1], ARGV[1])
    if counter then
    redis.call("HINCRBY", KEYS[1], ARGV[1], 1)
    return 1
    else
    return 0
    end

    通过哈希表保存线程标识和重入次数。


四、RedLock算法(多节点容错)

1. 适用场景

当Redis使用主从架构时,主节点故障可能导致锁丢失。RedLock通过在多个独立节点上获取锁来增强可靠性。

2. 实现步骤

  1. 客户端向N个Redis节点依次请求加锁。
  2. 当从大多数节点(N/2+1)获取锁成功时,总耗时需小于锁的有效时间。
  3. 若加锁失败,需向所有节点发送释放锁请求。

3. 争议点

  • 时钟同步问题:节点间时钟不同步可能导致锁过期时间计算错误。
  • 性能成本:需要至少3个独立节点,实现复杂,需权衡收益。

五、与其他方案的对比

方案 优点 缺点 适用场景
Redis锁 高性能,实现简单 依赖Redis可用性 高并发短期任务
ZooKeeper 强一致性,自动释放 性能较低,依赖ZK集群 强一致性要求的场景
数据库锁 无需额外组件 性能差,死锁风险高 低频简单场景

六、最佳实践建议

  1. 优先使用成熟客户端:如Redisson,避免重复造轮子。
  2. 设置合理的过期时间:根据业务耗时动态调整。
  3. 避免单点故障:使用Redis Sentinel或Cluster模式。
  4. 明确一致性需求:若需强一致性,考虑ZooKeeper方案。

七、典型错误案例

  • 未设置超时时间:客户端崩溃导致锁永久占用。
  • 非原子性操作:分开执行SETNXEXPIRE可能导致死锁。
  • 误删其他客户端锁:释放时未验证唯一标识。

通过上述方法,Redis分布式锁可在大多数场景下安全使用。更详细实现可参考Redis官方文档

file

Reference

Comments |0|

Legend *) Required fields are marked
**) You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
Category: 程序人生