Redisson 介绍
·
Redisson 介绍
Redisson 是一个高级的 Redis 客户端,基于 Netty 框架实现,提供了丰富的分布式对象和服务。它不仅简化了 Redis 的使用,还提供了分布式锁、集合、映射等高级功能。
Redisson 核心特性
1. 基础功能
- 连接池管理:自动管理连接,支持哨兵、集群模式
- 异步支持:提供同步、异步、响应式三种 API
- 序列化:支持多种序列化方式(JSON、Kryo、FST 等)
- 重连机制:自动重连和故障转移
2. 高级功能
- 分布式锁:可重入锁、公平锁、读写锁、联锁、红锁
- 分布式集合:Map、Set、List、Queue、Deque 等
- 分布式对象:原子性 Long、BitSet、HyperLogLog 等
- 分布式服务:远程服务、发布订阅、调度服务
Redisson 配置
Maven 依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.24.3</version>
</dependency>
单机模式配置
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379")
.setPassword("yourpassword")
.setDatabase(0)
.setConnectionPoolSize(64)
.setConnectionMinimumIdleSize(10);
RedissonClient redisson = Redisson.create(config);
哨兵模式配置
Config config = new Config();
config.useSentinelServers()
.addSentinelAddress("redis://sentinel1:26379",
"redis://sentinel2:26379",
"redis://sentinel3:26379")
.setMasterName("mymaster")
.setPassword("yourpassword");
RedissonClient redisson = Redisson.create(config);
集群模式配置
Config config = new Config();
config.useClusterServers()
.addNodeAddress("redis://node1:6379",
"redis://node2:6379",
"redis://node3:6379")
.setPassword("yourpassword")
.setScanInterval(2000);
RedissonClient redisson = Redisson.create(config);
Redisson 分布式锁详解
Redisson 实现了多种分布式锁,下面详细介绍每种锁的特性和使用方式。
1. 可重入锁(Reentrant Lock)
特性:
- 支持同一线程多次获取锁
- 自动续期(看门狗机制)
- 可设置锁超时时间
- 阻塞式和非阻塞式获取
基本使用:
// 获取锁对象
RLock lock = redisson.getLock("myLock");
// 阻塞式获取锁
lock.lock();
try {
// 执行业务逻辑
System.out.println("执行业务代码");
} finally {
// 释放锁
lock.unlock();
}
// 尝试获取锁(非阻塞)
if (lock.tryLock()) {
try {
// 执行业务逻辑
} finally {
lock.unlock();
}
}
// 带超时的尝试获取
if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
try {
// 等待10秒获取锁,锁持有30秒
} finally {
lock.unlock();
}
}
看门狗机制:
// 不指定超时时间,使用看门狗自动续期
lock.lock(); // 默认30秒自动续期
try {
// 业务逻辑执行时间可以超过30秒
// 锁会自动续期,直到unlock()
Thread.sleep(60000);
} finally {
lock.unlock();
}
自定义超时:
// 指定超时时间,不使用看门狗
lock.lock(10, TimeUnit.SECONDS);
try {
// 10秒后锁自动释放,不会续期
} finally {
lock.unlock();
}
2. 公平锁(Fair Lock)
特性:
- 按照请求顺序获取锁
- 避免饥饿现象
- 性能略低于可重入锁
使用方式:
RLock fairLock = redisson.getFairLock("myFairLock");
// 阻塞式获取
fairLock.lock();
try {
// 执行业务逻辑
} finally {
fairLock.unlock();
}
// 带超时的获取
if (fairLock.tryLock(10, 30, TimeUnit.SECONDS)) {
try {
// 执行业务逻辑
} finally {
fairLock.unlock();
}
}
3. 读写锁(ReadWrite Lock)
特性:
- 读锁(共享锁):多个线程可以同时持有
- 写锁(排他锁):独占访问
- 读读不互斥,读写互斥,写写互斥
使用方式:
RReadWriteLock rwLock = redisson.getReadWriteLock("myRWLock");
// 读锁
RLock readLock = rwLock.readLock();
readLock.lock();
try {
// 多个线程可以同时读取
String data = "读取数据";
System.out.println(data);
} finally {
readLock.unlock();
}
// 写锁
RLock writeLock = rwLock.writeLock();
writeLock.lock();
try {
// 独占写入
System.out.println("写入数据");
} finally {
writeLock.unlock();
}
实际应用场景:
// 缓存读写场景
public class CacheService {
private RReadWriteLock rwLock;
public CacheService(RedissonClient redisson) {
this.rwLock = redisson.getReadWriteLock("cache:rwlock");
}
public String getData(String key) {
RLock readLock = rwLock.readLock();
readLock.lock();
try {
// 读数据
return redisson.getBucket(key).get();
} finally {
readLock.unlock();
}
}
public void setData(String key, String value) {
RLock writeLock = rwLock.writeLock();
writeLock.lock();
try {
// 写数据
redisson.getBucket(key).set(value);
} finally {
writeLock.unlock();
}
}
}
4. 联锁(MultiLock)
特性:
- 同时锁定多个对象
- 所有锁都获取成功才算成功
- 用于跨资源的一致性操作
使用方式:
RLock lock1 = redisson1.getLock("lock1");
RLock lock2 = redisson2.getLock("lock2");
RLock lock3 = redisson3.getLock("lock3");
// 创建联锁
RLock multiLock = redisson.getMultiLock(lock1, lock2, lock3);
try {
// 同时获取多个锁
multiLock.lock();
// 执行跨资源的业务逻辑
} finally {
multiLock.unlock();
}
5. 红锁(RedLock)
特性:
- 分布式高可用锁
- 需要在多个 Redis 实例上加锁
- 大多数节点成功才算成功
- 防止单点故障
使用方式:
// 配置多个Redis实例
Config config1 = new Config();
config1.useSingleServer().setAddress("redis://node1:6379");
RedissonClient redisson1 = Redisson.create(config1);
Config config2 = new Config();
config2.useSingleServer().setAddress("redis://node2:6379");
RedissonClient redisson2 = Redisson.create(config2);
Config config3 = new Config();
config3.useSingleServer().setAddress("redis://node3:6379");
RedissonClient redisson3 = Redisson.create(config3);
// 获取红锁
RLock lock1 = redisson1.getLock("myRedLock");
RLock lock2 = redisson2.getLock("myRedLock");
RLock lock3 = redisson3.getLock("myRedLock");
RLock redLock = redisson1.getRedLock(lock1, lock2, lock3);
try {
// 大多数节点成功才获取锁
redLock.lock();
// 执行业务逻辑
} finally {
redLock.unlock();
}
6. 信号量(Semaphore)
特性:
- 限制同时访问的线程数
- 基于计数器实现
- 支持公平和非公平模式
使用方式:
RSemaphore semaphore = redisson.getSemaphore("mySemaphore");
// 设置许可数
semaphore.trySetPermits(3);
try {
// 获取许可
semaphore.acquire();
// 执行业务逻辑(最多3个线程同时执行)
} finally {
// 释放许可
semaphore.release();
}
// 非阻塞获取
if (semaphore.tryAcquire()) {
try {
// 执行业务逻辑
} finally {
semaphore.release();
}
}
7. 闭锁(CountDownLatch)
特性:
- 等待多个线程完成
- 基于计数器实现
- 一次性使用
使用方式:
RCountDownLatch latch = redisson.getCountDownLatch("myLatch");
// 设置等待数量
latch.trySetCount(5);
// 等待线程
new Thread(() -> {
try {
latch.await();
System.out.println("所有线程执行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
// 工作线程
for (int i = 0; i < 5; i++) {
new Thread(() -> {
// 执行业务逻辑
System.out.println("工作线程执行");
// 计数减1
latch.countDown();
}).start();
}
Redisson 锁的最佳实践
1. 工具类封装
@Component
public class DistributedLockUtil {
@Autowired
private RedissonClient redissonClient;
/**
* 执行带锁的业务逻辑
*/
public <T> T executeWithLock(String lockKey, long waitTime,
long leaseTime, TimeUnit unit,
Supplier<T> supplier) {
RLock lock = redissonClient.getLock(lockKey);
try {
if (lock.tryLock(waitTime, leaseTime, unit)) {
try {
return supplier.get();
} finally {
lock.unlock();
}
} else {
throw new RuntimeException("获取锁失败");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("锁等待被中断", e);
}
}
/**
* 无返回值的执行
*/
public void executeWithLock(String lockKey, long waitTime,
long leaseTime, TimeUnit unit,
Runnable runnable) {
executeWithLock(lockKey, waitTime, leaseTime, unit,
() -> {
runnable.run();
return null;
});
}
}
2. 使用示例
@Service
public class OrderService {
@Autowired
private DistributedLockUtil lockUtil;
public void createOrder(String orderId) {
lockUtil.executeWithLock(
"order:lock:" + orderId,
10, // 等待10秒
30, // 锁持有30秒
TimeUnit.SECONDS,
() -> {
// 创建订单逻辑
System.out.println("创建订单: " + orderId);
// 扣减库存
// 扣减余额
}
);
}
}
3. 注解方式实现
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DistributedLock {
String key();
long waitTime() default 10;
long leaseTime() default 30;
TimeUnit timeUnit() default TimeUnit.SECONDS;
}
@Aspect
@Component
public class DistributedLockAspect {
@Autowired
private RedissonClient redissonClient;
@Around("@annotation(distributedLock)")
public Object around(ProceedingJoinPoint point,
DistributedLock distributedLock) throws Throwable {
String lockKey = distributedLock.key();
RLock lock = redissonClient.getLock(lockKey);
try {
if (lock.tryLock(distributedLock.waitTime(),
distributedLock.leaseTime(),
distributedLock.timeUnit())) {
try {
return point.proceed();
} finally {
lock.unlock();
}
} else {
throw new RuntimeException("获取锁失败");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("锁等待被中断", e);
}
}
}
// 使用
@Service
public class InventoryService {
@DistributedLock(key = "inventory:lock:#{#productId}")
public void deductInventory(String productId, int quantity) {
// 扣减库存逻辑
}
}
Redisson 锁的底层原理
1. 锁获取过程
1. 客户端发送 Lua 脚本到 Redis
2. Redis 原子执行:SET key value NX PX timeout
3. 如果成功,启动看门狗线程
4. 如果失败,返回获取失败
2. 看门狗续期机制
1. 默认续期时间:30秒
2. 续期线程:每 10 秒检查一次
3. 如果锁还持有,续期 30 秒
4. 直到调用 unlock() 停止续期
3. 锁释放过程
1. 客户端发送 Lua 脚本
2. 检查锁是否属于当前线程
3. 如果属于,删除 key
4. 如果不属于,返回释放失败
注意事项
- 锁名称设计:要保证唯一性和可读性
- 超时时间:根据业务执行时间合理设置
- 异常处理:确保锁能正确释放
- 避免死锁:设置合理的超时时间
- 性能考虑:锁粒度不宜过大
更多推荐




所有评论(0)