写在前面
公司近期在做对外接口的限流,由于是轻量级的处理,所以采用“基于REDIS+LUA脚本”的方式进行访问控制。
当然也可以使用RequestRateLimiterGatewayFilterFactory或者阿里巴巴的sentinel。
SpringCloud - 流量控制(一):基于RequestRateLimiterGatewayFilterFactory的限流
如何编写?
① 定义注解
/**
* 限流注解
* @author ROCKY
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Limiter {
// 限流KEY,用于REDIS的存储
public String key();
// 限流时间(秒)
public int time() default 60;
// 限流次数
public int count() default 100;
// 限流类型
public LimitType limitType() default LimitType.DEFAULT;
}
② 切面处理
/**
* 限流AOP
* @author ROCKY
*/
@Aspect
@Component
@Slf4j
public class LimiterAspect {
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Autowired
private RedisScript<Long> limitScript;
@Before("@annotation(limiter)")
public void doBefore(JoinPoint point, Limiter limiter) throws Throwable {
// 可以使用指定的KEY,也可以自己封装
// final String limiterKey = limiter.key();
final String limiterKey = getLimiterKey(limiter, point);
int time = limiter.time();
int count = limiter.count();
List<Object> keys = Collections.singletonList(limiterKey);
try {
Long number = redisTemplate.execute(limitScript, keys, count, time);
if (StringUtils.isEmpty(number) || number.intValue() > count) {
log.error("限流请求总次数为: '{}', 当前为第'{}'请求, 缓存KEY为: '{}'", count, number.intValue(), limiterKey);
throw new MyException(MyException.LIMITER_IN_THE_CONTROL);
}
} catch (MyException me) {
throw me;
} catch (Exception e) {
throw new RuntimeException("限流控制内部异常,请稍候再试");
}
}
// 获取限流数据的KEY(小写)
public String getLimiterKey(Limiter limiter, JoinPoint point) {
StringBuffer stringBuffer = new StringBuffer(Constants.LIMITER_IN_REDIS_PREFIX_KEY);
if (limiter.limitType() == LimitType.IP) {
stringBuffer.append(IpUtils.getIpAddr(ServletUtils.getRequest())).append("-");
}
if (limiter.limitType() == LimitType.USER) {
// 从RequestContextHolder中获取用户名
...
}
if (limiter.limitType() == LimitType.TOKEN) {
// 从RequestContextHolder中获取TOKEN
...
}
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
Class<?> targetClass = method.getDeclaringClass();
stringBuffer.append(targetClass.getName()).append("-").append(method.

本文介绍了一种轻量级的接口限流方案,利用Redis与Lua脚本结合进行访问控制。通过定义限流注解、AOP切面处理及Lua脚本,实现了不同类型的限流策略。
最低0.47元/天 解锁文章
3115

被折叠的 条评论
为什么被折叠?



