3. Redisson 客户端入门:引入、配置与基本加解锁操作

在微服务架构中,直接使用 Jedis 或 Lettuce 实现分布式锁需要自行处理 Lua 脚本、看门狗续期、重试策略等复杂逻辑。Redisson 作为 Redis 官方推荐的 Java 客户端,提供了开箱即用的分布式锁实现,将底层 Lua 脚本、锁续期、可重入等机制封装为简单的 API。本节将带你完成 Redisson 的引入、配置与核心加解锁操作。

3.1 Redisson 的引入与核心优势

Redisson 是一个基于 Netty 的 Java Redis 客户端,提供了超过 30 种分布式数据结构和锁服务。相比原生 Jedis,Redisson 在分布式锁场景下具备以下核心优势:

特性 Jedis / Lettuce Redisson
锁续期(Watchdog) 需手动实现定时任务 内置自动续期,默认每 10 秒检查一次
可重入支持 需自行维护计数器 原生支持,同一线程可多次加锁
Lua 脚本封装 需手写 Lua 并调用 eval 内部自动生成并执行 Lua 脚本
失败重试策略 需自行实现循环重试 提供 waitTime / leaseTime 参数控制
连接管理 需手动管理连接池 内置 Netty 连接池,自动重连
选型建议: 在 Spring Boot 微服务项目中,推荐直接引入 redisson-spring-boot-starter,可自动装配 RedissonClient 实例,无需手动创建配置 Bean。

3.2 Maven 依赖配置

在 pom.xml 中添加 Redisson 依赖。以下为 Spring Boot 3.x 环境下的推荐版本:

<!-- Redisson 核心依赖 -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.27.2</version>
</dependency>

<!-- 若使用 Spring Boot 2.x,请使用 3.17.x 系列版本 -->
版本兼容性: Redisson 3.27.x 要求 Spring Boot 3.x + JDK 17。若项目仍使用 Spring Boot 2.x,请锁定 3.17.x 版本,避免类加载冲突。

3.3 配置文件与连接模式

Redisson 支持单节点、哨兵、集群、云托管等多种部署模式。以下为最常见的单节点与哨兵模式配置示例:

3.3.1 单节点模式(application.yml)

spring:
  redis:
    redisson:
      config: |
        singleServerConfig:
          address: "redis://127.0.0.1:6379"
          password: null
          database: 0
          connectionPoolSize: 64
          connectionMinimumIdleSize: 16
          timeout: 3000
        threads: 16
        nettyThreads: 32

3.3.2 哨兵模式(application.yml)

spring:
  redis:
    redisson:
      config: |
        sentinelServersConfig:
          sentinelAddresses:
            - "redis://sentinel1:26379"
            - "redis://sentinel2:26379"
            - "redis://sentinel3:26379"
          masterName: "mymaster"
          password: null
          database: 0
          connectionPoolSize: 64
        threads: 16
        nettyThreads: 32
配置要点: connectionPoolSize 建议设置为微服务实例数的 2~4 倍;timeout 建议不超过 5000ms,避免锁获取时长时间阻塞。

3.4 基本加锁与解锁操作

Redisson 提供 RLock 接口,支持同步、异步、响应式三种编程模型。以下为最常用的同步加解锁模式:

3.4.1 标准加锁模式(自动续期)

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    private final RedissonClient redissonClient;

    public OrderService(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    public void processOrder(String orderId) {
        String lockKey = "lock:order:" + orderId;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试加锁,默认等待时间 30 秒,看门狗自动续期
            lock.lock();
            // 执行业务逻辑
            System.out.println("订单 " + orderId + " 处理中...");
            Thread.sleep(5000); // 模拟业务耗时
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 解锁
            lock.unlock();
        }
    }
}

3.4.2 带超时控制的加锁模式

public boolean tryProcessOrder(String orderId) {
    String lockKey = "lock:order:" + orderId;
    RLock lock = redissonClient.getLock(lockKey);

    try {
        // 尝试加锁,等待 3 秒,锁持有时间 10 秒(到期自动释放,看门狗不续期)
        boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
        if (locked) {
            try {
                System.out.println("订单 " + orderId + " 获取锁成功");
                return true;
            } finally {
                lock.unlock();
            }
        } else {
            System.out.println("订单 " + orderId + " 获取锁超时");
            return false;
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        return false;
    }
}
API 选择建议: 对于短耗时操作(< 5 秒),推荐使用 lock() 配合看门狗自动续期;对于长耗时或需要精确控制锁持有时间的场景,使用 tryLock(waitTime, leaseTime, unit) 并设置合理的 leaseTime。

3.5 加锁流程与看门狗机制

Redisson 的加锁流程涉及 Lua 脚本原子性操作与后台看门狗线程。以下为加锁与续期的完整流程:

Redisson 加锁与看门狗续期流程 微服务客户端 Redis 主节点 看门狗线程 ① 调用 lock() ② 执行 Lua 脚本 Lua 脚本 exists key ? hexists key ? hincrby / pexpire ③ 返回锁状态 看门狗续期逻辑 每 10 秒检查锁是否存活 若存活则 pexpire 续期 30 秒 ④ 定时续期 解锁调用 ⑤ unlock() → 执行 Lua 脚本释放锁 hexists → hincrby -1 → del 看门狗线程停止 ⑥ 取消续期
流程要点: 加锁时 Redisson 通过 Lua 脚本保证原子性;看门狗线程在锁持有期间每 10 秒执行一次 pexpire 续期,默认续期 30 秒;解锁时同样通过 Lua 脚本释放锁并通知看门狗停止续期。

3.6 常见问题与避坑指南

问题场景 原因 解决方案
解锁时抛出 IllegalMonitorStateException 当前线程未持有锁却调用 unlock() 在 finally 块中先判断 lock.isHeldByCurrentThread()
锁超时后业务仍在执行 tryLock 的 leaseTime 设置过短 使用 lock() 让看门狗自动续期,或设置足够长的 leaseTime
Redis 主节点宕机导致锁丢失 Redisson 默认未开启 RedLock 使用 RedissonRedLock 跨多个主节点加锁
看门狗续期导致锁永久持有 业务代码死循环或无限阻塞 设置 lockWatchdogTimeout 上限,或使用 tryLock 带 leaseTime
生产环境警告: 不要在 @Transactional 方法内部直接使用 lock(),因为事务提交可能晚于锁释放,导致并发问题。建议将锁操作放在事务边界之外,或使用 @Transactional(propagation = Propagation.REQUIRES_NEW) 隔离事务。

3.7 本章小结

通过本节学习,你已掌握 Redisson 客户端的引入、配置与基本加解锁操作。核心要点包括:

  • 依赖引入: 使用 redisson-spring-boot-starter 实现自动装配
  • 配置模式: 单节点与哨兵模式配置差异,连接池参数调优
  • 加锁 API: lock() 自动续期 vs tryLock() 精确控制
  • 看门狗机制: 每 10 秒续期 30 秒,解锁后自动停止
  • 避坑指南: 线程持有检查、超时设置、事务边界隔离