深入浅出Redission

在Java分布式系统开发中,Redis的应用无处不在,但你是否也曾遇到这些痛点:用原生Redis命令实现分布式锁时反复踩坑死锁与锁超时问题?手写分布式集合操作时难以保证原子性?面对高并发场景,Redis客户端通信效率瓶颈明显?

今天要介绍的Redission,正是为解决这些问题而生的“瑞士军刀”。它不是简单的Redis客户端封装,而是一套完整的分布式应用开发框架。

一、Redission到底是什么

很多人会把Redission和Jedis、Lettuce归为一类,这其实是个误区。准确来说:

Redission是基于Redis实现的Java分布式应用开发框架,它以Redis为底层存储,封装了分布式锁、分布式集合、分布式信号量等数十种分布式场景核心功能,同时通过底层通信优化实现高性能交互。

简单对比三者的定位:

组件核心定位适用场景
JedisRedis原生命令的Java实现(BIO模型)简单Redis操作、低并发场景
Lettuce基于Netty的异步Redis客户端高并发场景下的基础Redis操作
Redission分布式功能框架(内置Lettuce核心)分布式锁、分布式集合等复杂场景
一句话总结:用Jedis/Lettuce是“操作Redis”,用Redission是“基于Redis开发分布式系统”。

二、网络通信模型

Redission底层网络模型基于Netty(Java NIO),关于Java NIO可以看我的另一篇:https://blog.youkuaiyun.com/Tracycoder/article/details/155450115

网络通信模型的这种设计和实现为Redission的高效性能打下了坚实的基础。

三、分布式锁的实现

Redission 是基于 Redis 实现的分布式服务框架,其核心优势之一是提供了丰富的分布式锁实现,覆盖了绝大多数业务场景(可重入、公平、联锁、红锁等)。这些锁的底层依赖 Redis 的数据结构(Hash、ZSet、String)和 Lua 脚本(保证原子性),并解决了原生 Redis 分布式锁的诸多痛点(如重入性、自动续期、死锁避免等)。

3.1 Redission 分布式锁的核心特性

所有 Redission 分布式锁都具备以下基础能力,无需手动实现:

  1. 原子性:通过 Lua 脚本将「判断-加锁-解锁」等操作打包执行,避免并发竞态条件;
  2. 可重入性:支持同一线程多次加锁,通过计数器记录重入次数;
  3. 自动续期(看门狗机制):默认锁过期时间 30 秒,若业务未执行完,会每隔 10 秒自动续期,避免锁提前释放;
  4. 阻塞/非阻塞支持:支持 lock()(阻塞等待)和 tryLock()(非阻塞,超时返回);
  5. 死锁避免:锁自带过期时间,即使服务宕机,Redis 也会自动释放锁;
  6. 集群适配:支持 Redis 单机、主从、哨兵、Cluster 集群模式,保证高可用。

3.2 Redission 主要分布式锁类型及实现原理

1. 可重入锁(ReentrantLock)- 最常用

  • 特点

    • 分布式环境下的「可重入互斥锁」,类比 Java 的 ReentrantLock
    • 同一线程可多次加锁,解锁需对应次数(重入计数器减为 0 才释放锁);
    • 适用于:大多数分布式互斥场景(如订单创建、库存扣减)。
  • 实现原理
    基于 Redis 的 Hash 数据结构 存储锁信息,Lua 脚本保证加锁/解锁原子性。

  • 加锁流程

  1. 锁的 Redis Key 格式:redisson_lock:{锁名称}(如 redisson_lock:order_create);
  2. Hash 结构的 Field 为「当前线程标识(UUID+线程ID)」,Value 为「重入次数」;
  3. 执行 Lua 脚本:
    • 若锁不存在:创建 Hash 并设置 Field=线程标识,Value=1,同时设置 Key 过期时间(默认 30 秒);
    • 若锁已存在且 Field 是当前线程:重入次数 +1,重置过期时间;
    • 若锁已存在且 Field 是其他线程:返回失败,进入阻塞等待(或直接返回,取决于 lock()/tryLock())。
  • 解锁流程
    执行 Lua 脚本:

    • 若锁不存在:直接返回成功;
    • 若锁存在但 Field 不是当前线程:返回失败(非法解锁);
    • 若锁存在且 Field 是当前线程:重入次数 -1,若减为 0 则删除锁 Key(释放锁),否则仅重置过期时间。
  • 核心 Lua 脚本(加锁)

-- 若锁不存在,创建锁(重入次数=1)
if (redis.call('exists', KEYS[1]) == 0) then
    redis.call('hset', KEYS[1], ARGV[2], 1);
    redis.call('pexpire', KEYS[1], ARGV[1]);
    return 1;
end;
-- 若锁已存在且属于当前线程,重入次数+1
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
    redis.call('hincrby', KEYS[1], ARGV[2], 1);
    redis.call('pexpire', KEYS[1], ARGV[1]);
    return 1;
end;
-- 其他情况,加锁失败
return 0;
  • 代码示例
RLock lock = redissonClient.getLock("order_create_lock");
try {
    // 阻塞加锁(默认30秒过期,自动续期)
    lock.lock();
    // 业务逻辑:创建订单、扣减库存...
} finally {
    // 必须解锁(若重入多次,需对应解锁多次)
    lock.unlock();
}

2. 公平锁(FairLock)

  • 特点

    • 分布式环境下的「公平互斥锁」,保证线程获取锁的顺序与请求顺序一致(FIFO);
    • 避免「饥饿问题」(某个线程长期无法获取锁);
    • 适用于:对获取锁顺序有要求的场景(如任务队列、优先级任务执行)。
  • 实现原理
    基于 Redis 的 ZSet(有序集合)+ Hash 实现,ZSet 用于维护等待队列(按请求时间排序),Hash 存储锁信息。

  • 核心设计

  1. 等待队列:ZSet 的 Key 为 redisson_lock_queue:{锁名称},Score 为「请求时间戳」,Value 为「线程标识」,保证 FIFO 顺序;
  2. 加锁流程:
    • 先尝试加锁(逻辑同可重入锁);
    • 若加锁失败,将当前线程加入 ZSet 等待队列,并通过 Redis 的 BLPOP 阻塞等待(监听前一个线程的释放信号);
  3. 解锁流程:
    • 释放锁后,从 ZSet 中取出下一个等待线程,通过 PUBLISH 发送信号唤醒,使其尝试加锁。
  • 注意
    公平锁的性能略低于可重入锁(需维护等待队列),非必要场景不建议使用。

3. 联锁(MultiLock)

  • 特点

    • 「多锁联动」,需同时获取所有子锁才算加锁成功,只要有一个子锁获取失败,所有已获取的子锁会自动释放;
    • 适用于:需要同时锁定多个资源的场景(如转账:需同时锁定转出账户和转入账户)。
  • 实现原理
    基于「组合模式」,内部维护一个子锁列表(RLock[]),通过原子操作保证多锁的一致性。

  • 加锁流程

  1. 按顺序尝试获取每个子锁(默认超时时间为总超时时间的 1/子锁数量);
  2. 若所有子锁都获取成功,返回加锁成功;
  3. 若某个子锁获取失败,立即释放已获取的所有子锁(避免死锁);
  4. 支持自动续期(所有子锁同时续期)。
  • 代码示例
// 定义两个子锁(锁定转出账户和转入账户)
RLock lock1 = redissonClient.getLock("account_lock:userA");
RLock lock2 = redissonClient.getLock("account_lock:userB");

// 创建联锁
RLock multiLock = redissonClient.getMultiLock(lock1, lock2);

try {
    // 必须同时获取两个锁才会继续执行(超时 5 秒,leaseTime -1 表示自动续期)
    multiLock.tryLock(5, -1, TimeUnit.SECONDS);
    // 业务逻辑:转账操作...
} finally {
    multiLock.unlock();
}

4. 红锁(RedLock)- 高可用锁

  • 特点

    • 基于 Redis 集群的「高可用互斥锁」,解决单节点/主从切换导致的锁失效问题;
    • 需向 多个独立的 Redis 节点(推荐 3-5 个)同时加锁,超过半数节点加锁成功才算整体加锁成功;
    • 适用于:对锁可用性要求极高的场景(如金融交易、核心数据修改)。
  • 实现原理
    遵循 Redis 作者提出的「RedLock 算法」,核心是「少数服从多数」,避免单节点故障导致锁丢失。

  • 加锁流程

  1. 客户端向所有独立 Redis 节点(无主从关系)发送加锁请求(每个节点的锁 Key 相同,线程标识相同);
  2. 每个节点的加锁逻辑同「可重入锁」,但不依赖主从复制(节点独立);
  3. 客户端统计加锁成功的节点数,若成功数 > 节点总数/2(如 3 个节点需 2 个成功),且总耗时未超过超时时间,则加锁成功;
  4. 若加锁失败,立即向所有节点发送解锁请求(释放已加的锁)。
  • 解锁流程

    • 向所有节点发送解锁请求(无论该节点是否加锁成功),确保所有节点的锁都被释放。
  • 代码示例

// 配置 3 个独立的 Redis 节点(无主从关系)
Config config1 = new Config();
config1.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient client1 = Redisson.create(config1);

Config config2 = new Config();
config2.useSingleServer().setAddress("redis://127.0.0.1:6380");
RedissonClient client2 = Redisson.create(config2);

Config config3 = new Config();
config3.useSingleServer().setAddress("redis://127.0.0.1:6381");
RedissonClient client3 = Redisson.create(config3);

// 创建红锁(传入 3 个节点的锁)
RLock lock1 = client1.getLock("redlock:finance");
RLock lock2 = client2.getLock("redlock:finance");
RLock lock3 = client3.getLock("redlock:finance");

RLock redLock = Redisson.createRedLock(lock1, lock2, lock3);

try {
    // 加锁:超时 5 秒,锁过期 30 秒(自动续期)
    boolean success = redLock.tryLock(5, 30, TimeUnit.SECONDS);
    if (success) {
        // 业务逻辑:金融交易...
    }
} finally {
    redLock.unlock();
}
  • 注意
    • 红锁的性能略低(需访问多个节点),且需要独立的 Redis 节点(不能是同一集群的从节点),部署成本较高。

5. 读写锁(ReadWriteLock)

  • 特点

    • 分布式环境下的「共享-排他锁」,类比 Java 的 ReentrantReadWriteLock
    • 读锁(共享锁):多个线程可同时获取,互不阻塞;
    • 写锁(排他锁):仅一个线程可获取,阻塞所有读锁和写锁;
    • 适用于:「读多写少」场景(如商品详情查询、数据统计,写操作仅在更新时执行)。
  • 实现原理
    基于 Redis 的 两个 Hash 结构 分别存储读锁和写锁信息,通过 Lua 脚本保证读写互斥逻辑。

  • 核心规则

    • 写锁加锁:需确保当前无读锁和其他写锁;
    • 读锁加锁:需确保当前无写锁;
    • 写锁优先级高于读锁(默认,可配置):当有写锁等待时,后续读锁会阻塞,避免写锁饥饿。
  • 代码示例

RReadWriteLock rwLock = redissonClient.getReadWriteLock("product_rw_lock");
RLock readLock = rwLock.readLock(); // 读锁
RLock writeLock = rwLock.writeLock(); // 写锁

// 读操作(共享锁)
try {
    readLock.lock();
    // 业务逻辑:查询商品详情...
} finally {
    readLock.unlock();
}

// 写操作(排他锁)
try {
    writeLock.lock();
    // 业务逻辑:更新商品价格...
} finally {
    writeLock.unlock();
}

6. 信号量(Semaphore)

  • 特点

    • 分布式环境下的「信号量」,控制并发访问的资源数量(类比 Java 的 Semaphore);
    • 支持「获取许可」和「释放许可」,许可数量可动态调整;
    • 适用于:限流场景(如限制同时访问某个接口的线程数)、资源池控制(如限制数据库连接数)。
  • 实现原理
    基于 Redis 的 String 数据结构 存储许可数量,Lua 脚本保证许可操作的原子性。

  • 核心流程

  1. 初始化:设置信号量的许可数量(如 semaphore:limit = 10,表示最多 10 个并发);
  2. 获取许可:acquire()tryAcquire(),将许可数量 -1,若为负数则阻塞(或返回失败);
  3. 释放许可:release(),将许可数量 +1,唤醒阻塞的线程。
  • 代码示例
RSemaphore semaphore = redissonClient.getSemaphore("api_limit_semaphore");
// 初始化许可数量(可选,若未初始化则默认为 0)
semaphore.trySetPermits(10);

try {
    // 获取 1 个许可(阻塞等待,直到有可用许可)
    semaphore.acquire();
    // 业务逻辑:接口处理...
} finally {
    // 释放 1 个许可
    semaphore.release();
}

// 非阻塞获取(超时 3 秒,获取 2 个许可)
boolean success = semaphore.tryAcquire(2, 3, TimeUnit.SECONDS);
if (success) {
    try {
        // 业务逻辑...
    } finally {
        semaphore.release(2);
    }
}

7. 可过期信号量(PermitExpirableSemaphore)

  • 特点

    • 增强版信号量,每个许可带有「过期时间」;
    • 适用于:临时资源占用场景(如临时占用服务器端口、临时锁定某个任务,超时自动释放)。
  • 实现原理
    基于 Redis 的 ZSet 数据结构 存储许可(Score 为过期时间戳,Value 为许可 ID),通过 Lua 脚本清理过期许可并分配新许可。

8. 闭锁(CountDownLatch)

  • 特点

    • 分布式环境下的「闭锁」,类比 Java 的 CountDownLatch
    • 一个线程等待其他多个线程完成操作后,再继续执行;
    • 适用于:分布式任务协调(如分布式计算的汇总任务,等待所有分片任务完成后再统计结果)。
  • 实现原理
    基于 Redis 的 Hash 数据结构 存储计数器,结合 Redis 的「发布-订阅」机制唤醒等待线程。

  • 核心流程

  1. 初始化:设置计数器值(如 countdown:task = 3,表示需要 3 个任务完成);
  2. 任务线程:执行完后调用 countDown(),计数器 -1;
  3. 等待线程:调用 await() 阻塞,直到计数器减为 0,通过 Redis 订阅消息唤醒。
  • 代码示例
RCountDownLatch latch = redissonClient.getCountDownLatch("task_coordinate_latch");
// 初始化计数器为 3(3 个任务需要完成)
latch.trySetCount(3);

// 等待线程(如汇总线程)
new Thread(() -> {
    try {
        // 阻塞等待,直到计数器为 0
        latch.await();
        // 所有任务完成,执行汇总逻辑...
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}).start();

// 任务线程 1
new Thread(() -> {
    // 业务逻辑:任务 1 执行...
    latch.countDown(); // 计数器减 1
}).start();

// 任务线程 2、3 同理...

3.3 分布式锁的分布式机制实现

锁Key的「哈希槽路由集中化」:避免锁分散

Redis Cluster 采用「哈希槽分片」(16384 个槽),每个主节点负责部分槽位,Key 按 CRC16(Key) % 16384 计算槽位,路由到对应主节点。
Redission 为了避免「同一把锁的 Key 分散到多个节点」,做了关键设计:
同一把分布式锁的所有操作(加锁、解锁、续期),都强制路由到「同一个 Redis 主节点」

  • 具体实现:

    • 锁的 Key 格式固定(如 redisson_lock:{锁名称}),Redission 不修改 Key 的哈希计算逻辑,而是依赖 Redis Cluster 的路由规则:
      同一把锁的 Key 经过 CRC16 计算后,始终映射到同一个哈希槽,进而路由到同一个主节点。
    • 所有客户端操作这把锁时,都会被 Redis Cluster 路由到该主节点,相当于「锁的集中存储」,避免了锁在多个节点分散导致的互斥失效。
  • 举例:
    锁名称为 order_lock,Key 是 redisson_lock:order_lock

    • 客户端 A 连接 Cluster 节点 1,计算 Key 的槽位为 1234,路由到主节点 3;
    • 客户端 B 连接 Cluster 节点 2,计算同一 Key 的槽位仍为 1234,同样路由到主节点 3;
    • 所有客户端的加锁/解锁操作都在主节点 3 执行,保证了锁的「全局互斥」—— 这是集群环境下锁分布性的基础。

3.4 核心共性总结

所有 Redission 分布式锁的底层设计都围绕以下 3 点:

  1. Redis 数据结构:根据锁的特性选择合适的结构(Hash 用于重入锁、ZSet 用于公平锁/可过期信号量、String 用于信号量);
  2. Lua 脚本:保证加锁、解锁、计数器修改等操作的原子性,避免并发问题;
  3. 看门狗机制:针对互斥锁(可重入锁、公平锁、红锁等),自动续期避免锁提前释放,适配长耗时业务。

3.5 分布式锁选型建议

锁类型核心场景特点
可重入锁(ReentrantLock)大多数分布式互斥场景性能优、通用性强
公平锁(FairLock)需保证锁获取顺序(避免饥饿)性能略低
联锁(MultiLock)同时锁定多个资源原子性保证多锁一致性
红锁(RedLock)高可用场景(金融、核心数据)部署成本高、可用性极强
读写锁(ReadWriteLock)读多写少场景提高读并发效率
信号量(Semaphore)限流、资源池控制控制并发数量
闭锁(CountDownLatch)分布式任务协调等待多个任务完成

根据业务场景选择合适的锁类型,优先使用「可重入锁」(通用性最强),高可用场景考虑「红锁」,读多写少场景用「读写锁」。

四、高可用部署适配

Redission 高可用部署适配的核心逻辑是:不侵入 Redis 集群原生机制,通过客户端层面的「拓扑感知、故障适配、一致性兜底」三大核心能力,屏蔽 Redis 不同部署模式(主从/哨兵、Cluster、RedLock 等)的底层差异与故障风险,确保分布式锁/服务在节点宕机、拓扑变化时仍稳定可用

4.1 拓扑动态感知:集群状态的实时雷达

Redission 客户端启动时及运行中,主动获取并刷新 Redis 集群拓扑信息(节点列表、主从关系、槽位映射),确保所有操作都能路由到正确节点。

  • 启动时:连接任意一个节点(哨兵/Cluster 节点),拉取全量拓扑;
  • 运行中:定期刷新(默认 60s,可配置)或被动触发(收到 MOVED/ASK/CLUSTERDOWN 响应时)。

在这里插入图片描述

4.2 故障转移适配:主节点宕机后的自动切换

当 Redis 主节点宕机,哨兵触发故障转移(从节点升级为新主),Redission 客户端通过以下流程无感知适配:

  1. 检测主节点连接失败;
  2. 向哨兵查询最新主节点;
  3. 切换连接到新主节点;
  4. 重试之前的锁操作(加锁/续期/解锁)。

在这里插入图片描述

4.3 Cluster 集群适配:槽位路由与迁移处理

Cluster 模式下,Redission 核心是「锁 Key 路由集中化」+「槽位迁移适配」:

  • 路由集中化:同一把锁的 Key 经 CRC16 计算后,始终映射到同一个哈希槽,路由到同一个主节点,避免跨槽操作;
  • 槽位迁移:收到 MOVED 响应时,立即刷新槽位映射,后续操作自动路由到新主节点。

在这里插入图片描述

4.4 RedLock 极致高可用:多节点投票机制

RedLock 不依赖主从复制,通过「多个独立 Redis 节点投票」实现容错:

  1. 客户端向所有独立节点(推荐 3-5 个)发送加锁请求;
  2. 若超过半数节点加锁成功(3 个需 ≥2 个,5 个需 ≥3 个),则整体加锁成功;
  3. 解锁时向所有节点发送解锁请求,避免残留锁。

在这里插入图片描述


Redission 高可用适配的本质是「客户端主导的智能适配」,核心可概括为:

  1. 「感知」:通过拓扑刷新实时掌握 Redis 集群状态;
  2. 「适配」:针对不同部署模式的故障场景(主节点宕机、槽位迁移),自动切换连接、重试操作;
  3. 「保障」:通过路由集中化、Lua 原子性、看门狗续期,确保锁的互斥性和一致性;
  4. 「分级」:从主从+哨兵(平衡成本与可用性)到 RedLock(极致容错),适配不同业务的可用性要求。

通过这套机制,Redission 让业务无需关心 Redis 底层部署细节,即可实现分布式锁/服务的高可用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TracyCoder123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值