【组件】接口限流与接口计次组件

该项目提供了一种基于Java实现的服务限流方案,包括固定窗口限流算法,并支持注解和动态管理限流。限流策略包括全局限流、IP限流,计数器策略可选择本地缓存或Redis。此外,还提供了回调接口用于处理限流信息,以及动态添加、删除限流规则的API。示例代码展示了如何在接口上使用注解进行限流以及动态管理限流的实现。

服务限流

项目:https://github.com/xuzhou-99/currentLimiting

前言

本模块主要实现对服务请求的限流,通过策略模式加载不同配置类型的限流实现,目前的限流算法是固定窗口限流算法(计数器),
一定时间内达到限流上限则限制访问。

主要的限流算法

参考文档:

4种经典限流算法讲解 https://zhuanlan.zhihu.com/p/376564740

架构之高并发:限流 https://www.pdai.tech/md/arch/arch-y-ratelimit.html

  • 固定窗口限流算法
  • 滑动窗口限流算法
  • 漏桶算法
  • 令牌桶算法

主要模块

  • 限流实现:
    • 注解限流:@CurrentLimiting,通过注解添加限流场景、策略、限流上限等参数
    • 动态限流:LimitFilter,通过其中的静态方法,动态添加、删除、查看、初始化限流请求
  • 限流场景SceneStrategy:全局限流、IP限流
  • 限流计数器CountStrategy:本地缓存、Redis(单机)
  • 限流策略LimitingStrategy:秒、分、时、天、周、月、年
引用组件
  • 目前是发布在github个人仓库,引用时需要添加 github 仓库
<repositories>
    <!-- github -->
    <repository>
        <id>github</id>
        <!-- https://raw.github.com/用户名/仓库名/分支名 -->
        <url>https://raw.github.com/xuzhou-99/mvn-repo/main</url>
        <snapshots>
            <enabled>true</enabled>
            <updatePolicy>always</updatePolicy>
        </snapshots>
    </repository>
</repositories>

<dependencies>
    
    <!--altaria 限流组件-->
    <dependency>
        <groupId>cn.altaria</groupId>
        <artifactId>currentLimiting</artifactId>
        <version>0.0.2-SNAPSHOT</version>
    </dependency>
</dependencies>
配置参数
# ------------------------ 限流配置 ---------------------------- #
security:
  limit:
    # 限流是否开启
    enable: true
    # 限流计数器策略,支持cache(本地),redis
    count-strategy: redis

spring:
  # --------------  redis配置,如果想使用redis模式,则配置------------#
  redis:
    host: 127.0.0.1
    port: 6379
回调接口实现

提供回调接口 ILimitingInfoHandle ,实现其中的 callback() 方法,可以获取每次限流/计次信息,自由拓展功能,例如记录数据库日志。

  • isSupport:默认需要2个实现类,分别支持
    • “limit”.equals(type):该实现类支持所有的限流回调
    • “times”.equals(type):该实现类仅支持计次回调
  • doBefore:限流或计次前调用方法
    • 计次需要特殊处理,实现该方法,获取appId、secretKey,进行判断是否有效,并处理计次有效时长、总次数
  • callback:回调方法,可以实现进行数据库处理等操作
/**
 * @author xuzhou
 * @since 2022/11/14
 */
public interface ILimitingInfoHandle {

    /**
     * 支持限流模式
     *
     * @param type 限流模式:limit限流,times计次
     * @return 支持
     */
    boolean isSupport(String type);

    /**
     * 校验 请求中 AppId和 SecretKey 是否有效
     *
     * @param limitInfo 限流参数信息
     * @return 有效
     */
    default boolean doBefore(LimitingPointInfo limitInfo) {
        return true;
    }


    /**
     * 回调处理
     *
     * @param limitInfo 限流信息
     */
    default void callback(LimitingPointInfo limitInfo) {
        // 计次通过后,剩余次数-1
    }

}

使用示例

接口限流
注解限流

通过添加注解@CurrentLimiting来标记该请求路由需要进行限流,切面CurrentLimitingAspect拦截
统一处理,解析请求路径、请求IP,调用限流过滤器CurrentLimitingProcessor根据配置中的count-strategy来策略
加载限流计数器,可以选择本地缓存cache,或者redis来进行限流处理。

  • strategy:限流策略
  • strategyTime:限流策略组合时长,配合 currentLimiting.strategy().getExTime() 生成过期时间,单位秒
  • scene:限流场景
  • limit:限流上限

例如,采用了redis限流计数器策略,则在redis中存放以下记录,每次通过的请求会使得value原子增1,
当达到limit上限的时候,则抛出CurrentLimitingException限流上限异常,组织请求的继续。

  • key(拼接的限流key): limit:ip:/api/limit1:172.31.2.214:60:2
  • value(已请求次数计数): 1
// 使用示例
@Slf4j
@Controller
@RequestMapping("/api")
public class TestController {

    @GetMapping("/limit")
    @ResponseBody
    @CurrentLimiting(strategy = LimitingStrategy.MONTH_STRATEGY, strategyTime = 1L, scene = SceneStrategy.ALL, limit = 10L)
    public String limit() {
        System.out.println("测试限流...");
        return null;
    }
}
动态限流

对于请求的限流可能并不是实时都要的,可能某一段时间是需要进行限流,所以添加了动态限流的组件,实现核心是CurrentLimitingFilter,
这是一个全局过滤器,可以通过调用其中的静态方法来实现动态管理限流

  • filterCache:动态限流集合,存放所有需要进行限流的请求标识
  • doFilter:Filter实现方法,对所有记录在filterCache中的请求进行限流管理
  • method:静态管理方法
    • initFilterCache():初始化动态限流集合
    • getFilterCache():获取动态限流集合
    • addLimit(***):新增限流
    • removeFilterKey(String key):移除限流
    • removeFilterKey(SceneStrategy scene, String requestTag):移除限流
@Slf4j
@Controller
@RequestMapping("/api")
public class TestController {

    @GetMapping("/limit1")
    @ResponseBody
    public String limit1() {
        log.info("测试 Filter 限流...");
        return null;
    }

    @GetMapping("/add")
    @ResponseBody
    public String add(HttpServletRequest request) {
        log.info("添加 Filter 限流...");
        String limitKey = CurrentLimitingFilter.addLimit(LimitingStrategy.MINUTE_STRATEGY, SceneStrategy.IP, 1L,
                2, "/api/limit1");
        return "添加" + limitKey + "限流!";
    }

    @GetMapping("/remove")
    @ResponseBody
    public String remove(HttpServletRequest request) {

        log.info("移除 Filter 限流...");
        String limitKey = CurrentLimitingFilter.removeFilterKey(SceneStrategy.IP, "/api/limit1");
        return "移除" + limitKey + "限流!";
    }
}
接口计次
接口计次

通过添加注解@CurrentLimiting来标记该请求路由需要进行计次,切面CurrentLimitingAspect拦截
统一处理,解析请求路径、请求IP,调用限流过滤器TimesLimitingProcessor根据配置中的count-strategy来策略
加载限流计数器,可以选择本地缓存cache,或者redis来进行限流处理。

  • scene:限流场景-APP
  • strategy、strategyTime、limit:可以通过 回调接口实现:doBefore/callback 来从数据库获取并修改,从而实现高度动态自定义

计次请求:

​ 支持AppId、ip组合计次

  • appId:应用id,放置于请求头
  • secretKey:应用密钥,放置于请求头
// 使用示例
@Slf4j
@Controller
@RequestMapping("/api")
public class TestController {

    @GetMapping("/times")
    @ResponseBody
    @CurrentLimiting(strategy = LimitingStrategy.MONTH_STRATEGY, strategyTime = 1L, scene = SceneStrategy.APP, limit = 10L)
    public String times() {
        System.out.println("测试计次...");
        return null;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值