Redis分布式锁详解

Redis分布式锁详解

分布式锁是在分布式系统中实现互斥访问共享资源的重要机制。Redis因其高性能和原子性操作特性,常被用来实现分布式锁。

一、基础实现方案

1. SETNX + EXPIRE方案(基本版)

# 加锁
SETNX lock_key unique_value  # 设置唯一标识
EXPIRE lock_key 10          # 设置过期时间

# 解锁
DEL lock_key                # 删除键

问题

  • 非原子性操作(SETNX和EXPIRE分开执行可能失败)
  • 可能误删其他客户端的锁

2. SET扩展命令方案(推荐)

# 原子性加锁
SET lock_key unique_value NX PX 10000  # NX表示不存在才设置,PX设置毫秒级过期时间

# 解锁(Lua脚本保证原子性)
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

优势

  • 原子性加锁
  • 设置过期时间防止死锁
  • 通过唯一值避免误删

二、Redlock算法(多节点版)

当需要更高可靠性时,Redis作者提出的Redlock算法:

  1. 获取当前时间(毫秒)
  2. 依次尝试从N个独立的Redis节点获取锁
  3. 计算获取锁总耗时(小于锁过期时间)
  4. 当从多数节点(N/2+1)获取成功,且总耗时小于锁有效时间,才认为加锁成功
  5. 若失败,向所有节点发起解锁请求

三、Java实现示例(Redisson)

// 1. 获取锁对象
RLock lock = redissonClient.getLock("myLock");

try {
    
    
    // 2. 尝试加锁(参数:等待时间,锁自动释放时间,时间单位)
    boolean isLocked = lock.tryLock(10, 30, TimeUnit.SECONDS);
    
    if (isLocked) {
    
    
        // 3. 执行业务代码
        doBusiness();
    }
} finally {
    
    
    // 4. 释放锁
    lock.unlock();
}

四、关键问题与解决方案

1. 锁续期(Watchdog机制)

问题:业务执行时间超过锁过期时间
方案:Redisson的看门狗会定期(默认10秒)检查并延长锁时间

2. 可重入性

方案:使用计数器记录重入次数(Redisson已实现)

3. 锁等待与公平性

方案

  • 实现锁等待队列
  • 使用Redis的List结构模拟队列

4. 主从切换问题

问题:主节点崩溃可能导致锁丢失
方案

  • 使用Redlock多节点方案
  • 或使用Redis的WAIT命令确保数据同步

五、生产环境建议

  1. 锁命名规范业务:资源:操作order:123:pay
  2. 超时时间设置
    • 不宜过短(业务未完成锁已释放)
    • 不宜过长(系统故障时恢复慢)
  3. 监控指标
    • 锁获取成功率
    • 平均持有时间
    • 等待队列长度
  4. 降级方案:Redis不可用时切换本地锁或数据库锁

六、与其他方案对比

方案 优点 缺点 适用场景
Redis锁 性能高、实现简单 可靠性依赖Redis 大多数分布式场景
Zookeeper锁 可靠性高 性能较低 强一致性要求场景
数据库锁 无需额外组件 性能差、有死锁风险 简单场景

七、最佳实践

  1. 始终为锁设置合理的过期时间
  2. 使用唯一标识(UUID/线程ID)作为锁值
  3. 释放锁前验证持有者身份
  4. 考虑使用成熟的客户端(如Redisson)而非自己实现
  5. 重要业务实现锁续期机制

Redis分布式锁在大多数场景下能很好工作,但对于对可靠性要求极高的场景,建议考虑Zookeeper或etcd等强一致性协调服务实现的分布式锁。