Redisson是如何实现分布式锁的?

Redisson 如何实现分布式锁?(核心原理与思考)

Redisson 是一个功能强大的 Redis 客户端,它提供了许多分布式对象和服务,其中就包括分布式锁。Redisson 的分布式锁是基于 Redis 的 Lua 脚本实现的,这保证了操作的原子性。

我们来一步步拆解 Redisson 锁的实现原理

4.1 最基础的 Redis 锁(存在的问题)

如果只用 SETNXDEL

  1. 加锁: SETNX mylock_key my_client_id
    • my_client_id 是一个唯一标识,比如 UUID,用来标识是哪个客户端加的锁。
  2. 解锁: DEL mylock_key

问题:

  • 死锁: 如果客户端加锁后,还没来得及 DEL 就宕机了,那么 mylock_key 永远不会被删除,其他客户端就永远拿不到锁了。
  • 误删: 如果客户端A加锁,但因为网络延迟等原因,锁过期了(被Redis自动删除了),然后客户端B加锁成功。此时客户端A恢复,执行 DEL mylock_key,它删除了客户端B的锁!
4.2 Redisson 的改进:过期时间 + 唯一ID + Lua 脚本

Redisson 解决了上述问题,它的核心思想是:

  1. 加锁时设置过期时间: 避免死锁。
  2. 加锁时设置唯一ID: 避免误删。
  3. 使用 Lua 脚本: 保证加锁和解锁操作的原子性。

Redisson 加锁的 Lua 脚本(简化版):

lua 复制代码
-- KEYS[1]: 锁的名称 (e.g., "myLock")
-- ARGV[1]: 锁的过期时间 (e.g., 30000 毫秒)
-- ARGV[2]: 客户端的唯一ID (e.g., UUID + 线程ID)

-- 如果锁不存在,或者锁是当前客户端加的
if redis.call('exists', KEYS[1]) == 0 or redis.call('hexists', KEYS[1], ARGV[2]) == 1 then
    -- 设置锁,并设置过期时间
    -- HINCRBY: 将哈希表中字段的值增加指定增量。这里是记录重入次数
    redis.call('hincrby', KEYS[1], ARGV[2], 1);
    redis.call('pexpire', KEYS[1], ARGV[1]); -- 设置过期时间 (毫秒)
    return nil; -- 表示加锁成功
end;
return redis.call('pttl', KEYS[1]); -- 返回锁的剩余过期时间,表示加锁失败

Redisson 解锁的 Lua 脚本(简化版):

lua 复制代码
-- KEYS[1]: 锁的名称
-- ARGV[1]: 客户端的唯一ID

-- 如果锁不存在,或者不是当前客户端加的锁
if redis.call('exists', KEYS[1]) == 0 or redis.call('hexists', KEYS[1], ARGV[1]) == 0 then
    return nil; -- 表示解锁失败或锁不存在
end;

-- 减少重入次数
local counter = redis.call('hincrby', KEYS[1], ARGV[1], -1);
-- 如果重入次数归零,说明完全释放了锁
if counter > 0 then
    -- 重新设置过期时间
    redis.call('pexpire', KEYS[1], ARGV[2]); -- ARGV[2] 是新的过期时间
    return 0; -- 表示锁还在,只是重入次数减少
else
    -- 重入次数归零,删除锁
    redis.call('del', KEYS[1]);
    return 1; -- 表示锁已完全释放
end;
return nil;

思考:为什么用 Hash 类型?

  • HINCRBY:这实现了可重入锁。同一个客户端(同一个线程)可以多次获取同一个锁,每次获取都会增加哈希表中对应字段的值(重入次数)。释放锁时,每次减少重入次数,直到为0才真正释放锁。
  • 哈希表的字段是客户端的唯一ID,值是重入次数。
  1. 锁的类型:
    • 可重入锁 (Reentrant Lock): 最常用,上面已解释。
    • 公平锁 (Fair Lock): 保证获取锁的顺序。
    • 联锁 (MultiLock): 同时获取多个 Redis 实例上的锁,只要有一个实例加锁失败,所有已加的锁都会被释放。用于解决 Redis 单点故障问题。
    • 红锁 (RedLock): Redisson 实现了 Redis 官方推荐的 RedLock 算法。它需要多个独立的 Redis Master 节点(至少3个,通常5个)。客户端尝试在大多数(N/2 + 1)Redis 实例上获取锁,才能算成功。这提供了更高的可用性和容错性,但实现更复杂,性能开销也更大。
    • 读写锁 (ReadWriteLock): 允许多个读操作同时进行,但写操作是独占的。
    • 信号量 (Semaphore): 控制并发访问资源的数量。
    • 闭锁 (CountDownLatch): 类似 Java 的 CountDownLatch。
相关推荐
Albert Edison17 小时前
【RabbitMQ】核心概念|工作流程|界面操作
分布式·rabbitmq·ruby
aP8PfmxS21 天前
从零学习Kafka:数据存储
分布式·学习·kafka
必胜刻1 天前
Redis分布式锁讲解
数据库·redis·分布式
少许极端1 天前
消息队列5-RabbitMQ的高级特性和MQ的应用问题与解决方案-事务、消息分发的应用、幂等性保证、顺序性保证、消息积压的解决
分布式·消息队列·rabbitmq
Arva .1 天前
RabbitMQ
网络·分布式·rabbitmq
DYuW5gBmH1 天前
Kafka 成功消费消息的完整流程图
分布式·kafka·流程图
小江的记录本2 天前
【RabbitMQ】RabbitMQ核心知识体系全解(5大核心模块:Exchange类型、消息确认机制、死信队列、延迟队列、镜像队列)
java·前端·分布式·后端·spring·rabbitmq·mvc
电磁脑机2 天前
基于分布式电磁场的双体闭环脑机接口体系与场域认知底层理论
分布式·目标跟踪·重构·架构·交互
电磁脑机2 天前
人类分布式大脑架构与文明、技术、安全的底层逻辑——原创大脑架构理论研究
网络·分布式·神经网络·安全·架构
J2虾虾2 天前
Hadoop入门
大数据·hadoop·分布式