前言

  • 很多时候,由于种种不可描述的原因,我们需要针对单个接口实现接口限流,防止访问次数过于频繁。这里就用 redis+aop 实现一个限流接口注解

@RedisLimit 代码

点击查看RedisLimit注解代码

import java.lang.annotation.*; /**
* 功能:分布式接口限流注解
* @author love ice
* @create 2023-09-18 15:43
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisLimit {
/**
* redis中唯一key,一般用方法名字做区分
* 作用: 针对不同接口,做不同的限流控制
*/
String key() default ""; /**
* 限流时间内允许访问次数 默认1
*/
long permitsPerSecond() default 1; /**
* 限流时间,单位秒 默认60秒
*/
long expire() default 60; /**
* 限流提示信息
*/
String msg() default "接口限流,请稍后重试";
}

AOP代码

点击查看aop代码

import com.aliyuncs.utils.StringUtils;
import com.test.redis.Infrastructure.annotation.RedisLimit;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; /**
* redis限流切面
*
* @author love ice
* @create 2023-09-18 15:44
*/
@Slf4j
@Aspect
@Component
public class RedisLimitAop {
@Autowired
private StringRedisTemplate stringRedisTemplate;
private DefaultRedisScript<Long> redisScript; @PostConstruct
public void init() {
redisScript = new DefaultRedisScript<>();
redisScript.setResultType(Long.class);
// 执行 lua 脚本
ResourceScriptSource resourceScriptSource = new ResourceScriptSource(new ClassPathResource("rateLimiter.lua"));
redisScript.setScriptSource(resourceScriptSource);
} @Pointcut("@annotation(com.test.redis.Infrastructure.annotation.RedisLimit)")
private void check() { } @Before("check()")
private void before(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod(); // 拿到 RedisLimit 注解,如果存在则说明需要限流
RedisLimit redisLimit = method.getAnnotation(RedisLimit.class); if (redisLimit != null) {
// 获取 redis 的 key
String key = redisLimit.key();
String className = method.getDeclaringClass().getName();
String name = method.getName();
String limitKey = key + className + name;
log.info("限流的key:{}", limitKey); if (StringUtils.isEmpty(key)) {
// 这里是自定义异常,为了方便写成了 RuntimeException
throw new RuntimeException("code:101,msg:接口中 key 参数不能为空");
} long limit = redisLimit.permitsPerSecond();
long expire = redisLimit.expire();
// 把 key 放入 List 中
List<String> keys = new ArrayList<>(Collections.singletonList(key));
Long count = stringRedisTemplate.execute(redisScript, keys, String.valueOf(limit), String.valueOf(expire));
log.info("Access try count is {} for key ={}", count, keys); if (count != null && count == 0) {
log.debug("令牌桶={}, 获取令牌失效,接口触发限流", key);
throw new RuntimeException("code:10X, redisLimit.msg()");
}
}
}
}

lua脚本代码

注意:脚本代码是放在 resources 文件下的,它的类型是 txt,名称后缀是lua。如果你不想改名称,就使用我写好的全名--> rateLimiter.lua

点击查看脚本代码
--获取KEY
local key = KEYS[1] local limit = tonumber(ARGV[1]) local curentLimit = tonumber(redis.call('get', key) or "0") if curentLimit + 1 > limit
then return 0
else
-- 自增长 1
redis.call('INCRBY', key, 1)
-- 设置过期时间
redis.call('EXPIRE', key, ARGV[2])
return curentLimit + 1
end

最后为了照顾纯小白,给大家看一下我的目录结构

使用 redis 实现分布式接口限流注解 RedisLimit的更多相关文章

  1. SpringBoot使用自定义注解+AOP+Redis实现接口限流

    为什么要限流 系统在设计的时候,我们会有一个系统的预估容量,长时间超过系统能承受的TPS/QPS阈值,系统有可能会被压垮,最终导致整个服务不可用.为了避免这种情况,我们就需要对接口请求进行限流. 所以 ...

  2. 服务限流 -- 自定义注解基于RateLimiter实现接口限流

    1. 令牌桶限流算法 令牌桶会以一个恒定的速率向固定容量大小桶中放入令牌,当有浏览来时取走一个或者多个令牌,当发生高并发情况下拿到令牌的执行业务逻辑,没有获取到令牌的就会丢弃获取服务降级处理,提示一个 ...

  3. 基于注解的接口限流+统一session认证

    代码心得: 一个基本的做法:对于用户身份认证做到拦截器里,针对HandlerMethod进行统一拦截认证,根据方法上的注解标识,判别是否需要身份验证,并将查找出来的User实体存入ThreadLoca ...

  4. 库存秒杀问题-redis解决方案- 接口限流

    <?php/** * Created by PhpStorm. * redis 销量超卖秒杀解决方案 * redis 文档:http://doc.redisfans.com/ * ab -n 1 ...

  5. Java分布式IP限流和防止恶意IP攻击方案

    前言 限流是分布式系统设计中经常提到的概念,在某些要求不严格的场景下,使用Guava RateLimiter就可以满足.但是Guava RateLimiter只能应用于单进程,多进程间协同控制便无能为 ...

  6. Guava-RateLimiter实现令牌桶控制接口限流方案

    一.前言 对于一个应用系统来说,我们有时会遇到极限并发的情况,即有一个TPS/QPS阀值,如果超了阀值可能会导致服务器崩溃宕机,因此我们最好进行过载保护,防止大量请求涌入击垮系统.对服务接口进行限流可 ...

  7. 【高并发】亿级流量场景下如何为HTTP接口限流?看完我懂了!!

    写在前面 在互联网应用中,高并发系统会面临一个重大的挑战,那就是大量流高并发访问,比如:天猫的双十一.京东618.秒杀.抢购促销等,这些都是典型的大流量高并发场景.关于秒杀,小伙伴们可以参见我的另一篇 ...

  8. SpringCloud(8)---zuul权限校验、接口限流

    zuul权限校验.接口限流 一.权限校验搭建 正常项目开发时,权限校验可以考虑JWT和springSecurity结合进行权限校验,这个后期会总结,这里做个基于ZuulFilter过滤器进行一个简单的 ...

  9. 【Dnc.Api.Throttle】适用于.Net Core WebApi接口限流框架

    Dnc.Api.Throttle    适用于Dot Net Core的WebApi接口限流框架 使用Dnc.Api.Throttle可以使您轻松实现WebApi接口的限流管理.Dnc.Api.Thr ...

  10. Spring Cloud Alibaba基础教程:使用Sentinel实现接口限流

    最近管点闲事浪费了不少时间,感谢网友libinwalan的留言提醒.及时纠正路线,继续跟大家一起学习Spring Cloud Alibaba. Nacos作为注册中心和配置中心的基础教程,到这里先告一 ...

随机推荐

  1. 快速上手 | Datavines 两表值比对规则用法

    Datavines 是一站式开源数据可观测性平台,提供元数据管理.数据概览报告.数据质量管理,数据分布查询.数据趋势洞察等核心能力,致力于帮助用户全面地了解和掌管数据,让您做到心中有数. 场景 比较某 ...

  2. 内核源码中单个.o文件的编译过程(六)

    通过对过渡篇的学习,相信你已经具有了相当的知识储备,接下来就来继续学习单个.o文件的编译过程 以/drivers/char/mem.c的编译为例 make /drivers/char/mem.o 一. ...

  3. MybatisPlus的各种查询方法

    MybatisPlus的各种查询方法 合并转载于https://my.oschina.net/u/241218/blog/1838534/和https://my.oschina.net/u/24275 ...

  4. 利用Abp过滤器实现业务数据“回收站”功能

    @ 目录 原理 创建过滤器 使用过滤器 查询 删除 恢复 原理 回收站是当用户删除一条记录时,不是直接从数据库中删除,而是将其放入"回收站",以便用户可以在需要时恢复数据. 在Ab ...

  5. 【题解】Educational Codeforces Round 150(CF1841)

    赛时过了 A-E,然后就开摆了,为什么感觉 C 那么无厘头[发怒][发怒] 排名:25th A.Game with Board 题目描述: Alice 和 Bob 玩游戏,他们有一块黑板.最初,有 \ ...

  6. CenOS 安装 mysql 临时密码 处理

    数据库 版本 Server version: 8.0.26 MySQL Community Server - GPL:官网下载的包 wget https://cdn.mysql.com//Downlo ...

  7. Pycharm:显示每一行代码的修改记录

    解决方案 安装插件GitToolBox

  8. JavaWeb和MVC三层架构

    JavaWeb 概述 网站发布和部署一定要依托技术语言吗: 不一定,一个网站可以直接发布和部署,因为因为浏览器能够识别网页只需要两样东西,网络和静态页面,还有一个装在他们的容器,比如 nginx. 静 ...

  9. 发布关于PostGIS对于USD格式的拓展

    我们非常高兴的发布为了一年一度的SIGGRAPH 2023发布关于为PostGIS支持USD格式的新拓展. 新添加了3个函数 ST_AsUSDA(geom geometry, usd_root_nam ...

  10. nginx配置gzip压缩

    前言 为提高用户获取响应数据的速度,Nginx服务器可以将响应数据进行gzip压缩,在减小响应数据的大小后再发送给用户端浏览器. 要想启用gzip压缩,需要浏览器支持gzip压缩功能,目前大多数浏览器 ...