RedisNotes

第 10 章:Redisson 实战

zjc 于 2026-01-10 发布

这是《Redis 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 Redis 把底层数据结构做得很强,Redisson 则把分布式常用模式封装成 Java 风格 API。本章讲 Redisson 的基础接入、锁、限流、延迟队列与使用边界。

10.1 Redisson 是什么

Redisson 是基于 Redis 的 Java 驻留对象框架,提供:

它解决的是“通用工程组件”,不是替代业务代码里的所有逻辑。

10.2 引入依赖

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.27.2</version>
</dependency>

配置:

spring:
  redis:
    redisson:
      config: |
        singleServerConfig:
          address: "redis://127.0.0.1:6379"
          password: redis123
          database: 0
          connectionMinimumIdleSize: 10
          connectionPoolSize: 50
          connectTimeout: 1000
          timeout: 1000

版本要与 Spring Boot、Redis Server、JDK 兼容矩阵匹配。

10.3 基础使用

@Autowired
private RedissonClient redisson;

public void demo() {
    RBucket<String> bucket = redisson.getBucket("user:1001");
    bucket.set("Tom", Duration.ofMinutes(10));
    System.out.println(bucket.get());

    RMap<String, Integer> cart = redisson.getMap("cart:user:1001");
    cart.put("sku:2001", 2);

    RScoredSortedSet<String> rank =
            redisson.getScoredSortedSet("rank:game");
    rank.add(100, "player:1");
}

这些对象本质仍是 Redis 数据结构,只是提供 Java API。

10.4 RedissonLock

RLock lock = redisson.getLock("lock:order:1001");

boolean locked = false;
try {
    locked = lock.tryLock(100, 10, TimeUnit.SECONDS);
    if (!locked) {
        throw new BusyException("try lock failed");
    }
    doBusiness();
} finally {
    if (locked && lock.isHeldByCurrentThread()) {
        lock.unlock();
    }
}

参数:

tryLock(waitTime, leaseTime, unit)

10.5 看门狗机制

默认锁超时时间是 30 秒:

lockWatchdogTimeout=30000

当使用:

lock.lock();
lock.tryLock(1, TimeUnit.SECONDS);

没有显式 leaseTime 时,Redisson 会启动后台任务定期续期,通常每 10 秒重置到 30 秒。业务执行完成或客户端进程崩溃后,续期停止,锁最终自动过期。

看门狗解决“业务执行时间不可预估”的问题,但也带来风险:

10.6 可重入锁

Redisson 的 RLock 是可重入锁:

RLock lock = redisson.getLock("lock:user:1001");

lock.lock();
try {
    a(lock);
} finally {
    lock.unlock();
}

void a(RLock lock) {
    lock.lock();
    try {
        System.out.println("reentrant");
    } finally {
        lock.unlock();
    }
}

底层使用 Hash 记录锁标识与重入次数,必须由持有线程 unlock。

10.7 公平锁与读写锁

公平锁:

RLock fairLock = redisson.getFairLock("lock:job");

等待线程按请求顺序获取锁,公平性带来额外开销,吞吐低于普通锁。

读写锁:

RReadWriteLock rwLock = redisson.getReadWriteLock("lock:config");

RLock readLock = rwLock.readLock();
RLock writeLock = rwLock.writeLock();

10.8 信号量与闭锁

RSemaphore semaphore = redisson.getSemaphore("sem:export");
semaphore.trySetPermits(5);

if (semaphore.tryAcquire()) {
    try {
        doExport();
    } finally {
        semaphore.release();
    }
}

限制并发任务数。闭锁:

RCountDownLatch latch = redisson.getCountDownLatch("latch:batch");
latch.trySetCount(3);
latch.await();
latch.countDown();

适合等待多个节点/阶段完成,但要注意 await 超时与任务失败清理。

10.9 分布式限流

RRateLimiter limiter =
        redisson.getRateLimiter("rate:login:user:1001");

limiter.trySetRate(RateType.OVERALL, 10, 1, RateIntervalUnit.SECONDS);

if (!limiter.tryAcquire()) {
    throw new TooManyRequestException();
}

适用场景:

精确滑动窗口可用 ZSet 自行实现,窗口大小按业务选择。全局强限流还要考虑 Redis 故障时的降级策略。

10.10 延迟队列

RBlockingQueue<String> queue =
        redisson.getBlockingQueue("queue:order:timeout");
RDelayedQueue<String> delayedQueue =
        redisson.getDelayedQueue(queue);

delayedQueue.offer("order:1001", 30, TimeUnit.MINUTES);

String orderId = queue.take(); // 到期后转移,再消费
delayedQueue.destroy();

适合订单超时关闭、重试延迟、提醒任务。生产还要处理:

大规模任务调度可评估 RocketMQ 延迟消息、Kafka + 定时器、ElasticJob/XXL-JOB。

10.11 布隆过滤器

RBloomFilter<Long> filter =
        redisson.getBloomFilter("bloom:valid:product");

filter.tryInit(1_000_000L, 0.01);

filter.add(10001L);
boolean mayContain = filter.contains(10002L);

特点:

适合缓存穿透防护、黑名单初筛、推荐去重初筛。

10.12 使用边界

Redisson 很方便,但不要把所有业务逻辑都搬进 Redis:

  1. 复杂状态流转仍应在数据库/服务层建模;
  2. 大量分布式对象操作可能形成大 key 和慢脚本;
  3. Redis 故障时锁、限流、延迟队列都会受影响;
  4. 与 Lettuce/Jedis 混用时要统一连接池和监控;
  5. 所有分布式组件都要有超时、降级和告警。

本章小结

思考题

  1. 显式设置 leaseTime=5s 后看门狗还会续期吗?为什么?
  2. Redisson 锁释放失败有哪些常见原因?
  3. 布隆过滤器为什么能防穿透,但不能完全替代数据库存在性校验?