使用 Redisson 实现分布式锁—解决方案详解
Redisson 是 Redis 官方推荐的 Java 客户端,提供了一系列分布式服务实现,其中分布式锁是其核心功能之一。本文将深入解析 Redisson 分布式锁的实现原理、高级特性和最佳实践。
一、Redisson 分布式锁的优势
与传统实现的对比
特性 | 手动实现 | Redisson 实现 |
---|---|---|
锁续期 | 需手动实现看门狗 | 内置自动续期机制 |
可重入性 | 不支持 | 原生支持可重入锁 |
锁类型 | 基础锁 | 公平锁/联锁/读写锁/红锁 |
等待机制 | 自旋或阻塞 | 订阅发布机制 |
异常处理 | 手动处理 | 完善的异常处理链 |
集群支持 | 需自行处理故障转移 | 原生支持Redis集群模式 |
二、核心实现原理
1. 加锁原子性保证
Redisson 使用 Lua 脚本保证原子操作:
if (redis.call('exists', KEYS[1]) == 0)
then redis.call('hset', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil;
end;
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1)
then redis.call('hincrby', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil;
end;
return redis.call('pttl', KEYS[1]);
2. 看门狗锁续期机制
private void scheduleExpirationRenewal(long threadId) {// 每10秒续期一次Timeout task = commandExecutor.getConnectionManager().newTimeout(timeout -> {// 续期逻辑RFuture<Boolean> future = renewExpirationAsync(threadId);future.onComplete((res, e) -> {if (e != null) {// 异常处理return;}if (res) {// 递归调用实现循环续期scheduleExpirationRenewal(threadId);}});}, lockWatchdogTimeout / 3, TimeUnit.MILLISECONDS);
}
三、完整使用示例
1. 添加 Maven 依赖
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.27.0</version>
</dependency>
2. 配置 Redisson 客户端
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379").setPassword("your_password").setDatabase(0).setConnectionPoolSize(64).setConnectionMinimumIdleSize(24);RedissonClient redisson = Redisson.create(config);
3. 基础锁使用
RLock lock = redisson.getLock("orderLock");void processOrder(String orderId) {try {// 尝试获取锁,等待100秒,锁自动释放时间30秒if (lock.tryLock(100, 30, TimeUnit.SECONDS)) {// 关键业务逻辑Order order = orderService.getOrder(orderId);order.process();orderService.update(order);}} catch (InterruptedException e) {Thread.currentThread().interrupt();log.error("锁获取被中断", e);} finally {if (lock.isHeldByCurrentThread()) {lock.unlock();log.info("订单{}处理完成,锁已释放", orderId);}}
}
四、高级锁特性详解
1. 可重入锁(Reentrant Lock)
public void nestedLockExample() {RLock lock = redisson.getLock("reentrantLock");lock.lock();try {// 外层业务逻辑innerMethod(lock);} finally {lock.unlock();}
}private void innerMethod(RLock lock) {// 内层方法再次获取锁lock.lock(); // 计数+1try {// 内层业务逻辑} finally {lock.unlock(); // 计数-1}
}
2. 公平锁(Fair Lock)
RLock fairLock = redisson.getFairLock("fairLock");
fairLock.lock();
try {// 按照请求顺序获取锁资源executeCriticalSection();
} finally {fairLock.unlock();
}
3. 读写锁(ReadWrite Lock)
RReadWriteLock rwLock = redisson.getReadWriteLock("resourceLock");// 读操作
void readData() {RLock readLock = rwLock.readLock();readLock.lock();try {// 多个线程可并发读取return fetchDataFromDB();} finally {readLock.unlock();}
}// 写操作
void writeData(Object data) {RLock writeLock = rwLock.writeLock();writeLock.lock();try {// 独占写权限updateDataInDB(data);} finally {writeLock.unlock();}
}
4. 联锁(MultiLock)
RLock lock1 = redisson.getLock("lock1");
RLock lock2 = redisson.getLock("lock2");
RLock lock3 = redisson.getLock("lock3");// 同时获取多个锁
RedissonMultiLock multiLock = new RedissonMultiLock(lock1, lock2, lock3);
multiLock.lock();
try {// 操作多个资源updateResource1();updateResource2();
} finally {multiLock.unlock();
}
五、红锁(RedLock)实现
解决Redis集群脑裂问题
Config config1 = createConfig("redis://node1:6379");
Config config2 = createConfig("redis://node2:6379");
Config config3 = createConfig("redis://node3:6379");RedissonClient client1 = Redisson.create(config1);
RedissonClient client2 = Redisson.create(config2);
RedissonClient client3 = Redisson.create(config3);RLock lock1 = client1.getLock("globalLock");
RLock lock2 = client2.getLock("globalLock");
RLock lock3 = client3.getLock("globalLock");// 构建红锁
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);try {// 尝试获取锁,锁定时间60秒if (redLock.tryLock(100, 60, TimeUnit.SECONDS)) {// 关键业务逻辑processGlobalResource();}
} finally {redLock.unlock();// 关闭客户端连接Stream.of(client1, client2, client3).forEach(RedissonClient::shutdown);
}
六、生产环境最佳实践
1. 锁命名规范
// 业务域:资源类型:资源ID
String lockKey = "order:processing:" + orderId;
RLock lock = redisson.getLock(lockKey);
2. 合理配置参数
config.setLockWatchdogTimeout(30_000); // 看门狗超时时间
config.setNettyThreads(32); // 网络线程数// 锁配置
RedissonFairLock lock = (RedissonFairLock) redisson.getFairLock("lock");
lock.setLockWatchdogTimeout(60_000); // 覆盖全局配置
3. 异常处理策略
try {if (lock.tryLock(10, 30, SECONDS)) {// 业务逻辑}
} catch (RedisResponseTimeoutException e) {// Redis响应超时处理metrics.recordTimeout();throw new ServiceUnavailableException("Redis超时");
} catch (RedisConnectionException e) {// 连接异常处理fallbackProcessor.process();
} catch (Exception e) {// 通用异常处理log.error("锁操作异常", e);
} finally {unlockSafely(lock);
}void unlockSafely(RLock lock) {try {if (lock.isHeldByCurrentThread() && lock.isLocked()) {lock.unlock();}} catch (IllegalMonitorStateException ex) {// 锁状态异常处理}
}
4. 监控与告警
// 监控锁等待时间
long start = System.currentTimeMillis();
if (lock.tryLock(waitTime, leaseTime, unit)) {long elapsed = System.currentTimeMillis() - start;metrics.recordLockWaitTime(elapsed);// ...
}// 监控锁持有时间
LockHoldTimer timer = metrics.startLockHoldTimer();
try {// 业务逻辑
} finally {timer.stop();
}// JMX监控
Redisson redisson = (Redisson) redissonClient;
redisson.getRemoteService().registerService(LockMetrics.class, lockMetrics);
七、故障场景处理方案
1. 客户端宕机处理
2. 网络分区处理
// 使用红锁提高可用性
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
redLock.lock(10, TimeUnit.SECONDS); // 设置较短租期// 添加监听器处理连接丢失
lock.addListener(new LockListener() {@Overridepublic void onLockLost() {// 触发补偿机制compensationService.compensate();}
});
八、性能优化策略
1. 锁粒度优化
// 粗粒度锁(不推荐)
RLock coarseLock = redisson.getLock("orderProcessing");// 细粒度锁(推荐)
RLock fineGrainedLock = redisson.getLock("order:" + orderId);
2. 锁分离技术
// 读多写少场景
RReadWriteLock rwLock = redisson.getReadWriteLock("resource");
rwLock.readLock().lock(); // 读操作
rwLock.writeLock().lock(); // 写操作// 热点数据场景
long shardId = orderId % 16;
RLock shardedLock = redisson.getLock("order_lock:" + shardId);
3. 异步锁操作
// 异步获取锁
RFuture<Boolean> lockFuture = lock.tryLockAsync(10, 30, TimeUnit.SECONDS);lockFuture.onComplete((res, ex) -> {if (res) {// 获取锁成功processAsync();} else {// 获取锁失败fallback();}
});// 异步释放锁
lock.unlockAsync();
九、常见问题解决方案
1. 锁等待超时
场景:系统负载高时锁获取超时
解决方案:
// 指数退避策略
long baseDelay = 50;
long maxDelay = 1000;
Random random = new Random();while (!lock.tryLock()) {long delay = baseDelay + random.nextInt((int) baseDelay);Thread.sleep(delay);baseDelay = Math.min(baseDelay * 2, maxDelay);
}
2. 锁提前释放
场景:GC暂停导致看门狗续期失败
解决方案:
// 增加续期超时时间
config.setLockWatchdogTimeout(60_000);// 添加JVM参数减少GC暂停
-XX:+UseG1GC -XX:MaxGCPauseMillis=100
3. 锁状态不一致
场景:Redis故障转移后锁状态丢失
解决方案:
// 使用红锁
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);// 启用持久化
config.setLockWatchdogTimeout(0); // 禁用看门狗
lock.lock(30, TimeUnit.SECONDS); // 依赖Redis持久化
十、Redisson 与企业架构集成
Spring Boot 自动配置
@Configuration
public class RedissonConfig {@Bean(destroyMethod = "shutdown")public RedissonClient redisson(@Value("${redis.address}") String address) {Config config = new Config();config.useSingleServer().setAddress(address).setConnectionPoolSize(64);return Redisson.create(config);}@Beanpublic DistributedLockFactory lockFactory(RedissonClient redisson) {return new RedissonLockFactory(redisson);}
}@Service
public class OrderService {@Autowiredprivate DistributedLockFactory lockFactory;public void processOrder(String orderId) {Lock lock = lockFactory.getLock("order:" + orderId);if (lock.tryLock()) {try {// 业务逻辑} finally {lock.unlock();}}}
}
与 Spring Cloud 集成
# application.yml
spring:cloud:distributed-lock:enabled: trueprovider: redissonredisson:config-file: classpath:redisson.yaml
@SpringBootApplication
@EnableDistributedLock
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}@Service
public class InventoryService {@DistributedLock(lockKey = "'inventory:' + #skuId")public void reduceStock(String skuId, int quantity) {// 无需手动加锁inventoryDao.reduce(skuId, quantity);}
}
总结:Redisson 分布式锁最佳实践
-
锁选择策略:
- 普通场景:
RLock
基础锁 - 读多写少:
RReadWriteLock
读写锁 - 高可用要求:
RedissonRedLock
红锁 - 顺序执行:
RedissonFairLock
公平锁
- 普通场景:
-
关键配置参数:
# 看门狗续期时间(默认30秒) lockWatchdogTimeout=30000 # 锁等待时间(根据业务设置) waitTime=5000 # 锁租期时间(大于业务执行时间) leaseTime=30000
-
性能优化建议:
- 锁粒度最小化
- 读写锁分离
- 避免长时间持有锁
- 热点数据分片
-
容灾方案:
- 多数据中心部署
- 降级策略(本地锁/熔断)
- 事务补偿机制
最终建议:
- 生产环境使用 Redisson 3.24+ 版本
- 集群环境使用红锁(至少3个独立主节点)
- 结合 Prometheus + Grafana 监控锁指标
- 定期进行混沌工程测试
通过合理使用 Redisson 分布式锁,可以构建出高并发、高可靠的分布式系统。但需谨记:分布式锁是最后的选择而非首选方案,优先考虑无锁设计(如CAS)、事务隔离级别优化等方案能获得更好的系统性能。