当前位置:网站首页>记一次使用Redisson踩坑问题
记一次使用Redisson踩坑问题
2022-07-20 15:42:00 【幼儿园里的山大王】
一、需求场景
对一个忘记密码进行邮件发送功能,同一个账号,两分钟内不能发送第二封邮件。这个可以通过redis进行次数限制。思路为:在代码的随后,随便放一个值,时间设置两分钟,然后在代码的最前面,通过redis取出值,如果不为空,那就说明已经发送过一次。
二、出现问题
在网络出现异常的情况下,用户狂点忘记密码进行邮箱发送,出现一种情况就是,请求在同一时间内进入接口,当一个请求进到接口,未进行到代码最后,记录次数到redis中时,就有第二个,第三个请求进来。这个时候次数限制就会出问题。
三、解决方式
一、使用单体应用锁
单体应用锁指的是只能在 一个JVM 进程内有效的锁。我们把这种锁叫做单体应用锁。
单体应用锁是JDK提供的锁,这种锁只能在 一个JVM 下起到作用,
也就是在一个Tomcat内是没有问题的。当存在两个或两个以上的Tomcat时,大量的并发请求分散到不同的Tomcat上,在每一个Tomcat中都可以防止并发的产生,但是在多个Tomcat之间,每个Tomcat中获得锁的这个请求,又产生了并发。这也就是单体应用锁的局限性了,它只能在一个JVM内加锁,而不能从这个应用层面去加锁。
二、使用分布式锁
单体应用锁是在一个JVM进程内有效,无法跨JVM、跨进程。那么分布式锁的定义就出来了,分布式锁就可以跨越多个JVM、跨多个进程的锁,这种锁就叫做分布式锁
1、使用Redisson作为分布式锁,引入对应依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.0</version>
</dependency>
public void test() {
// 1.获取锁,没有获取到锁的会阻塞
// 2.redisson设置一个key的默认过期时间为30s
// 3.redisson会自动续期
//设置lockey
String lockKey = "test";
RLock lock = redisson.getLock(lockKey);
//上锁
/**
* 处理业务执行时间大于锁的时间,自动续期
* 不设置过期时间,默认锁的时间为30s,每1/3的时间就自动续期,业务处理完需要手动释放锁
*/
lock.lock();
//lock.lock(10,TimeUnit.SECONDS); 这种是10秒后锁自动过期,不会有自动续期的机制
//boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS); 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
try {
//模拟业务执行
Thread.sleep(40000);
log.info("模拟业务执行了40s");
} catch (Exception e){
e.printStackTrace();
}finally {
//释放锁
lock.unlock();
}
}
lock.lock(); 是阻塞式等待的,默认加锁时间是30s;如果业务超长,运行期间会自动续期到30s。不用担心业务时间长,锁自动过期被删掉;加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认会在30s内自动过期,不会产生死锁问题;
也可以自己指定解锁时间lock.lock(10,TimeUnit.SECONDS),10秒钟自动解锁,自己指定解锁时间redis不会自动续期;
2、本次是使用UUID+线程名作为分布式锁的key
String redissionKeyValue = SystemTplConst.FORGOT_PASSWORD+"_"+UUID.randomUUID().toString()+Thread.currentThread().getName();
出现问题是使用Jemeter进行压测,同一秒内,打入50个请求,出现每一个请求都能发出邮件。出现这个问题主要是使用的的key有问题,出现每一个请求的key都不一样,也就是说同一个邮箱请求50次,50次的key都不一样,这就导致请求都进入了代码里,相当于没有加锁。最后改为邮箱为锁的key才解决。也就是同一个邮箱,50次请求,然后key是一样的,就回锁住,第一次请求处理完后。第二个请求才会进去。而这个时候redis就有值了。
边栏推荐
- If you know something about deep learning, you can send nature? It is more important to find the right problem and the problem with scientific value
- 密集预测任务的多任务学习(Multi-Task Learning)研究综述 - 优化方法篇
- [bug resolution] visibledeprecationwarning: creating an ndarray from ragged needed sequences
- 4 个简单操作,实现 CPU 轻量级网络 ---- PP-LCNet: A Lightweight CPU Convolutional Neural Network
- 文件映射(mmap)和sendfile和零copy之間的聯系和區別
- 有序矩阵中的第 k 个最小数组和
- Hide & seek introduction -- end-to-end simulation and processing of radio observation data (II)
- Iccv2021 frequency domain image translation: more photo realistic, better identity preserving
- 机器学习—支持向量机理论详细推导(含例题讲解)(一)
- Pandoc安装、使用、快速上手
猜你喜欢
在 Excel 内使用 ODBC 消费 SAP ABAP CDS view
Postman进阶功能
redis6.2 systemd 启动 提示 redis.service: Failed with result ‘protocol‘.
文件映射(mmap)和sendfile和零copy之間的聯系和區別
MySQL ON DELETE CASCADE(级联删除)[猿教程]
HIDE & SEEK 介绍 -- 端到端的模拟和处理无线电观测数据(二)
【VS2019】打印汉字乱码的问题
語義分割-Rethinking BiSeNet For Real-time Semantic Segmentation-2-miou計算
机器学习—支持向量机理论详细推导(含例题讲解)(二)
Another lightweight vit:lite vision transformer with enhanced self attention
随机推荐
The k-th smallest array sum in an ordered matrix
mysql 常用基础命令
Error reporting after matlab 2021b installation activation: solution to license manager error -103
HIDE & SEEK 介紹 -- 端到端的模擬和處理無線電觀測數據(二)
OptaPlanner将弃用DRL(Drools)评分方式!!!
MySQL master-slave replication, read-write separation
Hide & seek introduction -- end-to-end simulation and processing of radio observation data (II)
MySQL ON DELETE CASCADE(级联删除)[猿教程]
How to insert payload into global state after SAP Spartacus successfully reads cart
Kalman Filter 遇到 Deep Learning : 卡尔曼滤波和深度学习有关的论文
云开发寝适闹钟微信小程序源码
HIDE & SEEK 介绍 -- 端到端的模拟和处理无线电观测数据(二)
又一个轻量级 ViT:Lite Vision Transformer with Enhanced Self-Attention
MySQL on delete cascade [tutorial]
docker中mysql远程连接
ICCV2021 频域图像翻译 Frequency Domain Image Translation: More Photo-realistic, Better Identity-preserving
Sword finger offer 20 String representing numeric value
单片机外部中断触发方式:电平触发和边沿触发两者说明
密集预测任务的多任务学习(Multi-Task Learning)研究综述 - 优化方法篇
实现一个《头像循环轮播控件》