Redisson 分布式锁实现原理

1. 概述

Redisson 是基于 Redis 实现的 Java 分布式锁框架,其核心设计目标是原子性、可重入性、锁续期高效锁竞争处理。通过 Redis 的 Hash 数据结构和 Lua 脚本的原子性操作,Redisson 实现了高性能的分布式锁机制,并解决了传统 setnx 命令的局限性212。

2. 核心实现原理

2.1 加锁流程

Redisson 的加锁通过 Lua 脚本实现原子操作,核心逻辑如下:

-- KEYS[1]: 锁名(如 "myLock")
-- ARGV[1]: 锁超时时间(毫秒)
-- ARGV[2]: 锁标识(UUID:线程ID)

if (redis.call('exists', KEYS[1]) == 0) then
    redis.call('hincrby', KEYS[1], ARGV[2], 1);  -- 首次加锁,计数器设为1
    redis.call('pexpire', KEYS[1], ARGV[1]);     -- 设置锁超时时间
    return nil;
end;
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
    redis.call('hincrby', KEYS[1], ARGV[2], 1);  -- 可重入:计数器+1
    redis.call('pexpire', KEYS[1], ARGV[1]);
    return nil;
end;
return redis.call('pttl', KEYS[1]);              -- 锁被其他线程持有,返回剩余时间

关键点

  • 可重入性:通过 Hash 结构存储锁标识(UUID:ThreadID)和计数器,实现同一线程多次加锁214。

  • 原子性:Lua 脚本保证加锁操作的原子性,避免 setnx + expire 分步操作的风险12。


2.2 解锁流程

解锁同样通过 Lua 脚本实现:

-- KEYS[1]: 锁名,KEYS[2]: 发布订阅的 Channel
-- ARGV[1]: 解锁消息标识,ARGV[2]: 锁超时时间,ARGV[3]: 锁标识

if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then
    return nil;  -- 锁不属于当前线程,拒绝解锁
end;
local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1);  -- 计数器-1
if (counter > 0) then
    redis.call('pexpire', KEYS[1], ARGV[2]);     -- 仍有重入次数,仅续期
    return 0;
else
    redis.call('del', KEYS[1]);                  -- 计数器归零,删除锁
    redis.call('publish', KEYS[2], ARGV[1]);     -- 发布解锁消息
    return 1;
end;

关键点

  • 安全释放:校验锁归属,防止误删其他线程的锁10。

  • 发布订阅机制:解锁时通过 Redis 的 Pub/Sub 通知等待线程重新竞争锁716。


3. 关键机制源码分析

3.1 看门狗(WatchDog)

作用:在未显式指定锁超时时间时,自动续期锁,避免业务未完成时锁过期。
源码实现

  • 续期任务调度:在 scheduleExpirationRenewal 方法中,通过 Netty 的 HashedWheelTimer 创建定时任务,默认每 internalLockLeaseTime/3(10秒)执行一次续期1116。

  • 续期 Lua 脚本

    if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
        redis.call('pexpire', KEYS[1], ARGV[1]);  -- 重置锁超时时间
        return 1;
    end;
    return 0;

3.2 锁竞争处理

当锁被其他线程持有时,当前线程会执行以下逻辑:

  1. 订阅解锁消息:通过 Redis 的 Pub/Sub 订阅锁释放事件,避免轮询消耗资源716。

  2. 自旋尝试加锁:在 tryLock 方法中,结合 Semaphore 实现阻塞等待,直到超时或收到解锁通知1112。


4. 核心类与源码解析

4.1 RedissonLock 类

  • 关键方法

    • tryLockInnerAsync:执行加锁 Lua 脚本214。

    • unlockInnerAsync:执行解锁 Lua 脚本10。

  • 锁标识生成getLockName(threadId) 生成 UUID:ThreadID,确保全局唯一14。

4.2 锁续期与时间轮

  • 时间轮(HashedWheelTimer):Netty 提供的高效定时任务调度器,用于实现锁续期任务的延迟执行16。

  • 任务调度逻辑:在 renewExpiration 方法中递归调用,形成链式续期11。


5. 优缺点与适用场景

5.1 优点

  1. 高可用:支持 Redis 集群模式(需配合 RedLock 算法)12。

  2. 高性能:基于非阻塞的异步通信(Netty)和高效的锁竞争处理916。

  3. 功能丰富:支持可重入锁、公平锁、联锁等多种锁类型12。

5.2 局限性

  1. 集群模式风险:Redis 主从异步复制可能导致锁丢失(需 RedLock 解决)12。

  2. 依赖 Redis:Redis 宕机可能导致锁服务不可用。

Redisson 通过 Lua 脚本、Hash 数据结构、看门狗机制和发布订阅模型,实现了高性能、高可靠的分布式锁。其源码设计充分考虑了原子性、可重入性和锁续期问题,是分布式系统中锁管理的优选方案。对于高并发场景,建议结合 RedLock 算法提升容错性1216。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值