第一点 导入配置
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.12.0</version>
</dependency>
spring.redis.port=6379
spring.redis.host=***.***.***.***
第二点 配置 分布式锁 和 redissonClient 的@bean配置
@Configuration
public class RedissonClientConfig {
@Bean
public RedissonClient redissonClient(){
//创建一个Redisson配置对象 Config。
Config config = new Config();
//调用 useSingleServer 方法,选择单机模式,并指定 Redis 服务器的地址
config.useSingleServer().setAddress("redis://***.***.***.***:6379");
//调用 setConnectionMinimumIdleSize 方法,设置连接池最小空闲连接数为 10。
config.useSingleServer().setConnectionMinimumIdleSize(10);
//调用 Redisson.create 方法,创建一个 RedissonClient 对象,该对象可以用于连接和操作 Redis 数据库
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
//注意:这段代码连接的 Redis 服务器地址为 "redis://***.***.***.***:6379",如果该地址是无法连接成功的话,需要确认 Redis 服务器是否已经启动,并检查网络连接是否正常。另外,还需要根据实际情况调整连接池参数,以保证系统的性能和稳定性。
第三点 可以写 简略版分布式锁
//上锁/下锁
@RequestMapping("/lock")
public Result lock(Long id){
//每一把锁 都有直接的解锁线程在底层 所以线程 无法互相开锁
//创建锁 获取到锁对象Rlock
RLock lock = redissonClient.getLock("category_" + id);
try {
//判断锁的状态
boolean flag = lock.tryLock();
if(!flag){
return Result.error(501,"访问失败");
}
System.out.println("开始");
//给锁加时长
lock.lock(3, TimeUnit.SECONDS);
//沉睡3秒
Thread.sleep(3000L);
System.out.println("结束");
} catch (Exception e) {
e.printStackTrace();
}finally {
//强制释放锁在 finally 块中强制释放锁,确保锁一定会被释放,避免出现死锁等问题
lock.forceUnlock();
}
return Result.success(null,"成功");
}
//注意:需要注意的是,分布式锁的使用场景需要谨慎考虑,因为如果并发量过高,可能会造成锁争用严重,导致系统性能下降。此外,在设置锁的超时时间时,应该根据实际情况进行调整,避免锁的超时时间设置太短或太长,从而影响系统性能和稳定性。
第四点 限流操作
//限流 每5秒执行一次 令牌桶算法
@RequestMapping("/rateLimit")
public Result rateLimit(Long id){
//创建一个名为 "category_rateLimiter_" + id 的令牌桶对象,并使用 RedissonClient 对象 redissonClient 获取该令牌桶对象 RRateLimiter
RRateLimiter rateLimiter = redissonClient.getRateLimiter("category_rateLimiter_" + id);
//使用 trySetRate() 方法设置令牌发放速率,每 5 秒发放 1 个令牌
rateLimiter.trySetRate(RateType.OVERALL,1,5, RateIntervalUnit.SECONDS);
//使用 tryAcquire() 方法尝试从令牌桶中获取一个令牌,如果获取令牌成功,则可以进行访问;否则返回访问失败提示信息。此处限流的方式是控制请求发送的速率,使用令牌桶算法来平稳地控制进入系统的请求数量和频率
boolean flag = rateLimiter.tryAcquire(1);
if(!flag){
return Result.error(501,"访问频繁");
}
return Result.success(null,"成功");
}
//注意:令牌桶算法能够平滑地限制请求的发送速率,避免系统瞬间被大量请求压垮,但是如果访问者在短时间内发起大量请求,也有可能导致系统出现性能问题。因此,在设计限流策略时,还需要对请求频率的控制进行限制,比如设置一个固定的时间窗口内最多允许发送多少个请求。
//于 Redisson 实现的限流示例 最多容纳5个车位
@RequestMapping("/semaphore")
public Result semaphore(Long id){
//限流
RSemaphore semaphore = redissonClient.getSemaphore("category_semaphore_" + id);
//设置信号量的容量,即最多容纳 5 个车位,使用 trySetPermits() 方法设置。
semaphore.trySetPermits(5);
//如果需要展示限流效果,可以使用 Thread.sleep() 方法沉睡一段时间,模拟使用者占用许可的时间
try {
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
//使用 tryAcquire() 方法尝试获取一个许可,如果获取许可成功,则进入访问限制区;否则返回访问失败提示信息。此处限流的方式是使用信号量控制并发访问的数量,当已有 5 个访问者时,后续的访问者需要等待之前的访问者释放许可才能进行访问
boolean flag = semaphore.tryAcquire(1);
if(!flag){
return Result.error(501,"访问受限失败");
}
return Result.success(null,"成功");
}
//注意:限流的实现必须适合具体场景,不能滥用,否则可能会影响正常业务操作,甚至导致系统崩溃。因此,在设计限流策略时,需要综合考虑请求频率、资源情况、业务特点等因素,在性能和稳定性之间寻找平衡点。