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

流量守门员:接口限流艺术

在用户使用服务的过程中,可能会出现一些缺乏实质意义或违反服务条款的行为,包括但不限于以下几种情况:

  1. 以异常高的频率发送短信;
  2. 不断地更改个人资料信息;
  3. 过度频繁地进行点赞操作;
  4. 频繁提交评论内容。

针对上述行为实施流量控制措施是必要的,其主要目的如下:

  1. 防止恶意攻击:通过限制访问频率有效抵御机器人或自动化脚本对验证码等敏感接口的高频次调用尝试。
  2. 确保服务稳定性与可用性:避免由于短时间内涌入大量请求而造成的服务过载甚至崩溃,从而保障平台能够持续稳定地为用户提供服务。
  3. 维护良好用户体验:合理设置限流规则,在不影响正常用户正常使用体验的前提下,对异常行为加以限制。这样既保护了广大用户的权益,也维护了一个健康、积极的网络环境。

常见的方案

算法特点适用场景
固定窗口简单易实现,但存在窗口切换时的流量突增问题。低并发场景
滑动窗口更平滑的流量控制,但实现复杂度较高。高精度限流需求
令牌桶允许突发流量,通过令牌生成速率控制平均流量。需要容忍突发的场景
漏桶严格限制流量速率,输出流量恒定。需要稳定输出的场景

限流的维度:

  1. 按 IP 限流:防止单一 IP 高频攻击。
  2. 按用户 ID 限流:针对登录用户,防止账号被恶意攻击。
  3. 按手机号/邮箱限流:防止短信/邮件验证码被滥发。
  4. 组合维度:例如 IP + 用户ID,提高安全性。

时间滑动窗口

这里我们本系统设计了一个“时间滑动窗口”限流算法,它将时间划分为若干个固定大小的窗口,每个窗口内记录了该时间段内的请求次数。通过动态地滑动窗口,可以动态调整限流的速率,以应对不同的流量变化。

整个限流可以概括为两个主要步骤:

  1. 统计窗口内的请求数量
  2. 应用限流规则

限流的组合维度:IP+邮箱,利用 Redis 的有序集合 zset 实现思路如下:

  1. 允许用于 3 分钟内,只能发送 3 个验证码,或者 10 分钟内只能发送 8 个验证码
  2. 于是将用户发送邮箱验证码行为设计为 key= 场景 : 行为 : md5(ip+邮箱)
  3. score = 时间戳
  4. value = 时间戳


描述文字

实现思路

假设,现在接口只允许同一个用户 3 分钟内只能发送 3 次邮箱验证码。

  1. 记录窗口的请求数量

  1. 此时,计算“当前时间”- “3 分钟”内请求的次数 = 2 次 < 3 次,所以可以发送新请求。

  1. 如果,此时在 “3 分钟”时,又新增了请求,由于 3 分钟内请求次数已经超过了 3 次,拒绝请求。

  1. 此时,等待了 1 分钟后,再次发送请求
    1. 首先,剔除窗口外的请求(00 分钟)
    2. 计算,“当前时间”- “3 分钟”内请求的次数 = 2 次,新增请求。

后续的业务,就时不同场景中,根据不同的需求,进行修改校验就行了,比如 5 分钟限流 3 次,10 分钟限流 8 次等。

代码实现

代码实现方面的思路:

  1. 基于 Redis 的有序集合 Zset 实现滑动窗口限流(List 集合可以实现滑动窗口)。
  2. 目标对象时接口,此时我们就可以使用 AOP 拦截请求,达到限流的目的。
描述文字
统计窗口内容请求次数
private boolean isAllow(String key, LimitFlowAnno limitFlowAnno) {String luaScript = """local key = KEYS[1]local current_time = tonumber(ARGV[1])local window_size = tonumber(ARGV[2])local threshold = tonumber(ARGV[3])-- Remove outdated entriesredis.call('ZREMRANGEBYSCORE', key, 0, current_time - window_size)-- Check current countlocal count = redis.call('ZCARD', key)if count >= threshold thenreturn "0"  -- rejectend-- Allow and record this requestredis.call('ZADD', key, current_time, current_time)redis.call('PEXPIRE', key, window_size)  -- auto-expire the keyreturn "1"  -- allow""";long windowSizeMillis = limitFlowAnno.windowSize() * UNIT;long requestLimit = limitFlowAnno.requestLimit();long currentTimestamp = System.currentTimeMillis();String result = stringRedisTemplate.execute(new DefaultRedisScript<>(luaScript, String.class),Collections.singletonList(key),String.valueOf(currentTimestamp),String.valueOf(windowSizeMillis),String.valueOf(requestLimit));return "1".equals(result);
}
AOP 限流拦截
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface LimitFlowAnno {String behavior() default "";/*** Time scope, the unit is minute.*/long windowSize() default 1;/*** Limitation times.*/long requestLimit() default 3;
}
@Component
@Aspect
@Slf4j
@Order(2)
public class LimitFlowAop {private final long UNIT = 60 * 1000;@Resourceprivate StringRedisTemplate stringRedisTemplate;@Before("@annotation(limitFlowAnno)")private void handleBefore(JoinPoint joinPoint, LimitFlowAnno limitFlowAnno) {String argJsonStr = JSON.toJSONString(joinPoint.getArgs()[0]);HashMap<String, String> requestMap = JsonUtil.jsonStrToObj(argJsonStr, HashMap.class);String email = requestMap.get("to");String behavior = limitFlowAnno.behavior();String key = String.format(RedisKey.LIMIT_FLOW_KEY, behavior, email);if (isAllow(key, limitFlowAnno)) {log.info("请求通过");} else {throw new BizException(BizCode.CONTROL_FLOW);}}
}

最后,看Redis中的数据结构


Reference

  1. 基于Redis有序集合实现滑动窗口限流

相关文章:

  • 软件设计师-软考知识复习(2)
  • vue3+flex动态的绘制蛇形时间轴
  • Python小程序:上班该做点摸鱼的事情
  • vue3+Nest.js项目 部署阿里云
  • 字节跳动社招面经 —— BSP驱动工程师(4)
  • vue.js中的一些事件修饰符【前端】
  • uni-app 中封装全局音频播放器
  • 深入蜂窝物联网 第四章 Cat-1 与 5G RedCap:带宽、低时延与未来趋势
  • 五、UI自动化测试05--PyTest框架
  • 【SpringBoot】基于MybatisPlus的博客管理系统(1)
  • 【Unity】使用Socket建立客户端和服务端并进行通信的例子
  • 东土科技NewPre系列智能控制器的创新之旅
  • VMware安装 银河麒麟操作系统桌面版 V10 SP1 2403
  • HotSpot的算法细节
  • 集群系统的五大核心挑战与困境解析
  • 4月28号
  • 漏洞复现清单整理-预备梳理,等待补充
  • 多维驱动:负载均衡何以成为现代系统架构的基石
  • 网络爬取需谨慎:警惕迷宫陷阱
  • Ansible安装配置
  • 工业富联一季度净利增长25%,云计算业务营收增长超50%
  • 人社部:一季度全国城镇新增就业308万人,同比增加5万人
  • 事关稳就业稳经济,10张海报看懂这场发布会的政策信号
  • 校长套取学生伙食费设小金库,重庆通报6起违反八项规定典型问题
  • 独家丨申万宏源研究所将迎来新所长:首席策略分析师王胜升任
  • 我国对国家发展规划专门立法