学习总结录 学习总结录
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
  • 案例实践

  • 工具使用

  • 项目搭建

  • 服务治理

    • 服务治理-统一白名单
    • 服务治理-超时熔断
    • 服务治理-调用限流
      • 一、需求背景
      • 二、方案设计
      • 三、实现方案
        • 1、自定义注解
        • 2、服务实现
        • 3、切面实现
      • 四、案例测试
        • 1、依赖映入
        • 2、控制层调用
      • 参考
    • 服务治理-自定义拦截
  • ORM框架

  • MiniSpring

  • 案例归档
  • 服务治理
旭日
2023-04-20
目录

服务治理-调用限流

# 一、需求背景

对于一个业务服务通常它的请求是稳定在一个可承载的安全体量范围,但是对于一些突发或者恶意攻击的访问,我们需要把这些访问拦截掉,避免系统被这样的流量拖垮。

对于保护的接口,我们的方式如下:

  • 前端节流
  • 后端拦截超过一定限制的请求

# 二、方案设计

  • 使用自定义注解和切面技术,拦截需要被限流保护的接口。
  • 拦截到方法后,通过RateLimiter给方法设定已配置好的调用限流处理。

# 三、实现方案

# 1、自定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DoLimit {

    /**
     * 限流许可量
     */
    double permitsPerSecond() default 0D;

    /**
     * 失败结果 JSON
     */
    String returnJson() default "";

}

# 2、服务实现

常量参数

public class LimitConstant {
    public static Map<String, RateLimiter> rateLimiterMap = Collections.synchronizedMap(new HashMap<String, RateLimiter>());
}

后续接口实现,从这里根据key来获取到RateLimiter对象,然后进行对应请求次数判断。

接口定义

public interface LimitService {
    Object access(ProceedingJoinPoint point, Method method, DoLimit doLimit, Object[] args) throws Throwable;
}

接口实现

@Service
public class LimitServiceImpl implements LimitService {
    @Override
    public Object access(ProceedingJoinPoint point, Method method, DoLimit doLimit, Object[] args) throws Throwable {
        if (0 == doLimit.permitsPerSecond()) {
            return point.proceed();
        }
        // 获取类名
        String clazzName = point.getTarget().getClass().getName();
        // 获取方法名
        String methodName = method.getName();
        // key
        String key = clazzName + "." + methodName;
        // 如果获取到的对象为空,放入map中
        if (null == LimitConstant.rateLimiterMap.get(key)) {
            LimitConstant.rateLimiterMap.put(key, RateLimiter.create(doLimit.permitsPerSecond()));
        }
        // 根据key获取到rateLimiter对象
        RateLimiter rateLimiter = LimitConstant.rateLimiterMap.get(key);
        // 判断是否请求超出限制
        if (rateLimiter.tryAcquire()) {
            return point.proceed();
        }
        return JSON.parseObject(doLimit.returnJson(), method.getReturnType());
    }
}

# 3、切面实现

@Aspect
@Component
public class LimitPoint {

    @Autowired
    private LimitServiceImpl limitService;

    @Pointcut("@annotation(me.xu.limit.annotation.DoLimit)")
    public void aopPoint() {
    }

    @Around("aopPoint() && @annotation(doLimit)")
    public Object doRouter(ProceedingJoinPoint point, DoLimit doLimit) throws Throwable {
        return limitService.access(point, getMethod(point), doLimit, point.getArgs());
    }

    private Method getMethod(JoinPoint point) throws NoSuchMethodException {
        Signature sig = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) sig;
        return point.getTarget().getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
    }

}

# 四、案例测试

# 1、依赖映入

    <dependency>
        <groupId>me.xu</groupId>
        <artifactId>spring-limit</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>

# 2、控制层调用

@RestController
public class UserController {

    private Logger logger = LoggerFactory.getLogger(UserController.class);

    /**
     * 测试:http://localhost:8080/api/queryUserInfo?userId=aaa
     */
    @DoLimit(permitsPerSecond = 1, returnJson = "{\"code\":\"1111\",\"info\":\"调用方法超过最大次数,限流返回!\"}")
    @RequestMapping(path = "/api/queryUserInfo", method = RequestMethod.GET)
    public UserInfo queryUserInfo(@RequestParam String userId) {
        logger.info("查询用户信息,userId:{}", userId);
        return new UserInfo("wxx:" + userId, 19, "地址");
    }

}
  • @DoLimit设置了错误返回结果和每秒请求数量

# 参考

服务治理-调用限流 (opens new window)

上次更新: 2024/06/29, 15:13:44
服务治理-超时熔断
服务治理-自定义拦截

← 服务治理-超时熔断 服务治理-自定义拦截→

最近更新
01
基础概念
10-31
02
Pytorch
10-30
03
Numpy
10-30
更多文章>
Theme by Vdoing | Copyright © 2021-2024 旭日 | 蜀ICP备2021000788号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式