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. 如果不属于,返回释放失败

注意事项

  1. 锁名称设计:要保证唯一性和可读性
  2. 超时时间:根据业务执行时间合理设置
  3. 异常处理:确保锁能正确释放
  4. 避免死锁:设置合理的超时时间
  5. 性能考虑:锁粒度不宜过大
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐