springmvc限流解决方案

本文采用3中限流方案:

1,谷歌的guava框架
2,使用redis技术
3,使用lua + redis 技术

限流方案类型

1,令牌桶限流(guava) 2,计数器限流(redis)

各位看官可根据自己的项目情况选择方案!!!

package com.example.webtest.controller;import java.text.SimpleDateFormat;
import java.util.Date;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import com.example.webtest.service.Isacquire;
import com.google.common.util.concurrent.RateLimiter;import redis.clients.jedis.Jedis;/*** 令牌桶限流* @author zack* QQ群:167350653*/
@Controller
public class TokenBucketLimitController {final String SUCCESS = "success";final String FAIL = "fail";/*** 定义一个令牌桶,每秒钟放两个令牌*/final RateLimiter rateLimiter = RateLimiter.create(2);/*** 普通限流测试(令牌桶限流)(缺点:不适合分布式)* <dependency>*	    <groupId>com.google.guava</groupId>*	    <artifactId>guava</artifactId>*	    <version>23.0</version>*	</dependency>* @param name* @return*/@RequestMapping("/limiterTest")@ResponseBodypublic String limiterTest(String name) {SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");boolean acquire = false;//vip用户,2秒返回一次,一次获取4个令牌if(name!=null && "vip".equals(name)) {//尝试获取令牌acquire = rateLimiter.tryAcquire(4);}else {//尝试获取令牌acquire = rateLimiter.tryAcquire();}//判断获取令牌的结果if(acquire) {System.out.println("success获取令牌成功,当前时间:"+format.format(new Date()));return SUCCESS;}else {//当前的一秒钟之内已经没有令牌,返回失败,当前请求被限流System.out.println("fail获取令牌失败(被限流)");return FAIL+"(被限流)";}}/*** 限流阻塞测试(令牌桶限流)(缺点:不适合分布式)* @param name* @return*/@RequestMapping("/limiterTest2")@ResponseBodypublic String limiterTest2(String name) {SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");速率是每秒5个许可RateLimiter rateLimiter = RateLimiter.create(5);for(int i = 0;i<100;i++){//开启限流阻塞rateLimiter.acquire();System.out.println("下标:"+i+"  success获取令牌成功,当前时间:"+format.format(new Date()));}return SUCCESS;}/*** 计数器分布式限流,使用redis保持原子性(计数器限流)* pom文件引入jedis*<dependency>*		<groupId>redis.clients</groupId>*		<artifactId>jedis</artifactId>*		<version>3.0.1</version>*</dependency>* @param name* @return*/@RequestMapping("/limiterTest3")@ResponseBodypublic String limiterTest3(String name) {String result = SUCCESS;SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//获取redis连接Jedis jedis = new Jedis("127.0.0.1", 6379);jedis.auth("123456"); jedis.connect();//连接//限流的keyString key = "limiterTest3";//对key的value进行+1操作,aferValue就是+1后的值long aferValue = jedis.incr(key);if(aferValue == 1) {System.out.println("第一次");//设置key 60秒后失效jedis.expire(key, 60);}else {//判断是否超过限制10次if(aferValue > 10) {result = FAIL;}}System.out.println("请求次数:"+aferValue+"  当前时间:"+format.format(new Date())+"  能否成功连接:"+result);return result;}@Autowiredprivate Isacquire isacquire;/*** 使用 redis + lua 进行分布式限流(计数器限流)* @return*/@RequestMapping("/limiterTest4")@ResponseBodypublic String limiterTest4() {SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");//得到限流判断结果  ,15秒最多10次请求if(isacquire.acquire("limiterTest4",15,10)) {System.out.println("success获取令牌成功,当前时间:"+format.format(new Date()));return SUCCESS;}else {//当前的一秒钟之内已经没有令牌,返回失败,当前请求被限流System.out.println("fail获取令牌失败(被限流)");return FAIL+"(被限流)";}}}

下面为limiterTest4方法所用到的service类

package com.example.webtest.service;import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Service;import redis.clients.jedis.Jedis;@Service
public class Isacquire {private DefaultRedisScript<Long> redisScript;/*** 是否被限流* @param limitKey 关键字* @param second 限制秒数* @param limitCount 限制次数* @return* * pom文件需导入* <dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId></dependency>* */public boolean acquire(String limitKey,Integer second,Integer limitCount) {//获取redis连接Jedis jedis = new Jedis("127.0.0.1",6379);jedis.auth("123456"); jedis.connect();//连接redisScript = new DefaultRedisScript<>();//设置lua的返回值为luaredisScript.setResultType(Long.class);//加载我们自己写的lua脚本redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("rateLimiter.lua")));//执行lua脚本   参数说明:(lua脚本,key的数量,限制10次,60秒)Long result = (Long) jedis.eval(redisScript.getScriptAsString(),1,limitKey,String.valueOf(limitCount),String.valueOf(second));if(result == 0) {System.out.println("被限流");return false;}return true;}}

rateLimiter.lua文件

--获取传入的参数key
local key = KEYS[1];
--限制参数
local limitCount = ARGV[1];
--限制周期
local expire = ARGV[2];
--对指定的key进行+1的操作
local afterValue = redis.call('incr',key);
--第一次,设置失效时间, 备注:tonumber转为number
if afterValue == 1 thenredis.call("expire",key,tonumber(expire));return 1;
end
--判断次数是否超过限制,超过返回0
if afterValue > tonumber(limitCount) thenreturn 0;
endreturn 1;

pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.6.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>webtest</artifactId><version>0.0.1-SNAPSHOT</version><name>webtest</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 引入Guava实现:令牌桶限流 --><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>23.0</version></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId></dependency><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

备注:如需下载项目源码请在QQ群中167350653下载

另外更优雅的方式是将redis+lua限流方案改成一个注解方式,在需要的方法上加注解更灵活和方便,将在下一篇文章中展示。

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

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

相关文章

二叉树的三种遍历(递归与非递归) + 层次遍历

<转载于 >>> > 二叉树是一种非常重要的数据结构&#xff0c;很多其他数据机构都是基于二叉树的基础演变过来的。二叉树有前、中、后三种遍历方式&#xff0c;因为树的本身就是用递归定义的&#xff0c;因此采用递归的方法实现三种遍历&#xff0c;不仅代码简洁…

springboot使用mongodb

大家好&#xff0c;我是烤鸭&#xff1a;这是一篇关于springboot项目中使用mongodb。 环境&#xff1a;jdk 1.8springboot 1.5.6.RELEASEmaven 3.5 1. mongodb在springboot中的配置springboot集成这个三方插件就是简单&#xff0c;只需要引入依赖&#xff0c;在properties或者…

[css] 请使用css画一个圆,方法可以多种

[css] 请使用css画一个圆&#xff0c;方法可以多种 <div class"circle"></div>1.border-radius.cirlce{width:10vw; height:10vw; background:gray;border-radius:50%; }2.clip-path.circle{width:10vw; height:10vw; background:gray;clip-path: circl…

springboot中getOutputStream() has already been called for this response和java.io.FileNotFoundException

这个异常挺多人遇到的&#xff0c;不过我看了一下&#xff0c;跟我们的情况都不一样。 1. 流没关闭。 2. 未设置响应头。 3. jsp页面需要清空流。说一下我们遇到的情况。就是一个简单的sprinboot项目。 用的是springboot 1.5.6&#xff0c;本地启动后用花生壳内网映射…

eclipse搜索框太小

解决方式&#xff1a; Window>Preferences>DevStyle>Inline Search 把 use the inline search 取消勾选

fileinput 加 ftp 加 nginx 加 SpringBoot上传文件

亲测可用 准备linux服务器 https://www.cnblogs.com/shuaifing/p/8268949.html 搭建ftp https://www.cnblogs.com/shuaifing/p/8260532.html Springboot整合fileinput 上传文件https://www.cnblogs.com/shuaifing/p/8274906.html 页面 引入 jquery boostrap fileinput.min.js…

[css] css中最常用的字体有哪些?你是怎么选择字体的?

[css] css中最常用的字体有哪些&#xff1f;你是怎么选择字体的&#xff1f; 总结&#xff1a; win&#xff1a;微软雅黑为Win平台上最值得选择的中文字体&#xff0c;但非浏览器默认&#xff0c;需要设置&#xff1b;西文字体的选择以Arial、Tahoma等无衬线字体为主。 mac&am…

springboot redis shiro 实现 单点登录

大家好&#xff0c;我是烤鸭&#xff1a;今天给大家分享简单的单点登录的实现方式。环境及jar包:springboot 1.5.10 redis 2.9.0 &#xff08;可以用tomcat的session&#xff0c;但是无法解决多个tomcat共享session的问题&#xff09;shiro 1.4.0 lombok …

IntelliJ IDEA 控制台最大化

快捷键一&#xff1a; ctrlshift方向键上下 快捷键二&#xff1a; CtrlShift"

Centos7安装Hadoop教程

一&#xff1a;安装SSH 1&#xff0c;执行下面的命令安装ssh yum install openssh-clients yum install openssh-server 2&#xff0c;执行如下命令测试一下 SSH 是否可用&#xff08;SSH首次登陆提示 yes/no 信息&#xff0c;输入 yes 即可&#xff0c;然后按照提示输入 root…

[css] 请举例说明css有哪些不可继承的属性?

[css] 请举例说明css有哪些不可继承的属性&#xff1f; 1、display&#xff1a;规定元素应该生成的框的类型2、文本属性&#xff1a;vertical-align&#xff1a;垂直文本对齐text-decoration&#xff1a;规定添加到文本的装饰text-shadow&#xff1a;文本阴影效果white-space&…

elasticsearch 6.x (一) 部署 windows入门 spingboot连接

大家好&#xff0c;我是烤鸭&#xff1a;今天分享的是 elasticsearch 6.x 部署 windows服务器。环境&#xff1a;win10elasticsearch-6.2.4springboot 2.0.0.RELEASE1. 官网下载elasticsearch这个是最新版本的es下载地址。https://www.elastic.co/downloads/elasticsearch选择z…

Programming Assignment 5: Burrows–Wheeler Data Compression

Programming Assignment 5: Burrows–Wheeler Data Compression 1. 题目阅读 实现Burrows-Wheeler数据压缩算法。这个革命性的算法产生了gzip和pkzip&#xff0c;并且相对容易实现&#xff0c;还不受任何专利保护。它构成了unix压缩实用程序bzip2的基础。 这个算法由以下三种算…

hadoop Connection refused: no further information原因排查(Centos7)

一&#xff1a;排查防火墙&#xff0c;是否开放9000端口 firewall-cmd --list-ports查看防火墙是否有9000端口&#xff0c;如果没有&#xff0c;通过下面的命令添加端口&#xff1a; firewall-cmd --zonepublic --add-port9000/tcp --permanent systemctl restart firewalld…

[css]你有使用过preload、preconnect、prefetch这些属性吗?说说它们都有什么作用?

[css]你有使用过preload、preconnect、prefetch这些属性吗&#xff1f;说说它们都有什么作用&#xff1f; preload 元素的 rel 属性的属性值preload能够让你在你的HTML页面中元素内部书写一些声明式的资源获取请求&#xff0c;可以指明哪些资源是在页面加载完成后即刻需要的。…

elasticsearch 6.x (二) linux部署 kibana x-pack 安装

大家好&#xff0c;我是烤鸭&#xff1a; 环境&#xff1a;linux Cent OS 7.3elasticsearch-6.2.4 1. 下载elasticsearch https://www.elastic.co/downloads/elasticsearch 上面的网址直接下载的话&#xff0c;实在太慢了。官方还提供了另一种方式。 https://www.elastic.co…

Kali Linux ——在无网络情况下安装无线网卡驱动

1、背景&#xff1a; 今日刚刚开始学习kali linux&#xff0c;众所周知&#xff0c;安装完成后&#xff0c;系统是没有无线网卡驱动的&#xff0c;这就对学生党造成相当的困扰&#xff1a;校园网要连接有线是需要认证客户端的&#xff0c;而认证客户端只有windows端&#xff0c…

HADOOP_HOME and hadoop.home.dir are unset 报错处理

一般是windows才会出现这个问题 请看下面的解决方案&#xff1a; 第一步&#xff1a;下载winutils-master.zip Gitee地址&#xff1a;https://gitee.com/nkuhyx/winutils.git 蓝奏云&#xff1a;https://www.lanzoux.com/i55ccnc Github地址&#xff1a;https://github.com/cda…

[css] 你是怎样对css文件进行压缩合并的?

[css] 你是怎样对css文件进行压缩合并的&#xff1f; 使用在线网站进行压缩&#xff0c;如http://tool.lu/css如使用Gulp&#xff0c;可使用gulp-minify-css进行压缩如使用WebPack&#xff0c;可使用optimize-css-assets-webpack-plugin进行压缩个人简介 我是歌谣&#xff0c;…

elasticsearch 6.x (三) linux 集群多节点部署

大家好&#xff0c;我是烤鸭&#xff1a;关于集群内单个节点部署&#xff0c;请参考上一篇文章。elasticsearch 6.x linux部署(二) kibana x-pack 安装环境&#xff1a;linux Cent OS 7.3elasticsearch-6.2.41. 下载多个es安装每个安装步骤都是一样的。2. 修改配置文件(重…