完整Redis分布式锁技术方案(基于Redisson)
一、技术方案概述
1. 设计理念
基于Redisson实现高可靠分布式锁,支持单机/集群Redis自动适配 ,提供单点锁、联锁核心功能,通过静态工具类简化业务调用,同时保障锁的原子性、自动续期、超时控制等特性,适用于分布式系统中的并发场景(如库存扣减、订单创建、数据同步等)。
2. 核心优势
- 自动适配Redis部署模式(单机/集群),无需手动修改配置;
- 支持锁自动续期(leaseTime=-1时),避免业务未完成锁提前释放;
- 提供联锁功能,支持多key原子性锁定(解决分布式场景下多资源并发竞争问题);
- 完善的异常处理和线程中断支持,确保锁释放的安全性;
- 基于Spring Boot自动配置,零侵入集成业务系统。
二、完整代码实现
1. 包结构规范
kotlin
com.data.redis
├── DistributedLockTool.java // 静态调用工具类
└── redisson
├── DistributedLocker.java // 分布式锁核心接口
├── RedissonDistributedLocker.java // Redisson实现类
└── RedissonAutoConfiguration.java // 自动配置类
2. 核心接口(DistributedLocker.java)
java
package com.data.redis.redisson;
import java.util.concurrent.TimeUnit;
/**
* 分布式锁接口
* @author 2021/5/21
*/
public interface DistributedLocker {
/**
* 获取锁
* @param lockKey 锁key(建议格式:业务模块:资源标识:唯一ID,如order:create:1001)
* @param leaseTime 持有锁时间(单位:unit),-1表示自动续期
* @param waitTime 申请锁超时时间(单位:unit)
* @param unit 时间单位
* @return true=获取成功,false=获取失败
*/
boolean lock(String lockKey, long leaseTime, long waitTime, TimeUnit unit);
/**
* 获取联锁(多key原子锁)
* @param lockKeys 锁key集合(需保证所有key都获取成功才持有锁,任意一个失败则全部失败)
* @param leaseTime 持有锁时间,-1表示自动续期
* @param waitTime 申请锁超时时间
* @param unit 时间单位
* @return true=获取成功,false=获取失败
*/
boolean multiLock(Collection<String> lockKeys, long leaseTime, long waitTime, TimeUnit unit);
/**
* 释放锁(仅释放当前线程持有的锁)
* @param lockKey 锁key
*/
void unlock(String lockKey);
/**
* 释放联锁
* @param lockKeys 锁key集合
*/
void multiUnlock(Collection<String> lockKeys);
}
3. Redisson实现类(RedissonDistributedLocker.java)
java
package com.data.redis.redisson;
import org.redisson.api.RedissonClient;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
/**
* Redis分布式锁实现(基于Redisson)
* @author 2021/5/21
*/
public class RedissonDistributedLocker implements DistributedLocker {
private final RedissonClient redissonClient;
// 构造器注入RedissonClient
public RedissonDistributedLocker(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
@Override
public boolean lock(String lockKey, long leaseTime, long waitTime, TimeUnit unit) {
try {
// Redisson的tryLock支持超时等待、持有时间、自动续期(leaseTime=-1时)
return redissonClient.getLock(lockKey).tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
// 恢复线程中断状态
Thread.currentThread().interrupt();
return false;
}
}
@Override
public boolean multiLock(Collection<String> lockKeys, long leaseTime, long waitTime, TimeUnit unit) {
try {
// 批量获取锁对象,构建联锁
org.redisson.api.RLock[] rLocks = lockKeys.stream()
.map(redissonClient::getLock)
.toArray(org.redisson.api.RLock[]::new);
// 联锁特性:所有锁都获取成功才返回true,任意一个失败则全部释放
return redissonClient.getMultiLock(rLocks).tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
@Override
public void unlock(String lockKey) {
org.redisson.api.RLock lock = redissonClient.getLock(lockKey);
// 仅释放当前线程持有的锁,避免释放其他线程的锁
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
@Override
public void multiUnlock(Collection<String> lockKeys) {
org.redisson.api.RLock[] rLocks = lockKeys.stream()
.map(redissonClient::getLock)
.toArray(org.redisson.api.RLock[]::new);
redissonClient.getMultiLock(rLocks).unlock();
}
}
4. 静态工具类(DistributedLockTool.java)
typescript
package com.data.redis;
import com.data.redis.redisson.DistributedLocker;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
/**
* 分布式锁静态工具类(业务层直接调用入口)
* @author 2021/5/21
*/
public class DistributedLockTool {
// 由Spring自动注入DistributedLocker实现类
private static DistributedLocker distributedLocker;
// 提供setter方法,供Spring配置类注入
public static void setDistributedLocker(DistributedLocker distributedLocker) {
DistributedLockTool.distributedLocker = distributedLocker;
}
/**
* 获取单点锁
* @param lockKey 锁key
* @param leaseTime 持有时间(-1=自动续期)
* @param waitTime 申请超时时间
* @param unit 时间单位
* @return 是否获取成功
*/
public static boolean lock(String lockKey, long leaseTime, long waitTime, TimeUnit unit) {
checkLockerInit();
return distributedLocker.lock(lockKey, leaseTime, waitTime, unit);
}
/**
* 获取联锁(多key)
* @param lockKeys 锁key集合
* @param leaseTime 持有时间(-1=自动续期)
* @param waitTime 申请超时时间
* @param unit 时间单位
* @return 是否获取成功
*/
public static boolean multiLock(Collection<String> lockKeys, long leaseTime, long waitTime, TimeUnit unit) {
checkLockerInit();
return distributedLocker.multiLock(lockKeys, leaseTime, waitTime, unit);
}
/**
* 释放单点锁
* @param lockKey 锁key
*/
public static void unlock(String lockKey) {
checkLockerInit();
distributedLocker.unlock(lockKey);
}
/**
* 释放联锁
* @param lockKeys 锁key集合
*/
public static void multiUnlock(Collection<String> lockKeys) {
checkLockerInit();
distributedLocker.multiUnlock(lockKeys);
}
/**
* 检查DistributedLocker是否已初始化(避免空指针)
*/
private static void checkLockerInit() {
if (distributedLocker == null) {
throw new IllegalStateException("分布式锁组件未初始化,请检查Redisson配置是否正确");
}
}
}
5. 自动配置类(RedissonAutoConfiguration.java)
java
package com.data.redis.redisson;
import com.data.redis.DistributedLockTool;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Redisson自动配置类(适配Spring Boot,支持单机/集群模式)
* @author 2021/5/21
*/
@Configuration
@ConditionalOnClass(Config.class) // 存在Redisson的Config类时才生效
@EnableConfigurationProperties(RedisProperties.class) // 启用RedisProperties配置绑定
public class RedissonAutoConfiguration {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(RedissonAutoConfiguration.class);
private final RedisProperties redisProperties;
// 注入Spring Boot默认的Redis配置(application.yml中的spring.redis配置)
public RedissonAutoConfiguration(RedisProperties redisProperties) {
this.redisProperties = redisProperties;
}
/**
* 初始化RedissonClient(自动适配单机/集群模式)
* @return RedissonClient实例
*/
@Bean
public RedissonClient redissonClient() {
int timeout = 3000; // 默认连接超时时间:3秒
if (redisProperties.getTimeout() != null) {
// 转换为毫秒(RedisProperties的timeout单位是秒)
timeout = redisProperties.getTimeout().getSeconds() > 0 ?
(int) redisProperties.getTimeout().toMillis() : timeout;
}
Config config = new Config();
// 适配单机模式(默认)和集群模式
if (redisProperties.getCluster() == null || redisProperties.getCluster().getNodes().isEmpty()) {
logger.info("【Redisson】初始化单机模式配置,地址:{}:{}", redisProperties.getHost(), redisProperties.getPort());
// 单机模式配置
Config.SingleServerConfig singleServerConfig = config.useSingleServer()
.setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort())
.setTimeout(timeout) // 连接超时时间
.setConnectionPoolSize(64) // 连接池最大容量
.setConnectionMinimumIdleSize(10); // 连接池最小空闲连接数
// 配置Redis密码(如果有)
if (redisProperties.getPassword() != null && !redisProperties.getPassword().trim().isEmpty()) {
singleServerConfig.setPassword(redisProperties.getPassword());
}
} else {
logger.info("【Redisson】初始化集群模式配置,节点:{}", redisProperties.getCluster().getNodes());
// 集群模式配置
String[] nodeAddresses = redisProperties.getCluster().getNodes().stream()
.map(node -> "redis://" + node)
.toArray(String[]::new);
Config.ClusterServersConfig clusterServersConfig = config.useClusterServers()
.addNodeAddress(nodeAddresses)
.setTimeout(timeout)
.setConnectTimeout(3000) // 集群节点连接超时时间
.setIdleConnectionTimeout(600000); // 空闲连接超时时间(10分钟)
if (redisProperties.getPassword() != null && !redisProperties.getPassword().trim().isEmpty()) {
clusterServersConfig.setPassword(redisProperties.getPassword());
}
}
return Redisson.create(config);
}
/**
* 初始化分布式锁实现类,并注入到静态工具类
* @param redissonClient RedissonClient实例(由上面的@Bean方法提供)
* @return DistributedLocker实现类
*/
@Bean
@ConditionalOnBean(RedissonClient.class) // 存在RedissonClient时才初始化
public DistributedLocker distributedLocker(RedissonClient redissonClient) {
RedissonDistributedLocker locker = new RedissonDistributedLocker(redissonClient);
// 注入到静态工具类,供业务层直接调用
DistributedLockTool.setDistributedLocker(locker);
return locker;
}
}
三、依赖配置(Maven/Gradle)
1. Maven(pom.xml)
xml
<!-- Spring Boot Redis自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Redisson核心依赖(兼容Spring Boot) -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.23.3</version> <!-- 推荐使用稳定版,与Redis版本兼容 -->
</dependency>
<!-- 若使用Spring Cloud,需确保与Spring Boot版本匹配 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2023.0.4</version> <!-- 根据实际使用的Spring Cloud版本调整 -->
<type>pom</type>
<scope>import</scope>
</dependency>
2. Gradle(build.gradle)
java
// Spring Boot Redis自动配置
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
// Redisson核心依赖
implementation 'org.redisson:redisson-spring-boot-starter:3.23.3'
// Spring Cloud依赖(根据实际版本调整)
implementation platform('org.springframework.cloud:spring-cloud-dependencies:2023.0.4')
四、使用示例(业务层调用)
1. 单点锁使用场景(如订单创建防重复提交)
kotlin
import com.data.redis.DistributedLockTool;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class OrderService {
/**
* 创建订单(防重复提交)
* @param userId 用户ID
* @param orderNo 订单号(唯一标识)
* @return 订单创建结果
*/
public String createOrder(Long userId, String orderNo) {
// 1. 设计锁key:业务模块:资源标识:唯一ID(确保锁的粒度合理)
String lockKey = "order:create:" + orderNo;
try {
// 2. 获取锁:申请超时3秒,持有锁5秒(若业务耗时较长,设为-1自动续期)
boolean lockSuccess = DistributedLockTool.lock(lockKey, 5, 3, TimeUnit.SECONDS);
if (!lockSuccess) {
// 3. 锁获取失败(如超时),返回友好提示
return "操作过于频繁,请稍后再试";
}
// 4. 锁获取成功,执行核心业务逻辑(如创建订单、扣减库存等)
System.out.println("订单创建成功,orderNo:" + orderNo);
return "订单创建成功";
} catch (Exception e) {
// 5. 业务异常处理
logger.error("创建订单失败,orderNo:{}", orderNo, e);
return "订单创建失败";
} finally {
// 6. 释放锁(必须在finally中执行,确保锁一定被释放)
DistributedLockTool.unlock(lockKey);
}
}
}
2. 联锁使用场景(如转账时锁定转出/转入账户)
java
import com.data.redis.DistributedLockTool;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Service
public class TransferService {
/**
* 账户转账(锁定转出和转入账户,避免并发问题)
* @param fromAccount 转出账户
* @param toAccount 转入账户
* @param amount 转账金额
* @return 转账结果
*/
public String transfer(String fromAccount, String toAccount, BigDecimal amount) {
// 1. 设计联锁key:按固定顺序排序(避免死锁)
String lockKey1 = "account:lock:" + fromAccount;
String lockKey2 = "account:lock:" + toAccount;
List<String> lockKeys = Arrays.asList(lockKey1, lockKey2);
try {
// 2. 获取联锁:申请超时5秒,持有锁10秒(自动续期设为-1)
boolean lockSuccess = DistributedLockTool.multiLock(lockKeys, 10, 5, TimeUnit.SECONDS);
if (!lockSuccess) {
return "转账繁忙,请稍后再试";
}
// 3. 执行转账业务逻辑(扣减转出账户金额,增加转入账户金额)
System.out.println("转账成功:" + fromAccount + " -> " + toAccount + ",金额:" + amount);
return "转账成功";
} catch (Exception e) {
logger.error("转账失败,from:{},to:{}", fromAccount, toAccount, e);
return "转账失败";
} finally {
// 4. 释放联锁
DistributedLockTool.multiUnlock(lockKeys);
}
}
}
五、关键配置说明(application.yml)
yaml
spring:
redis:
# 单机模式配置
host: 127.0.0.1
port: 6379
password: 123456 # Redis密码(无密码则省略)
timeout: 3000 # 连接超时时间(秒)
# 集群模式配置(单机模式时注释)
# cluster:
# nodes:
# - 192.168.1.100:6379
# - 192.168.1.101:6379
# - 192.168.1.102:6379
# Redisson额外配置(可选)
redisson:
codec: org.redisson.codec.JsonJacksonCodec # 序列化方式(默认Jackson)
threads: 4 # 业务线程池大小
netty-threads: 8 # Netty线程池大小
六、注意事项(避坑指南)
- 锁key设计规范:
必须保证锁key的唯一性和粒度合理性,建议格式:业务模块:资源类型:唯一标识(如inventory:deduct:1001),避免锁粒度过粗(导致并发低)或过细(导致锁过多)。
- 避免死锁:
使用联锁时,必须按固定顺序排列锁key(如按字典序排序),避免两个线程同时持有部分锁,互相等待对方释放。
- 锁释放时机:
必须在finally块中释放锁,确保即使业务异常,锁也能正常释放,避免死锁。
- 自动续期场景:
当业务耗时不确定时(如大文件处理),将leaseTime设为-1,Redisson会自动续期锁(默认每30秒续期一次),避免锁提前释放。
- Redis集群可靠性:
生产环境建议使用Redis集群(主从+哨兵或Redis Cluster),确保Redisson客户端能自动切换节点,避免单点故障导致锁失效。
- 并发量控制:
连接池大小(connectionPoolSize)建议根据Redis性能和业务并发量调整(默认64),避免连接池耗尽导致锁获取超时。
七、完整组件清单(可直接复制集成)
| 包路径/类名 | 作用 |
|---|---|
| com.data.redis.DistributedLockTool | 静态调用入口,简化业务使用 |
| com.data.redis.redisson.DistributedLocker | 分布式锁核心接口,定义规范 |
| com.data.redis.redisson.RedissonDistributedLocker | 接口实现,基于Redisson封装 |
| com.data.redis.redisson.RedissonAutoConfiguration | 自动配置类,适配Spring Boot |
| pom.xml/build.gradle | 依赖配置,引入Redisson和Redis |
| application.yml | Redis和Redisson配置 |