1.分布式锁
之前用的是redis的set NX EX 手动设了一个过期时间但是存在自动续期问题比如
解锁
A线程拿到锁执行业务
但是业务还没执行完就自动解锁
B拿到锁执行业务
AB并发执行
A执行完直接删除B的锁(Lua脚本有效解决先比较value值相同才删)
但是AB并发问题无法解决所以引入了redisson的watchdog
Rlock lock=new RedissonClient();
try{
lock.trylock(3,-1,key) //拿锁没拿到等待3秒再拿,-1代表开启看门狗
}
catch(Execption e){
Throw Exception(e);
}
finnally{
if(lock.isHeldCurrentThread()) //判断是否是当前线程
{
lock.unlock;
}
}
2.ZSET滑动窗口限流
原理:ZSET集合有一个score score用于存时间戳用来做范围查询 ZCARD查询一个窗口内的元素数量判断请求书是否超出最大请求数
我是用自定义注解加上AOP切面来实现的
1.自定义了一个注解@RateLimit
其中包括四个属性
{
key()
window_time()
max_request()
UserIdArgs()
}
然后这个注解放到Controller的api接口上传入这四个参数
然后AOP切面做了一个获取参数的操作
resolveArgs()方法
通过反射的方式去获取切入点的MethodSignature
通过signature获取参数parameters数组
还有args数组
遍历parameters数组
通过getAnotation判断第一个值是不是RequstParam注解然后在判断参数名是不是传入的参数名
同理通过getAnotation判断第一个值是不是PathParam注解然后在判断参数名是不是传入的参数名
把parademeters数组遍历完 但是有个问题就是一定在注解里显示写出来
然后获取到参数名后组成key执行Lua脚本
Lua脚本主要做的就是
先删除窗口外的所有值用zremrangebyscore 并且算出来窗户口的额左边界值让删除的判定是小于这个左边界值 redis.call('zremrangebyscore', key,'-inf', '('.. min_time)
然后zcard计数当前窗口的请求数如果当前数量为4(我设置的最大请求数是5)此时小于最大请求数就返回4 如果此时请求数量为5那么返回的就是6就是当前是第几个请求
这样在count判断中只用>max_request即可
如果大于就抛业务异常请求过于频繁
如果不大于就继续执行切点方法 return JoinPoint.proceed();
