当前位置: 首页 > news >正文

分布式接口限流与防重复提交实现方案

一、背景

在分布式系统架构下,接口的稳定性与安全性是系统设计的核心挑战之一。随着业务规模的扩大和高并发场景的增多,接口面临的​​流量洪峰​​、​​恶意刷单​​、​​重复提交​​等问题日益突出:

  • ​流量过载风险​​:突发流量(如活动促销、热点事件)可能导致核心接口超出系统承载能力,引发服务雪崩;
  • ​恶意请求攻击​​:未授权用户通过脚本高频调用接口,消耗服务器资源(如CPU、数据库连接),影响正常业务;
  • ​重复提交隐患​​:用户因网络延迟重复点击按钮,或前端未做防重校验时,可能导致业务逻辑重复执行(如重复下单、重复扣款)。

传统单机限流方案(如Guava RateLimiter)仅能控制单个应用实例的流量,无法满足分布式系统多实例间的协同限流需求。而基于Redis的分布式限流方案,凭借其​​全局状态共享​​、​​高并发支持​​和​​原子性操作​​的特性,成为解决分布式限流问题的首选。

Redisson作为Redis的Java客户端增强工具,内置了RRateLimiter(分布式限流器)组件,支持基于时间窗口的令牌桶算法,能够轻松实现跨实例的分布式限流。本文将结合Spring Boot框架,通过自定义注解与AOP切面,演示如何基于Redisson快速实现一套​​低侵入、可配置、分布式​​的接口限流与防重复提交方案。

二、依赖引入

在Spring Boot项目中,通过redisson-spring-boot-starter快速集成Redisson,只需添加以下Maven依赖(版本号根据实际情况调整):

<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>${redisson.version}</version>
</dependency>

三、限流注解定义

为了实现无侵入式的限流控制,我们定义一个自定义注解@RateLimit,用于标记需要限流的方法。该注解支持配置​​时间窗口​​(单位:秒)和​​限流键前缀​​,灵活适配不同业务场景的限流需求。

import java.lang.annotation.*;/*** 分布式限流注解(基于 Redisson 实现)* 用于标记需要限制调用频率的方法,防止接口被高频调用或重复提交*/
@Target(ElementType.METHOD)       // 作用于方法级别
@Retention(RetentionPolicy.RUNTIME)  // 运行时保留,可通过反射获取
@Documented                     // 文档可见
@Inherited                      // 支持子类继承
public @interface RateLimit {/*** 限流时间窗口(单位:秒)* 表示在多长时间内允许的最大请求次数(默认60秒)*/int seconds() default 60;/*** 限流键前缀* 用于生成Redis中限流规则的唯一键,建议根据业务场景命名(如"order:submit")*/String key_pre();
}

四、分布式限流切面实现

通过Spring AOP的环绕通知(@Around),拦截所有标记了@RateLimit的方法,在方法执行前进行限流校验。核心逻辑包括:

  1. ​生成唯一限流键​​:结合限流键前缀与请求参数的SHA256摘要,确保不同参数的请求独立计数;
  2. ​初始化限流器​​:通过Redisson的RRateLimiter创建分布式限流器,设置时间窗口内的最大请求次数;
  3. ​执行限流校验​​:若当前请求超出限流阈值,则拦截请求并返回提示;否则放行请求,执行原方法。
  4. 更换限流规则:标记为3处的代码可与标记为4处的代码置换位置,实现两种限流逻辑
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import zyy.oa.framework.common.annotations.RateLimit;
import zyy.oa.framework.common.utils.Result;
import cn.hutool.core.lang.Assert;import java.lang.reflect.Method;
import java.time.Duration;@Aspect
@Component
@AllArgsConstructor
public class CommonAspect {private final RedissonClient redissonClient;  // Redisson客户端注入/*** 环绕通知:拦截所有标记了@RateLimit的方法,执行限流校验* @param pjp 切入点对象* @param rateLimit 限流注解参数* @return 原方法执行结果或限流提示* @throws Throwable 异常*/@Around("@annotation(rateLimit)")public Object around(ProceedingJoinPoint pjp, RateLimit rateLimit) throws Throwable {// 1. 解析方法参数,生成唯一限流键Method method = ((MethodSignature) pjp.getSignature()).getMethod();Object[] args = pjp.getArgs();  // 获取方法入参String paramsJson = JSONObject.toJSONString(args);  // 参数转JSON字符串String requestKey = DigestUtil.sha256Hex(paramsJson);  // 参数SHA256摘要(防重复关键)String limitKey = "rate_limit:" + rateLimit.key_pre() + ":" + requestKey;  // 完整限流键// 2. 初始化Redisson限流器(仅首次请求时设置)RRateLimiter rateLimiter = redissonClient.getRateLimiter(limitKey);boolean isFirstRequest = rateLimiter.trySetRate(RateType.OVERALL,  // 限流类型:全局(所有节点共享)1,                 // 时间窗口内最大请求数(此处设为1次/窗口)Duration.ofSeconds(rateLimit.seconds())  // 时间窗口长度);// 3.确保键过期时间与窗口一致rateLimiter.expire(Duration.ofSeconds(rateLimit.seconds()));  // 4. 执行限流校验:尝试获取令牌(无令牌则拦截),非首次请求触发限流(首次请求可能因初始化延迟未生效,不拦截)// 可根据需要与3处代码位置置换实现不计入限流请求Assert.isTrue(rateLimiter.tryAcquire()&&firstTime, "限定时间内重复请求,已忽略");// 5. 限流通过,执行原方法return pjp.proceed();}
}

五、使用示例

在需要限流的业务方法上添加@RateLimit注解,即可快速启用分布式限流功能。以下是一个典型的接口限流场景:

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import zyy.oa.framework.common.utils.Result;
import java.util.Map;@RestController
public class FlowController {private final FlowDefinitionService flowDefinitionService;// 示例:限制"自动发起流程"接口的调用频率@Operation(summary = "自动发起流程")@PostMapping("/autoStartFlow")@RateLimit(key_pre = "flow:autoStart",  // 限流键前缀(业务相关,可以根据接口自定义)seconds = 60                  // 时间窗口60秒(1分钟内仅允许1次请求))public Result autoStartFlow(@Parameter(description = "流程分类") @RequestParam String category,@Parameter(description = "流程名称") @RequestParam(required = false) String name,@Parameter(description = "变量集合") @RequestBody Map<String, Object> variables) {return flowDefinitionService.autoStartFlow(category, name, variables);}
}

六、方案特性与应用场景

方案特性

特性说明
​分布式支持​基于Redis存储限流状态,天然支持多实例集群环境,各节点限流规则同步
​低侵入性​通过注解+AOP实现,业务代码无需修改,仅需标记需要限流的方法
​参数敏感性​结合请求参数生成SHA256摘要,不同参数的请求视为独立操作,避免误限
​灵活配置​支持自定义时间窗口(seconds)和键前缀(key_pre),适配不同业务场景
​高并发友好​Redisson的RRateLimiter基于Lua脚本实现原子操作,保证高并发下的准确性

应用场景

  • ​核心接口防刷​​:如支付接口、短信发送接口,限制单位时间内的调用次数;
  • ​防重复提交​​:表单提交、订单确认等操作,防止用户重复点击导致业务重复执行;
  • ​资源消耗保护​​:批量任务接口、数据导出接口,限制高频调用对服务器资源的消耗;
  • ​业务风控​​:配合用户行为分析,对异常高频请求(如短时间内大量不同参数调用)进行拦截。

总结

本文基于Redisson实现了分布式接口限流与防重复提交方案,通过自定义注解和AOP切面,以低侵入的方式解决了分布式系统中的流量控制问题。该方案兼顾了灵活性、准确性和可维护性,适用于大多数需要限制接口调用频率的业务场景。实际使用中,可根据业务需求调整限流时间窗口、最大请求数等参数,或扩展注解功能(如支持动态限流策略),进一步适配复杂业务场景。

http://www.dtcms.com/a/318849.html

相关文章:

  • 快速搭建vue3+flask实现一个异物检测项目
  • RP2040下的I2S Slave Out,PIO状态机(四)
  • MT信号四通道相关性预测的Informer模型优化研究
  • 此芯p1开发板使用OpenHarmony时llama.cpp不同优化速度对比(GPU vs CPU)
  • 掌握工程化固件烧录,开启你的技术进阶之路-FPGA ISE(xilinx)
  • 微软推出“愤怒计划“:利用AI工具实现恶意软件自主分类
  • Daemon Tools for Mac —— 专业虚拟光驱与磁盘映像工具
  • 手机控制断路器:智能家居安全用电的新篇章
  • Casrel关系抽取
  • 如何快速开发符合Matter标准的智能家居设备?
  • 在 openEuler 24.03 (LTS) 上安装 FFmpeg 的完整指南
  • 接入小甲鱼数字人API教程【详解】
  • 物联网架构全解析:华为“1+2+1”与格行随身WiFi,技术如何定义未来生活?
  • 优选算法 力扣 LCR 179. 查找总价格为目标值的两个商品 双指针降低时间复杂度 C++题解 每日一题
  • 界面组件DevExpress WPF中文教程:网格视图数据布局 - 紧凑模式
  • 代企业开发钉钉数据对接
  • hadoop HDFS 重置详细步骤
  • [bug]AttributeError: module ‘typing_extensions‘ has no attribute ‘TypeVar‘
  • 人工智能的20大应用
  • 图论(1):图数据结构
  • 第二十七天(数据结构:图)
  • uni-app vue3 小程序接入 aliyun-rtc-wx-sdk
  • Android 之 Jetpack- Room
  • 力扣238:除自身之外数组的乘积
  • 快速开发实践
  • 使用Spring Boot + Angular构建安全的登录注册系统
  • 十八、MySQL-DML-数据操作-插入(增加)、更新(修改)、删除
  • LongVie突破超长视频生成极限:1分钟电影级丝滑视频,双模态控制告别卡顿退化
  • 本地组策略编辑器无法打开(gpedit.msc命令异常)
  • 编程之线性代数矩阵和概率论统计知识回顾