Redisson 是一个用于 Java 的 Redis 客户端,它不仅提供了对 Redis 命令的访问,还实现了多种分布式对象、锁和同步工具。Redisson 的设计目标是简化在分布式系统中使用 Redis 的复杂度,并为开发者提供更高层次的抽象,以便更容易地实现诸如分布式锁、信号量、布隆过滤器等高级功能。
Redission 支持可重入锁,这意味着同一个线程可以在不释放之前持有的锁的情况下再次获取同一把锁。为了实现这一点,Redission 在内部维护了一个计数器来跟踪同一个客户端获取同一把锁的次数。每次获取锁时计数器增加,而每次解锁时计数器减少,直到计数器归零才真正释放锁
以下是 Redisson 的一些主要特点和提供的功能:
Redisson 实现了几乎所有的 Redis 数据类型(如 String, Map, Set, List 等),并且将它们包装成 Java 对象的形式,使得操作这些数据类型就像操作本地 Java 集合一样简单。
提供了 RSet
, RList
, RMap
等接口,允许用户在多个 JVM 之间共享数据结构,保证数据的一致性和高可用性。
RLock
)、公平锁 (RFairLock
)、读写锁 (RReadWriteLock
) 和红锁 (RRedLock
)。RSemaphore
)、计数信号量 (RCountDownLatch
) 和闭锁 (RPermitExpirableSemaphore
) 等同步工具,帮助协调不同节点之间的并发访问。支持发布/订阅模式 (RTopic
) 和阻塞队列 (RBlockingQueue
),可以用来构建事件驱动架构或异步任务处理系统。
内置的任务调度器 (RScheduledExecutorService
) 可以安排一次性或周期性的任务执行,适用于需要定时触发的操作。
提供了 RBucket
, RScoredSortedSet
, RHyperLogLog
等高级数据结构的支持,满足更复杂的业务需求。
提供了基于 Redis 的缓存机制,包括本地缓存、近缓存和多级缓存策略,提高了数据读取效率并降低了主数据库的压力。
Redisson 易于与其他 Java 应用程序和服务集成,可以通过 Spring Boot Starter 快速配置,也兼容其他常见的依赖注入容器。
Redisson 使用 Netty 框架进行网络通信,并且内部做了很多优化以确保高效的命令执行和数据传输。
全面支持 Redis 集群,能够自动发现和管理集群中的节点变化,保障服务的连续性和可靠性。
在实际应用中,可能会在以下场景中使用 Redis 分布式锁:
在 Spring Boot 中使用 Redis 实现分布式锁有多种方式,常用的是通过 Redisson
或者 spring-boot-starter-data-redis
结合 Lettuce
/Jedis
客户端库来实现。
使用 Redisson
Redisson 是一个流行的 Redis Java 客户端,它提供了许多高级功能,包括分布式锁。以下是设置和使用 Redisson 分布式锁的基本步骤:
添加依赖
在 pom.xml
文件中添加 Redisson 的依赖:
org.redisson
redisson-spring-boot-starter
3.20.0
配置 Redisson 连接
在 application.properties
或 application.yml
文件中配置 Redisson 的连接信息。
获取锁对象并使用
使用 RedissonClient 来获取 RLock 对象,然后尝试加锁、解锁等操作。
@Autowired
private RedissonClient redissonClient;
public void someServiceMethod() {
RLock lock = redissonClient.getLock("myLock");
try {
// 尝试加锁,等待时间10秒,锁自动释放时间为30秒
boolean isLocked = lock.tryLock(10, 30, TimeUnit.SECONDS);
if (isLocked) {
// 执行需要互斥执行的代码块
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
// 处理异常
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock(); // 确保在finally块中解锁
}
}
}
注意事项
加锁(tryLock()
)
Redisson 使用 Redis 的 SETNX
(SET if Not eXists)命令来尝试获取锁。SETNX
是一种原子操作,只有在键不存在时才会设置成功。这意味着如果多个客户端同时尝试获取同一个锁,只有一个会成功。使用 SETNX
设置锁时,通常会结合 EXPIRE
或者直接使用 SETEX
命令为锁设置一个过期时间。这是为了防止死锁的发生,即如果持有锁的进程崩溃而没有主动释放锁,那么经过一定时间后锁也会自动释放。
骚戴理解:简单来说就是通过SETNX
+PEXPIRE
+ Lua 脚本实现分布式锁, Lua 脚本会在 Redis 中执行,它首先尝试使用 SETNX
设置键,如果成功,则通过 PEXPIRE
设置键的过期时间。Lua 脚本是为了保证这些操作的原子性
删除锁(unlock()
)
为了安全地删除锁,Redission 使用 Lua 脚本来检查当前锁是否由当前客户端持有( Redisson 在加锁的时候会关联一个唯一的标识符(lockId),解锁时会检查这个标识符是否匹配,避免了误删其他客户端持有的锁的问题)。如果是,则删除该锁;否则拒绝解锁请求。
Redission 提供了一种称为“看门狗”(Watchdog)的机制,用来自动延长锁的有效期。当客户端成功获取到锁后,看门狗会启动一个后台任务,周期性地检查锁的状态并在必要时更新其过期时间。这样即使处理时间超过了最初设定的锁有效期,只要任务还在进行中,锁就不会被其他客户端抢走,通过看门狗机制确保长时间运行的任务不会意外失去锁
expire
或者 pexpire
命令延长锁的生存时间。续期的时间间隔通常是锁原始有效时间的一半左右。