redis+lua实现限流

1、需要引入Redis的maven坐标

<!--redis和 springboot集成的包 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>2.3.0.RELEASE</version>
</dependency>

2、redis配置

spring:# Redis数据库索引redis:database: 0# Redis服务器地址host: 127.0.0.1# Redis服务器连接端口port: 6379# Redis服务器连接密码(默认为空)password:# 连接池最大连接数(使用负值表示没有限制)jedis:pool:max-active: 8# 连接池最大阻塞等待时间(使用负值表示没有限制)max-wait: -1# 连接池中的最大空闲连接max-idle: 8# 连接池中的最小空闲连接min-idle: 0# 连接超时时间(毫秒)timeout: 10000

3、新建脚本放在该项目的 resources 目录下,新建 limit.lua

local key = KEYS[1] --限流KEY 
local limit = tonumber(ARGV[1]) --限流大小 
local current = tonumber(redis.call('get', key) or "0") if current + 1 > limit then 
return 0 else redis.call("INCRBY", key,"1") redis.call("expire", key,"2") return current + 1 end

4、自定义限流注解

import java.lang.annotation.*;@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RedisRateLimiter {//往令牌桶放入令牌的速率double value() default  Double.MAX_VALUE;//获取令牌的超时时间double limit() default  Double.MAX_VALUE;
}

5、自定义切面类 RedisLimiterAspect 类 ,修改扫描自己controller类

import com.imooc.annotation.RedisRateLimiter;
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.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.assertj.core.util.Lists;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.List;@Aspect
@Component
public class RedisLimiterAspect {@Autowiredprivate HttpServletResponse response;/*** 注入redis操作类*/@Autowiredprivate StringRedisTemplate stringRedisTemplate;private DefaultRedisScript<List> redisScript;/*** 初始化 redisScript 类* 返回值为 List*/@PostConstructpublic void init(){redisScript = new DefaultRedisScript<List>();redisScript.setResultType(List.class);redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("limit.lua")));}public final static Logger log = LoggerFactory.getLogger(RedisLimiterAspect.class);@Pointcut("execution( public * com.zz.controller.*.*(..))")public void pointcut(){}@Around("pointcut()")public Object process(ProceedingJoinPoint proceedingJoinPoint) throws  Throwable {MethodSignature  signature = (MethodSignature)proceedingJoinPoint.getSignature();//使用Java 反射技术获取方法上是否有@RedisRateLimiter 注解类RedisRateLimiter redisRateLimiter = signature.getMethod().getDeclaredAnnotation(RedisRateLimiter.class);if(redisRateLimiter == null){//正常执行方法,执行正常业务逻辑return proceedingJoinPoint.proceed();}//获取注解上的参数,获取配置的速率double value = redisRateLimiter.value();double time = redisRateLimiter.limit();//list设置lua的keys[1]//取当前时间戳到单位秒String key = "ip:"+ System.currentTimeMillis() / 1000;List<String> keyList = Lists.newArrayList(key);//用户Mpa设置Lua 的ARGV[1]//List<String> argList = Lists.newArrayList(String.valueOf(value));//调用脚本并执行List result = stringRedisTemplate.execute(redisScript, keyList, String.valueOf(value),String.valueOf(time));log.info("限流时间段内访问第:{} 次", result.toString());//lua 脚本返回 "0" 表示超出流量大小,返回1表示没有超出流量大小if(StringUtils.equals(result.get(0).toString(),"0")){//服务降级fullback();return null;}// 没有限流,直接放行return proceedingJoinPoint.proceed();}/*** 服务降级方法*/private  void  fullback(){response.setCharacterEncoding("UTF-8");response.setContentType("application/json; charset=utf-8");PrintWriter writer = null;try {writer= response.getWriter();JSONObject o = new JSONObject();o.put("status",500);o.put("msg","Redis限流:请求太频繁,请稍后重试!");o.put("data",null);writer.printf(o.toString());}catch (Exception e){e.printStackTrace();}finally {if(writer != null){writer.close();}}}
}

6、在需要限流的类添加注解

import com.imooc.annotation.RedisRateLimiter;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.TimeUnit;@RestController
@Api(value = "限流", tags = {"限流测试接口"})
@RequestMapping("limiter")
public class LimiterController {@ApiOperation(value = "Redis限流注解测试接口",notes = "Redis限流注解测试接口", httpMethod = "GET")@RedisRateLimiter(value = 10, limit = 1)@GetMapping("/redislimit")public IMOOCJSONResult redislimit(){System.out.println("Redis限流注解测试接口");return IMOOCJSONResult.ok();}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/127864.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

能源化工过程-故障诊断数据集初探-田纳西-伊斯曼过程数据集

1. 田纳西-伊斯曼过程(TE)数据集简介 整个TE数据集由训练集和测试集构成,TE集中的数据由22次不同的仿真运行数据构成,TE集中每个样本都有52个观测变量。d00.dat至d21.dat为训练集样本,d00_te.dat至d21_te.dat为测试集样本。d00.dat和d00_te.dat为正常工况下的样本。d00.d…

如何开始开发一个跑腿App系统?

1. 确定需求和功能规划 开始开发之前&#xff0c;需明确系统所需的基本功能&#xff0c;包括用户注册、登录、下单、配送员匹配、订单跟踪等。这些功能需要在系统设计之初明确。 2. 技术选型 选择适合的技术栈。前端可以使用框架如React、Vue.js&#xff0c;后端可选择Node…

Vue Camera组件的使用方法

Vue Camera组件是一个用于在Web应用中使用摄像头的Vue插件。它提供了一些常见的功能和方法来控制摄像头和捕获图像或视频数据。以下是一些Vue Camera组件的常见功能和使用方法&#xff1a; 1.显示摄像头画面&#xff1a;Vue Camera组件可以直接显示摄像头的实时画面。你只需要…

创新工具箱!重塑手机页面原型设计体验

在2024年&#xff0c;随着移动设备的普及和用户对移动体验的要求不断提升&#xff0c;手机页面原型设计工具变得越来越重要。在这篇文章中&#xff0c;我将为您推荐几款在2024年非常流行且值得一试的手机页面原型设计工具。 Pixso Pixso是一款基于云端的协作设计工具&#xf…

【已解决】PPT不能转换成PDF文档怎么办?

PPT可以转换成PDF文档&#xff0c;只需要点击PPT菜单页面中的【文件】选项&#xff0c;再点击【导出】即可转换&#xff0c;如果转换时发现【导出】选项不可选&#xff0c;无法完成转换怎么办&#xff1f;以下3种方法可以试试&#xff01; 出现上面这种情况&#xff0c;我们可以…

智慧水务监控系统解决方案

智慧水务监控系统解决方案 目前&#xff0c;水质监测在各行各业中起着至关重要的作用。随着人们对环境保护和健康意识的提升&#xff0c;对水质监测的需求也日益增长。然而&#xff0c;现有的水质监测方法与需求之间存在一定的差距&#xff0c;需要通过智慧水务监控系统来解决…

模糊C均值聚类(FCM)python

目录 一、模糊C均值聚类的原理 二、不使用skfuzzy的python代码 三、 使用skfuzzy的python代码 一、模糊C均值聚类的原理 二、不使用skfuzzy的python代码 import numpy as np import random import matplotlib.pyplot as plt plt.rcParams[font.sans-serif][SimHei] plt.r…

1111 Online Map(30分)

题目翻译&#xff1a; 就是求解一个点到另一个点的最短路径。 不过由于限制条件很多&#xff0c;还得分开求两次&#xff0c;所以写起来就很繁。 题解思路&#xff1a; 可以用dijkstra或者dfs&#xff0c;用后者的话最后一个测试点可能会超时。 代码&#xff1a; dfs&…

Vins-Fusion、Vins-Mono(之前那个编译通过但是没有这个好用)

ROS的catkin_make不要修改,暂时没有理由&#xff0c;理由就是两次一个改了一个没改&#xff0c;没改的成功了以成功为准。 另外docker也没用成功&#xff0c;原本的逻辑来说&#xff0c;docker肯定不能出问题的&#xff0c;但是由于roscore通信的原因可能没有将结果显示&#x…

二叉树问题——前/中/后/层遍历问题(递归与栈)

摘要 博文主要介绍二叉树的前/中/后/层遍历(递归与栈)方法 一、前/中/后/层遍历问题 144. 二叉树的前序遍历 145. 二叉树的后序遍历 94. 二叉树的中序遍历 102. 二叉树的层序遍历 103. 二叉树的锯齿形层序遍历 二、二叉树遍历递归解析 // 前序遍历递归LC144_二叉树的前…

Spring Cloud Gateway 重写 URL

目录 1、简介 2、Spring Cloud Gateway 快速回顾 3、基于配置的 URL 重写 4、基于 DSL 的 URL 重写 5、测试 6、总结 1、简介 Spring Cloud Gateway 的常见用例是作为一个网关&#xff0c;代理一个或多个服务&#xff0c;从而为客户端提供更简单的消费方式。 本文将带你…

数学+分类讨论+构造:1102T3

http://cplusoj.com/d/senior/p/SS231102C 首先可以通过枚举逆序对点的贡献推出无解情况为 n m o d 4 > 1 n \bmod 4 > 1 nmod4>1 然后构造可以按 n m o d 3 n\bmod 3 nmod3 进行分类 #include<bits/stdc.h> using namespace std; #ifdef LOCAL#define deb…

Linux的test测试功能

测试文件名的类型&#xff0c;文件是否存在&#xff0c; 文件的权限检测 文件之间的比较 两个整数之间的比较 判断字符串数据 多重条件判定 一个一个来&#xff0c;这个有点多&#xff0c;不过比较有意思&#xff0c;来代码 案例1&#xff0c;判断文件是否存在&#xff…

超声波俱乐部分享:百度世界大会点燃AI创业者新希望

10月22日&#xff0c;2023年第十三期超声波俱乐部内部分享会在北京望京举行。本期的主题是&#xff1a;百度世界大会点燃AI创业者新希望。 到场的嘉宾有&#xff1a;超声波创始人杨子超&#xff0c;超声波联合创始人、和牛商业创始人刘思雨&#xff0c;中国国际经济交流中心研…

excel利用正则匹配和替换指定内容

上班中, 突然接到电话, 屋里的上司大人发来个excel, 说要替换里面x-x-xxx列的内容为x栋x单元xxx. 大致表格如下, 原表格我就不发了 身为程序猿的我, 肯定第一就想到了 正则! 打开excel-开始-查找和替换, 我擦, 只能完全匹配和替换 比如一次只能替换1-1- -> 为1栋1单元 1-2…

Java 零碎知识点

目录 [多线程]创建多线程的三种方式 [网络编程]一、重点概念1、TCP/IP网络模型2、IP 对象3、端口号4、协议UDP(User Datagram Protocol)TCP(Transmission Control Protocol) 二、UDP 通信三、TCP 通信 [前端][Vue]一、Vue3项目创建响应式函数父子通信父传子子传父 跨层组件通信…

Java规则引擎2.1.8版本新增功能说明

规则引擎更新功能 新增: 1.决策结束节点新增结果导出excel功能&#xff1b; 在决策流程的结束节点&#xff0c;可以将决策结果导出为Excel文件。这个功能为用户提供了更多的灵活性和便利性&#xff0c;使他们能够轻松地将决策结果数据进行进一步的分析和处理。 2.新增公有变…

@所有人,城市燃气信息化与信息安全建设方法

关键词&#xff1a;城市燃气信息化、智慧燃气建设、城市燃气安全、智慧燃气、智慧燃气平台 近几年&#xff0c;燃气作为一种新兴的燃料迅速普及开来&#xff0c;和燃气有关的企业之间的竞争也不可避免。身处在互联网的时代&#xff0c;企业只有顺应时代的潮流&#xff0c;将城…

代码最佳实践和指南(四)

错误处理和测试 错误处理和测试的重要性 测试你的代码是必要的&#xff0c;以确保你的代码正在做你认为它应该做的事情。尝试用小的、虚构的数据集测试你的代码&#xff0c;在那里你知道结果应该是什么&#xff0c;并检查你的程序是否给出了预期的答案。如果你有时间和资源&a…

SpringBoot 继承 Apollo 应用 简单步骤记录

1、pom.xml 添加依赖&#xff1b; <!--本地项目涉及到该sdk版本冲突时可能需要手动解决版本控制问题--><dependency><groupId>com.ctrip.framework.apollo</groupId><artifactId>apollo-client-tair</artifactId><version>1.4.0<…