目录
一.为什么要使用分布式锁?
二.Redisson 的基本使用:
1.添加 Redisson 依赖:
2.在 application.yml 配置 Redis:
3. 创建 Redisson 客户端:
(1)单节点模式:
(2)集群模式:
4.注入RedissonClient:
5.使用 Redisson 存储和获取值:
三.配置集群连接池:
1. Redisson 集群连接池配置项:
2. 配置 Redis 集群的连接池:
四.如何在Boot项目中使用Redission实现分布式锁?
1.引入 Redisson 依赖:
2.配置 Redisson:
3.在 Spring Boot 中注入 RedissonClient:
4.使用分布式锁:
Redisson 是一个基于 Redis 的高效 Java 客户端,封装了 Redis 的大部分功能,提供了更为丰富和高效的操作接口,能够帮助开发者更便捷地进行分布式缓存、分布式锁、分布式集合等操作。它不仅支持 Redis 的基本操作,还提供了更多的高级功能,如分布式锁、分布式集合、分布式计数器等,可以大大简化分布式应用的开发。
一.为什么要使用分布式锁?
分布式锁是解决 分布式系统中的资源竞争问题 的一种有效机制。在高并发分布式系统中,多个服务节点可能同时访问同一资源(如数据库、文件系统等)。这种竞争可能导致数据的不一致性、重复操作、死锁等问题,因此,使用分布式锁来保证同一时刻只有一个节点能够访问共享资源,从而确保系统的正确性和稳定性。
在单机系统中,当多个线程访问共享资源时,操作系统通常使用互斥锁(如 Java 中的 synchronized
或 ReentrantLock
)来保证同一时刻只有一个线程能访问该资源。而在分布式系统中,资源通常分布在多个服务实例或节点上,单纯的本地锁(如 synchronized
)无法跨节点进行协调,因此需要分布式锁来确保不同节点间的同步。
使用分布式锁的方式:
- 所有节点都尝试获取锁,如果一个节点获得了锁,它将执行任务。
- 其他节点则会等待或者跳过执行该任务,避免重复执行。
使用场景:
- 防止多次执行相同的任务
- 确保分布式系统中资源的独占访问
- 控制并发数量
二.Redisson 的基本使用:
1.添加 Redisson 依赖:
在项目中使用 Redisson,首先需要添加 Redisson 的 Maven 依赖:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.1</version> <!-- 请根据最新版本替换 -->
</dependency>
2.在 application.yml
配置 Redis:
# 单节点
redisson:
address: redis://127.0.0.1:6379
# 集群
redisson:
cluster:
addresses:
- redis://127.0.0.1:7000
- redis://127.0.0.1:7001
- redis://127.0.0.1:7002
3. 创建 Redisson 客户端:
Redisson 提供了两种方式来创建客户端:单节点模式 和 集群模式。
(1)单节点模式:
在单节点模式下,我们只需要连接到一个 Redis 实例,在配置类中:
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.redisson.Redisson;
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redissonClient() {
// 配置单节点 Redis
Config config = new Config();
SingleServerConfig serverConfig = config.useSingleServer();
serverConfig.setAddress("redis://127.0.0.1:6379");
serverConfig.setPassword("yourpassword");
return Redisson.create(config);
}
}
(2)集群模式:
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.ClusterServersConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.redisson.Redisson;
import java.util.List;
@Configuration
public class RedissonClusterConfig {
// 从配置文件中读取 Redis 集群的地址
@Value("${redisson.cluster.addresses}")
private List<String> clusterAddresses;
@Bean
public RedissonClient redissonClient() {
// 创建 Redis 配置对象
Config config = new Config();
// 配置集群
ClusterServersConfig clusterConfig = config.useClusterServers();
// 添加集群节点地址
for (String address : clusterAddresses) {
clusterConfig.addNodeAddress(address);
}
// 如果需要配置密码,使用 setPassword 方法
// clusterConfig.setPassword("yourpassword");
// 创建并返回 Redisson 客户端
return Redisson.create(config);
}
}
4.注入RedissonClient:
通过 @Autowired
注入 RedissonClient
到需要使用的服务类中。
import org.redisson.api.RedissonClient;
import org.redisson.api.RMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class RedisService {
@Autowired
private RedissonClient redissonClient;
public void demoMapUsage() {
// 获取 Redis 集群中的分布式 Map
RMap<String, String> map = redissonClient.getMap("myMap");
map.put("name", "Alice");
map.put("age", "30");
System.out.println("Name: " + map.get("name"));
System.out.println("Age: " + map.get("age"));
}
}
5.使用 Redisson 存储和获取值:
RBucket<String>
是 Redisson 提供的一个接口,它代表 Redis 中一个字符串类型的值。我们可以通过它来存储和获取一个键值对。
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class RedisService {
@Autowired
private RedissonClient redissonClient;
// 存储值
public void setValue(String key, String value) {
RBucket<String> bucket = redissonClient.getBucket(key); // 获取 Redis 中的指定 key
bucket.set(value); // 存储值
}
// 获取值
public String getValue(String key) {
RBucket<String> bucket = redissonClient.getBucket(key); // 获取 Redis 中的指定 key
return bucket.get(); // 获取存储的值
}
}
三.配置集群连接池:
在使用 Redisson 配置 Redis 集群时,我们可以通过配置连接池来管理连接的数量、连接的超时时间等。Redisson 提供了灵活的配置方式来定制集群模式的连接池。
1. Redisson 集群连接池配置项:
Redisson 提供了多个与连接池相关的配置项,主要包括以下几个:
- masterConnectionPoolSize:主节点连接池的大小(连接数量)。
- slaveConnectionPoolSize:从节点连接池的大小(连接数量)。
- connectionMinimumIdleSize:连接池中保持的最小空闲连接数。
- connectionPoolSize:连接池的最大连接数。
- idleConnectionTimeout:空闲连接的超时时间。
- connectTimeout:连接的超时时间。
- timeout:操作超时时间(请求的最大等待时间)。
2. 配置 Redis 集群的连接池:
在 application.yml
中配置连接池参数:
redisson:
cluster:
addresses:
- redis://127.0.0.1:7000
- redis://127.0.0.1:7001
- redis://127.0.0.1:7002
# 集群连接池配置
master-connection-pool-size: 100 # 主节点连接池大小
slave-connection-pool-size: 50 # 从节点连接池大小
connection-pool-size: 200 # 总连接池大小
connection-minimum-idle-size: 10 # 最小空闲连接数
idle-connection-timeout: 10000 # 空闲连接超时
connect-timeout: 3000 # 连接超时
timeout: 5000 # 请求超时
配置连接池是确保 Redis 集群高效运行的关键,它能够有效管理连接的数量,提高 Redis 的性能,避免频繁地创建和销毁连接。
如果我们在
application.yml
或application.properties
文件中配置了 Redisson 的连接池参数,并且使用了redisson-spring-boot-starter
,Spring Boot 会自动读取这些配置并初始化连接池。
四.如何在Boot项目中使用Redission实现分布式锁?
在 Spring Boot 项目中使用 Redisson 实现分布式锁,主要涉及到以下几个步骤:
- 引入 Redisson 依赖
- 配置 Redisson 客户端
- 在 Spring Boot 中注入
RedissonClient
- 使用分布式锁
1.引入 Redisson 依赖:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.16.1</version> <!-- 请根据最新版本替换 -->
</dependency>
2.配置 Redisson:
redisson:
# Redis 集群配置
cluster:
# 集群节点地址,多个节点地址用逗号分隔
nodes:
- redis://127.0.0.1:7000
- redis://127.0.0.1:7001
- redis://127.0.0.1:7002
- redis://127.0.0.1:7003
- redis://127.0.0.1:7004
- redis://127.0.0.1:7005
# Redis 密码(如果有密码的话)
password: yourpassword # Redis 的密码
# 连接池配置
connection-pool-size: 100 # 连接池大小
connection-minimum-idle-size: 10 # 最小空闲连接数
idle-connection-timeout: 10000 # 空闲连接超时(毫秒)
connect-timeout: 3000 # 连接超时(毫秒)
timeout: 5000 # 请求超时(毫秒)
retries: 3 # 在获取连接时的最大重试次数
retry-interval: 1000 # Redis 集群模式下的超时时间
wait-timeout: 3000 # 最大等待连接的时间(毫秒)
subscription-mode: false # 集群模式下是否启用超时管理
threads: 16 # 线程池大小
3.在 Spring Boot 中注入 RedissonClient:
在 Spring Boot 中,我们可以通过 @Autowired
注入 RedissonClient
,然后在服务类中使用它进行 Redis 操作。
import org.redisson.api.RLock;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class RedisWithLockService {
@Autowired
private RedissonClient redissonClient;
// 锁的名称
private static final String LOCK_KEY = "myLock";
// 存储到 Redis 中的键
private static final String REDIS_KEY = "userBalance";
// 分布式锁处理业务逻辑
public void updateBalance(String userId, double newBalance) {
// 获取分布式锁
RLock lock = redissonClient.getLock(LOCK_KEY);
try {
// 尝试获取锁,最多等待 10 秒,锁自动释放时间为 30 秒
if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
// 锁获取成功,执行 Redis 操作
System.out.println("Lock acquired, updating balance...");
// 获取当前用户的余额
double currentBalance = getUserBalanceFromRedis(userId);
System.out.println("Current balance: " + currentBalance);
// 更新余额(模拟业务逻辑)
double updatedBalance = currentBalance + newBalance;
System.out.println("Updated balance: " + updatedBalance);
// 将新的余额存储回 Redis
setUserBalanceToRedis(userId, updatedBalance);
} else {
System.out.println("Unable to acquire lock for updating balance.");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 确保释放锁
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
// 获取用户余额(从 Redis 中)
private double getUserBalanceFromRedis(String userId) {
RBucket<Double> bucket = redissonClient.getBucket(REDIS_KEY + ":" + userId);
return bucket.isExists() ? bucket.get() : 0.0; // 如果值存在则获取,如果没有则返回 0
}
// 更新用户余额(存入 Redis)
private void setUserBalanceToRedis(String userId, double balance) {
RBucket<Double> bucket = redissonClient.getBucket(REDIS_KEY + ":" + userId);
bucket.set(balance); // 存储新的余额
}
}
4.使用分布式锁:
在 RedisLockService
中定义了 processWithDistributedLock
方法,调用时,Redisson 将确保在同一时刻只有一个进程/线程可以进入锁的保护区域。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class RedisWithLockController {
@Autowired
private RedisWithLockService redisWithLockService;
// 模拟调用分布式锁更新用户余额的接口
@GetMapping("/updateBalance")
public String updateBalance(@RequestParam String userId, @RequestParam double amount) {
redisWithLockService.updateBalance(userId, amount);
return "Balance update request received for user: " + userId;
}
}
通过访问下面接口地址:
http://localhost:8080/updateBalance?userId=user1&amount=100
查看后端返回数据。
总结:
- Redisson 提供了丰富的 API 用于存储和获取 Redis 中的值。你可以通过
RBucket
等数据结构操作 Redis 中的数据。- 使用 分布式锁 可以确保在多个服务实例之间协调对共享资源(如 Redis 中的数据)的访问。
- Redisson 的分布式锁非常适合用来保护 Redis 中的临界资源,避免高并发访问导致的数据不一致问题。