返回顶部
首页 > 资讯 > 精选 >怎么使用AOP+redis+lua做限流
  • 284
分享到

怎么使用AOP+redis+lua做限流

2023-06-30 11:06:20 284人浏览 安东尼
摘要

这篇“怎么使用aop+redis+lua做限流”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么使用AOP+Redis+lu

这篇“怎么使用aop+redis+lua做限流”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么使用AOP+Redis+lua做限流”文章吧。

需求

公司里使用OneByOne的方式删除数据,为了防止一段时间内删除数据过多,让我这边做一个接口限流,超过一定阈值后报异常,终止删除操作。

实现方式

创建自定义注解 @limit 让使用者在需要的地方配置 count(一定时间内最多访问次数)period(给定的时间范围),也就是访问频率。然后通过LimitInterceptor拦截方法的请求, 通过 redis+lua 脚本的方式,控制访问频率。

源码

Limit 注解

用于配置方法的访问频率count、period

import javax.validation.constraints.Min;import java.lang.annotation.*;@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic @interface Limit {        String key() default "";        String prefix() default "";        @Min(1)    int count();        @Min(1)    int period();        LimitType limitType() default LimitType.CUSTOMER;}

LimiTKEy

用于标记参数,作为redis key值的一部分

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.PARAMETER)@Retention(RetentionPolicy.RUNTIME)public @interface LimitKey {}

LimitType

枚举,redis key值的类型,支持自定义key和ip、methodName中获取key

public enum LimitType {        CUSTOMER,        IP,        METHOD_NAME;}

RedisLimiterHelper

初始化一个限流用到的redisTemplate Bean

import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.serializer.GenericJackson2JSONRedisSerializer;import org.springframework.data.redis.serializer.StringRedisSerializer;import java.io.Serializable;@Configurationpublic class RedisLimiterHelper {    @Bean    public RedisTemplate<String, Serializable> limitRedisTemplate(@Qualifier("defaultStringRedisTemplate") StringRedisTemplate redisTemplate) {        RedisTemplate<String, Serializable> template = new RedisTemplate<String, Serializable>();        template.setKeySerializer(new StringRedisSerializer());        template.setValueSerializer(new GenericJackson2jsonRedisSerializer());        template.setConnectionFactory(redisTemplate.getConnectionFactory());        return template;    }}

LimitInterceptor

使用 aop 的方式来拦截请求,控制访问频率

import com.Google.common.collect.ImmutableList;import com.yxt.qida.api.bean.service.xxv2.openapi.anno.Limit;import com.yxt.qida.api.bean.service.xxv2.openapi.anno.LimitKey;import com.yxt.qida.api.bean.service.xxv2.openapi.anno.LimitType;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.ArrayUtils;import org.apache.commons.lang3.StringUtils;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.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.script.DefaultRedisScript;import org.springframework.data.redis.core.script.RedisScript;import org.springframework.WEB.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.Http.httpservletRequest;import java.io.Serializable;import java.lang.annotation.Annotation;import java.lang.reflect.Method;@Slf4j@Aspect@Configurationpublic class LimitInterceptor {    private static final String UNKNOWN = "unknown";    private final RedisTemplate<String, Serializable> limitRedisTemplate;    @Autowired    public LimitInterceptor(RedisTemplate<String, Serializable> limitRedisTemplate) {        this.limitRedisTemplate = limitRedisTemplate;    }    @Around("execution(public * *(..)) && @annotation(com.yxt.qida.api.bean.service.xxv2.openapi.anno.Limit)")    public Object interceptor(ProceedingJoinPoint pjp) {        MethodSignature signature = (MethodSignature) pjp.getSignature();        Method method = signature.getMethod();        Limit limitAnnotation = method.getAnnotation(Limit.class);        LimitType limitType = limitAnnotation.limitType();        int limitPeriod = limitAnnotation.period();        int limitCount = limitAnnotation.count();                String key;        switch (limitType) {            case IP:                key = getIpAddress();                break;            case CUSTOMER:                key = limitAnnotation.key();                break;            case METHOD_NAME:                String methodName = method.getName();                key = StringUtils.upperCase(methodName);                break;            default:                throw new RuntimeException("limitInterceptor - 无效的枚举值");        }                Object[] args = pjp.getArgs();        Annotation[][] paramAnnoAry = method.getParameterAnnotations();        for (Annotation[] item : paramAnnoAry) {            int paramIndex = ArrayUtils.indexOf(paramAnnoAry, item);            for (Annotation anno : item) {                if (anno instanceof LimitKey) {                    Object arg = args[paramIndex];                    if (arg instanceof String && StringUtils.isNotBlank((String) arg)) {                        key = (String) arg;                        break;                    }                }            }        }        if (StringUtils.isBlank(key)) {            throw new RuntimeException("limitInterceptor - key值不能为空");        }        String prefix = limitAnnotation.prefix();        String[] keyAry = StringUtils.isBlank(prefix) ? new String[]{"limit", key} : new String[]{"limit", prefix, key};        ImmutableList<String> keys = ImmutableList.of(StringUtils.join(keyAry, "-"));        try {            String luaScript = buildLuaScript();            RedisScript<Number> redisScript = new DefaultRedisScript<Number>(luaScript, Number.class);            Number count = limitRedisTemplate.execute(redisScript, keys, limitCount, limitPeriod);            if (count != null && count.intValue() <= limitCount) {                return pjp.proceed();            } else {                String classPath = method.getDeclarinGClass().getName() + "." + method.getName();                throw new RuntimeException("limitInterceptor - 限流被触发:"                        + "class:" + classPath                        + ", keys:" + keys                        + ", limitcount:" + limitCount                        + ", limitPeriod:" + limitPeriod + "s");            }        } catch (Throwable e) {            if (e instanceof RuntimeException) {                throw new RuntimeException(e.getLocalizedMessage());            }            throw new RuntimeException("limitInterceptor - 限流服务异常");        }    }        public String buildLuaScript() {        StringBuilder lua = new StringBuilder();        lua.append("local c");        lua.append("\nc = redis.call('get',KEYS[1])");        // 调用不超过最大值,则直接返回        lua.append("\nif c and tonumber(c) > tonumber(ARGV[1]) then");        lua.append("\nreturn c;");        lua.append("\nend");        // 执行计算器自加        lua.append("\nc = redis.call('incr',KEYS[1])");        lua.append("\nif tonumber(c) == 1 then");        // 从第一次调用开始限流,设置对应键值的过期        lua.append("\nredis.call('expire',KEYS[1],ARGV[2])");        lua.append("\nend");        lua.append("\nreturn c;");        return lua.toString();    }    public String getIpAddress() {        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();        String ip = request.getHeader("x-forwarded-for");        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {            ip = request.getHeader("Proxy-Client-IP");        }        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {            ip = request.getHeader("WL-Proxy-Client-IP");        }        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {            ip = request.getRemoteAddr();        }        return ip;    }}

TestService

使用方式示例

    @Limit(period = 10, count = 10)    public String delUserByUrlTest(@LimitKey String token, String thirdId, String url) throws IOException {        return "success";    }

以上就是关于“怎么使用AOP+redis+lua做限流”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网精选频道。

--结束END--

本文标题: 怎么使用AOP+redis+lua做限流

本文链接: https://lsjlt.com/news/328492.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 怎么使用AOP+redis+lua做限流
    这篇“怎么使用AOP+redis+lua做限流”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么使用AOP+redis+lu...
    99+
    2023-06-30
  • 使用AOP+redis+lua做方法限流的实现
    目录需求实现方式源码Limit 注解LimitKeyLimitTypeRedisLimiterHelperLimitInterceptorTestService需求 公司里使用One...
    99+
    2024-04-02
  • 怎么用Redis Lua脚本实现ip限流
    这篇文章主要讲解了“怎么用Redis Lua脚本实现ip限流”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么用Redis Lua脚本实现ip限流”吧!引言分布式限流最关...
    99+
    2023-07-02
  • 如何使用Redis和Lua开发限流器功能
    如何使用Redis和Lua开发限流器功能引言:随着互联网的发展,许多应用都面临着高并发的挑战。在面对大量请求时,必须采取措施来保护系统的稳定性和可用性,其中一个重要的手段就是限流。限流是指对请求的流量进行控制,确保系统在负载高峰时仍然能够正...
    99+
    2023-10-22
    redis lua 限流器
  • Redis+AOP怎么自定义注解实现限流
    今天小编给大家分享一下Redis+AOP怎么自定义注解实现限流的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。下载1,下载页面...
    99+
    2023-07-02
  • redis中怎么使用lua脚本
    这篇文章给大家分享的是有关redis中怎么使用lua脚本的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一:Lua脚本说来也巧,redis的大老板给了你解决这种问题的方法,那就是L...
    99+
    2024-04-02
  • Redis的Lua脚本怎么使用
    在 Redis 中使用 Lua 脚本可以通过 EVAL 命令来实现。 EVAL 命令的基本语法如下: EVAL script num...
    99+
    2024-05-07
    Redis Lua
  • SpringBoot怎么使用RateLimiter通过AOP方式进行限流
    这篇文章主要讲解了“SpringBoot怎么使用RateLimiter通过AOP方式进行限流”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot怎么使用RateLimiter通...
    99+
    2023-07-02
  • Redis限流怎么实现
    这篇文章给大家分享的是有关Redis限流怎么实现的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。面对越来越多的高并发场景,限流显示的尤为重要。当然,限流有许多种实现的方式,Redi...
    99+
    2024-04-02
  • Java生态/Redis中怎么使用Lua脚本
    本篇内容主要讲解“Java生态/Redis中怎么使用Lua脚本”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java生态/Redis中怎么使用Lua脚本”吧!一、安装LUAMac上安装LUA很简...
    99+
    2023-07-05
  • SpringBoot使用自定义注解+AOP+Redis实现接口限流的实例代码
    目录为什么要限流限流背景实现限流1、引入依赖2、自定义限流注解3、限流切面4、写一个简单的接口进行测试5、全局异常拦截6、接口测试为什么要限流 系统在设计的时候,我们会有一个系统的预...
    99+
    2024-04-02
  • 怎么使用Go+Redis实现常见限流算法
    本文小编为大家详细介绍“怎么使用Go+Redis实现常见限流算法”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么使用Go+Redis实现常见限流算法”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。固定窗口使用R...
    99+
    2023-07-05
  • 怎么使用lua进行nginx redis访问控制
    本篇内容介绍了“怎么使用lua进行nginx redis访问控制”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. 需求分析\1. Ngin...
    99+
    2023-06-27
  • SpringBoot如何使用RateLimiter通过AOP方式进行限流
    目录使用RateLimiter通过AOP方式进行限流1、引入依赖2、自定义注解3、AOP实现类4、使用SpringBoot之限流限流的基础算法Guava RateLimiter其他使...
    99+
    2024-04-02
  • SpingBoot中怎么利用Redis对接口限流
    这期内容当中小编将会给大家带来有关SpingBoot中怎么利用Redis对接口限流,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。实现的思路使用 Hash 存储接口的限流配置request_limit_co...
    99+
    2023-06-20
  • 使用Java实现Redis限流的方法
    1、概述   限流的含义是在单位时间内确保发往某个模块的请求数量小于某个数值,比如在实现秒杀功能时,需要确保在10秒内发往支付模块的请求数量小于500个。限流...
    99+
    2024-04-02
  • 怎么使用tomcat做redis集群
    要使用Tomcat做Redis集群,您需要执行以下步骤:1. 下载和安装Tomcat服务器:您可以从Tomcat官方网站下载并安装适...
    99+
    2023-09-04
    redis tomcat
  • Redis怎么实现限流和熔断
    Redis 可以通过以下方式实现限流和熔断: 限流:使用 Redis 的计数器功能来实现限流。在每次请求到来时,首先检查计数器的...
    99+
    2024-05-07
    Redis
  • 如何使用SpringBoot + Redis实现接口限流
    本篇内容介绍了“如何使用SpringBoot + Redis实现接口限流”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!配...
    99+
    2023-06-30
  • SpringBoot中怎么使用Redis做缓存
    在SpringBoot中使用Redis做缓存可以通过以下步骤实现: 添加依赖:首先在pom.xml文件中添加Spring Data...
    99+
    2024-04-09
    SpringBoot Redis
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作