文章目录
前言
在高并发的场景中,接口限流一般是必不可少的,一方面是为了保护系统的安全,避免某个点出问题造成雪崩效应,另一方面也可以防止一些恶意或者非正常的请求,当然有时候与第三方打交道时,也会遇到第三方接口限制访问次数的场景,这也是限流的一种使用场景。
限流算法
1、计数器
2、漏桶算法
3、令牌桶算法
限流的算法逻辑都比较简单,本文不做详细介绍,不理解的可以自行查阅相关资料,本次Redis应用实战参考gateway网关的实现方式,采用令牌桶算法实现。
环境准备
使用start.spring.io快速构建一个springboot项目
项目目录结构
代码实现
1、先准备一个自定义的限流注解
import java.lang.annotation.*;
/**
* 限流注解,基于令牌桶算法实现
*/
@Target({
ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimit {
/**
* 限流唯一标识(请求的ip+方法类+方法名+key)
*
* @return
*/
String key() default "";
/**
* 生成令牌的速率
* @return
*/
int replenishRate();
/**
* 总容量
* @return
*/
int burstCapacity();
}
自义定拦截器,处理所有带RateLimit注解的方法,因为要用到AOP,所以先引入AOP相关的jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、RateLimitAspect 切面
RateLimitAspect切面类,对标有RateLimit注解的方法做处理。
import com.wyl.redislimitdemo.annotation.RateLimit;
import com.wyl.redislimitdemo.util.IPUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.time.Instant;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@Aspect
@Configuration
public class RateLimitAspect {
@Resource
private RedisTemplate<String, Serializable> redisTemplate;
@Resource
private Def