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。
相关推荐
only-qi3 小时前
微服务场景下,如何实现分布式事务来保证一致性?
分布式·微服务·架构
m0_564876844 小时前
Distributed data parallel (DDP)分布式训练
分布式
BYSJMG5 小时前
计算机毕设选题推荐:基于Hadoop的交通事故数据可视化分析系统
大数据·vue.js·hadoop·分布式·后端·信息可视化·课程设计
野犬寒鸦5 小时前
从零起步学习并发编程 || 第三章:JMM(Java内存模型)详解及对比剖析
java·服务器·开发语言·分布式·后端·学习·spring
虫小宝7 小时前
查券返利机器人的异步任务调度:Java XXL-Job+Redis实现海量查券请求的分布式任务分发
java·redis·分布式
yq1982043011568 小时前
构建高可用资源导航平台:基于Django+Scrapy的分布式架构实践
分布式·scrapy·django
你这个代码我看不懂9 小时前
Kafka常见问题解答
分布式·kafka
Tony Bai9 小时前
Git 即数据库:Beads (bd) —— 专为 AI Agent 打造的分布式任务追踪引擎
数据库·人工智能·分布式·git
小邓睡不饱耶9 小时前
Spark Streaming实时微博热文分析系统:架构设计与深度实现
大数据·分布式·spark
北亚数据恢复9 小时前
分布式数据恢复—Ceph+TiDB数据恢复报告
分布式·ceph·数据恢复·tidb·服务器数据恢复·北亚数据恢复·存储数据恢复