接口限流的简单实现

需求分析:

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();
}

测试结果:

未点击时

第十一次时

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

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

相关推荐
2401_854391085 分钟前
高效开发:SpringBoot网上租赁系统实现细节
java·spring boot·后端
Cikiss13 分钟前
微服务实战——SpringCache 整合 Redis
java·redis·后端·微服务
Cikiss15 分钟前
微服务实战——平台属性
java·数据库·后端·微服务
OEC小胖胖28 分钟前
Spring Boot + MyBatis 项目中常用注解详解(万字长篇解读)
java·spring boot·后端·spring·mybatis·web
2401_857617621 小时前
SpringBoot校园资料平台:开发与部署指南
java·spring boot·后端
计算机学姐1 小时前
基于SpringBoot+Vue的在线投票系统
java·vue.js·spring boot·后端·学习·intellij-idea·mybatis
Yvemil72 小时前
MQ 架构设计原理与消息中间件详解(二)
开发语言·后端·ruby
2401_854391082 小时前
Spring Boot大学生就业招聘系统的开发与部署
java·spring boot·后端
虽千万人 吾往矣3 小时前
golang gorm
开发语言·数据库·后端·tcp/ip·golang
这孩子叫逆3 小时前
Spring Boot项目的创建与使用
java·spring boot·后端