Redisson 到底能做什么?从分布式锁说起

15 阅读4分钟

很多人接触 Redisson,是因为“分布式锁”。网上一搜,三行代码就能加锁:

RLock lock = redissonClient.getLock("myLock");
lock.lock();
// 业务逻辑
lock.unlock();

看起来简单又可靠。但用了一段时间后才发现:Redisson 的能力远不止加锁。它更像是把 Java 并发包(JUC)里的那些工具——ReentrantLock、Semaphore、CountDownLatch、BlockingQueue——搬到了分布式环境,并用 Redis 作为底层支撑。

而这一切,都通过一个核心对象:RedissonClient

一、所有功能,都从 RedissonClient 来

无论你要用锁、队列、还是分布式集合,第一步永远是创建 RedissonClient

Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient client = Redisson.create(config);

之后的所有操作,都是它的方法:

  • client.getLock("order_lock") → 分布式可重入锁
  • client.getSemaphore("concurrent_limit") → 信号量
  • client.getCountDownLatch("startup_ready") → 倒计时门闩
  • client.getMap("user_profile") → 分布式 Map
  • client.getTopic("notification") → 发布订阅

Redisson 不是对 Jedis 或 Lettuce 的简单封装,而是重新设计了一套面向对象的 Redis 操作接口。你操作的不是 key 和 value,而是一个个有行为的对象。

二、分布式锁只是起点,不是全部

Redisson 的 RLock 确实比手写 SETNX + Lua 更可靠,主要因为它解决了几个实际问题:

1. 自动续期(Watchdog)

默认情况下,加锁成功后,Redisson 会启动一个后台线程,每 10 秒检查一次:如果当前线程还在持有这把锁,就自动延长过期时间(默认 30 秒)。
这样即使业务执行时间超过初始 TTL,也不会提前释放锁。

注意:如果你显式指定了超时时间,比如 lock.lock(10, TimeUnit.SECONDS),就不会触发自动续期。

2. 可重入

同一个线程可以多次获取同一把锁,内部用 Redis Hash 记录线程 ID 和重入次数。释放时逐次递减,归零才真正删 key。行为和 ReentrantLock 完全一致。

3. 更多锁类型

  • 公平锁client.getFairLock(),按请求顺序排队;
  • 读写锁client.getReadWriteLock(),读共享、写独占;
  • 联锁new RedissonMultiLock(lock1, lock2),多个资源同时锁定。

这些都不是靠拼几个 Redis 命令就能轻松实现的。

三、Redisson 的“JUC 搬家计划”

除了锁,Redisson 几乎把整个 java.util.concurrent 包都复刻到了 Redis 上:

JUC 类Redisson 对应典型用途
SemaphoreRSemaphore限制并发访问数(如限流)
CountDownLatchRCountDownLatch等待多个服务就绪
BlockingQueueRBlockingQueue跨服务任务队列
DelayedQueueRDelayedQueue延迟任务(如订单超时取消)
AtomicLongRAtomicLong分布式计数器

举个例子:用 RCountDownLatch 等三个微服务启动完成:

RCountDownLatch latch = client.getCountDownLatch("services-ready");
latch.trySetCount(3); // 初始化为3

// 每个服务启动完调用
latch.countDown();

// 主控服务等待
latch.await(); // 阻塞直到计数归零

整个过程天然跨 JVM,且状态持久化在 Redis 中。

四、RMap:不只是存数据,还能监听变化

RMap 是对 Redis Hash 的封装,但它支持更多高级特性:

RMap<String, Order> orderMap = client.getMap("orders");
orderMap.addListener((name, entry, action) -> {
    if (action == EntryEvent.Action.UPDATE) {
        System.out.println("订单更新: " + entry.getKey());
    }
});

你可以监听某个 key 的增删改事件,像本地 Map 一样响应变化,但作用于整个集群。

其他亮点:

  • 本地缓存RMapCache 支持 LRU 本地缓存,减少 Redis 访问;
  • 单条过期:每个 entry 可单独设 TTL;
  • 批量操作fastPut()putAll() 减少网络往返。

五、使用时要注意什么?

  1. 记得关闭客户端
client.shutdown(); // 应用退出时调用

否则连接不会释放,可能耗尽连接池。

  1. 锁的粒度要合理
    锁太粗(如 "global_lock")会成为瓶颈,太细(如每条记录一个锁)可能增加 Redis 压力。建议按业务维度划分,比如 "order:123:lock"
  2. Watchdog 不能解决主从切换问题
    Redis 主从异步复制,极端情况下可能丢锁。对强一致性要求极高的场景,需评估是否适用。
  3. 序列化影响性能
    默认用 Jackson,如果存大量数据,可换 FstCodecKryoCodec 提升速度。

六、结语

Redisson 提供的能力,其实早就写在它的 API 里了。很多人只用了 getLock(),是因为一开始的需求就是加锁。但当你遇到限流、延迟任务、跨节点协同、数据变更通知等问题时,不妨先看看 Redisson 是否已经有现成的组件。

它不神奇,只是把常见的分布式协作模式,用 Redis 实现了一遍,并封装成你熟悉的接口。用不用,取决于你是否知道它在那里。