接口限流的简单实现

需求分析:

1、什么是接口限流:

接口限流是一种控制访问特定接口的请求数量的机制,以防止系统过载并确保服务的稳定性和可用性。在软件架构中,接口限流通常用于以下几个目的:

  1. 资源保护:防止服务器因为过多的并发请求而耗尽资源,如数据库连接、线程或内存。
  2. 性能保证:通过限制请求的速率,确保系统在高负载下仍能保持可接受的响应时间。
  3. 防止滥用:避免恶意用户或自动化脚本对系统进行滥用,如防止暴力破解尝试或分布式拒绝服务(DDoS)攻击。
  4. 服务降级:在系统负载过高时,通过限流可以优先保证核心业务逻辑的运行,而非核心服务可以暂时降级。
  5. 成本控制:通过限流可以避免不必要的硬件扩展,从而控制成本。
  6. 遵守协议:满足服务级别协议(SLA)的要求,确保服务提供商能够按照协议提供服务。

接口限流可以通过多种方式实现,包括:

  • 时间窗口计数器:在固定的时间窗口内(如每秒)限制请求的数量。
  • 滑动窗口计数器:使用多个时间窗口来平滑请求速率,避免在时间窗口边界处的请求峰值。
  • 令牌桶算法:以固定速率生成令牌,请求在获取令牌后才能被处理,允许一定程度的突发流量。
  • 漏桶算法:请求按照固定速率从桶中流出,超出桶容量的请求被丢弃,平滑处理请求。

在实际应用中,接口限流可以通过编程实现(如使用Java中的并发工具),也可以通过使用现成的限流库(如Google的Guava库中的RateLimiter),或者利用反向代理和负载均衡器(如Nginx)来实现。此外,一些云服务提供商也提供了限流服务,可以直接集成到云环境中。

本次使用AOP+自定义注解+redis的方法来实现部分关键接口的限流

2、简单的原理如图所示

3、设计思路:

1、写一个自定义注解接收一个参数count 次/分钟

2、以方法名+用户ids作为key,次数作为value

3、每次请求前先从redis拿数据决定怎么处理

4、什么是AOP(面向切面编程)

AOP 是一种编程范式,它允许程序者将横切关注点(如日志记录、事务管理、安全性等)与业务逻辑分离,从而提高程序的模块化和可维护性。在 Java 中,AOP 的实现通常依赖于特定的框架,如 Spring AOP 或 AspectJ。

5、AOP 的核心概念:

  1. 切面(Aspect) :表示一个模块化的横切关注点。
  2. 连接点(Join point) :程序执行的特定点,如方法的调用或处理异常。
  3. 切点(Pointcut) :匹配连接点的表达式,用于指定切面应该在何处应用。
  4. 通知(Advice) :在切点处执行的动作,如前置、后置、环绕等。
  5. 目标对象(Target Object) :被通知(Advice)的对象。
  6. 代理(Proxy) :用于在不修改目标对象的情况下,通过引入额外功能(如日志、事务)来创建目标对象的一个代理。

6、AOP可以简单的如下图描述:

最终打算使用AOP+自定义注解的方式来实现

7、自定义注解

在 Java 中,注解(Annotation)是一种特殊的接口,它可以用来标记类、方法或变量,以提供元数据。自定义注解允许开发者定义自己的注解类型,以便于在代码中标记特定的行为或配置。

自定义注解可以包含以下元素:

  1. 元注解(Meta-Annotations)

    • 用于注解其它注解的注解,提供关于注解的信息。常见的元注解包括:

      • @Target:指定注解可以用于哪些元素(如类、方法、参数等)。
      • @Retention:指定注解的保留策略,决定注解在何时可用(如源码、编译时、运行时)。
      • @Documented:指定注解应该被Javadoc工具记录在文档中。
      • @Inherited:指定注解是否被子类继承。
  2. 成员变量

    • 自定义注解可以有0个或多个成员变量,这些变量被称为注解的属性。成员变量的数据类型必须是基本数据类型、String、Class、enum、注解或这些类型的数组。
  3. 默认值

    • 注解的属性可以指定默认值,这样在使用注解时可以省略该属性。
  4. 标记注解(Marker Annotations)

    • 如果自定义注解不包含任何属性,它就是一个标记注解,用来简单地标记某个元素。
  5. 单成员注解

    • 如果自定义注解只包含一个成员变量,那么这个成员变量可以不用声明,而是直接在注解使用时指定该值。

开始实现:

1、首先得先写一个自定义的注解

java 复制代码
package com.ruoyi.common.annotation;
​
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
​
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Limit {
    /**
     * 限制次数(每分钟)
     * @return
     */
    int count() default 5;
}
​

2、写一个切面类来处理逻辑

java 复制代码
@Aspect
@Component
public class LimitAspect {
​
    @Autowired
    private RedisTemplate redisTemplate;
​
    // 定义一个切点,匹配所有标记Limit注解的方法
    @Pointcut("@annotation(com.common.annotation.Limit)")
    public void LimitMethod() {}
​
    // 前置通知:在方法执行前执行
    @Before("LimitMethod()")
    public void beforeMethod(JoinPoint joinPoint) {
        //获取注解的count
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Limit annotation = signature.getMethod().getAnnotation(Limit.class);
        int count = annotation.count();
        //拼接redis的key
        String name = signature.getMethod().getName();
        //这里看业务自己选择
        String userId = "1";
        String key = name + userId;
        Object o = redisTemplate.opsForValue().get(key);
        //第一次访问
        if (o == null) {
            redisTemplate.opsForValue().increment(key, 1);
            // 设置键的过期时间为五分钟(300秒)
            redisTemplate.expire(key, 5, TimeUnit.MINUTES);
        } else {
            int redisCount = (int) o;
            //未超过阈值
            if (redisCount < count) {
                redisTemplate.opsForValue().increment(key, 1);
            }
            //达到阈值后
            else {
                throw new RuntimeException("超过请求限制,请五分钟后在请求");
            }
        }
    }
}

3、简单写个接口测试一下:

less 复制代码
@Limit(count = 10)
@GetMapping(value = "/test")
public AjaxResult test() {
    return AjaxResult.success();
}

测试结果:

未点击时

第十一次时

有条件的朋友可以来个一件三连支持一下

如果可以的话顺便关注一下公众号:想摆烂的码农小郑

相关推荐
zopple1 小时前
常见的 Spring 项目目录结构
java·后端·spring
cjy0001113 小时前
springboot的 nacos 配置获取不到导致启动失败及日志不输出问题
java·spring boot·后端
小江的记录本4 小时前
【事务】Spring Framework核心——事务管理:ACID特性、隔离级别、传播行为、@Transactional底层原理、失效场景
java·数据库·分布式·后端·sql·spring·面试
sheji34164 小时前
【开题答辩全过程】以 基于springboot的校园失物招领系统为例,包含答辩的问题和答案
java·spring boot·后端
程序员cxuan4 小时前
人麻了,谁把我 ssh 干没了
人工智能·后端·程序员
wuyikeer6 小时前
Spring Framework 中文官方文档
java·后端·spring
Victor3566 小时前
MongoDB(61)如何避免大文档带来的性能问题?
后端
Victor3566 小时前
MongoDB(62)如何避免锁定问题?
后端
wuyikeer6 小时前
Spring BOOT 启动参数
java·spring boot·后端
子木HAPPY阳VIP7 小时前
Ubuntu 22.04 VMware 设置固定IP配置
人工智能·后端·目标检测·机器学习·目标跟踪