记一次使用Redisson踩坑问题

一、需求场景

对一个忘记密码进行邮件发送功能,同一个账号,两分钟内不能发送第二封邮件。这个可以通过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就有值了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值