实战限流(guava的RateLimiter)
关于限流
常用的限流算法有漏桶算法和令牌桶算法,guava的RateLimiter使用的是令牌桶算法,也就是以固定的频率向桶中放入令牌,例如一秒钟10枚令牌,实际业务在每次响应请求之前都从桶中获取令牌,只有取到令牌的请求才会被成功响应,获取的方式有两种:阻塞等待令牌或者取不到立即返回失败,下图来自网上:

本次实战,我们用的是guava的RateLimiter,场景是spring mvc在处理请求时候,从桶中申请令牌,申请到了就成功响应,申请不到时直接返回失败;
源码下载
对于的源码可以在我的git下载,地址是:https://github.com/zq2599/blog_demos ,里面有多个工程,本次实战的工程为guavalimitdemo,如下图红框所示:

实战开发
创建一个maven工程,在pom中把guava的依赖添加进来:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
把限流服务封装到一个类中AccessLimitService,提供tryAcquire()方法,用来尝试获取令牌,返回true表示获取到,如下所示:
@Service
public class AccessLimitService {
//每秒只发出5个令牌
RateLimiter rateLimiter = RateLimiter.create(5.0);
/**
* 尝试获取令牌
* @return
*/
public boolean tryAcquire(){
return rateLimiter.tryAcquire();
}
}
调用方是个普通的controller,每次收到请求的时候都尝试去获取令牌,获取成功和失败打印不同的信息,如下:
@Controller
public class HelloController {
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Autowired
private AccessLimitService accessLimitService;
@RequestMapping("/access")
@ResponseBody
public String access(){
//尝试获取令牌
if(accessLimitService.tryAcquire()){
//模拟业务执行500毫秒
try {
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
return "aceess success [" + sdf.format(new Date()) + "]";
}else{
return "aceess limit [" + sdf.format(new Date()) + "]";
}
}
}
以上就是服务端的代码了,打包部署在tomcat上即可,接下来我们写一个类,十个线程并发访问上面写的controller:
public class AccessClient {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
/**
* get请求
* @param realUrl
* @return
*/
public static String sendGet(URL realUrl) {
String result = "";
BufferedReader in = null;
try {
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 建立实际的连接
connection.connect();
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
public void access() throws Exception{
final URL url = new URL("http://localhost:8080/guavalimitdemo/access");
for(int i=0;i<10;i++) {
fixedThreadPool.submit(new Runnable() {
public void run() {
System.out.println(sendGet(url));
}
});
}
fixedThreadPool.shutdown();
fixedThreadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
}
public static void main(String[] args) throws Exception{
AccessClient accessClient = new AccessClient();
accessClient.access();
}
}
直接执行AccessClient的main方法,可以看到结果如下:

部分请求由于获取的令牌可以成功执行,其余请求没有拿到令牌,我们可以根据实际业务来做区分处理。还有一点要注意,我们通过RateLimiter.create(5.0)配置的是每一秒5枚令牌,但是限流的时候发出的是6枚,改用其他值验证,也是实际的比配置的大1。
以上就是快速实现限流的实战过程,此处仅是单进程服务的限流,而实际的分布式服务中会考虑更多因素,会复杂很多。
欢迎关注我的公众号:程序员欣宸

实战限流(guava的RateLimiter)的更多相关文章
- 限流 - Guava RateLimiter
2019独角兽企业重金招聘Python工程师标准>>> 限流 限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦并发访问/请求达到限制速率或者 ...
- coding++:高并发解决方案限流技术-使用RateLimiter实现令牌桶限流-Demo
RateLimiter是guava提供的基于令牌桶算法的实现类,可以非常简单的完成限流特技,并且根据系统的实际情况来调整生成token的速率. 通常可应用于抢购限流防止冲垮系统:限制某接口.服务单位时 ...
- 高并发解决方案限流技术-----使用RateLimiter实现令牌桶限流
1,RateLimiter是guava提供的基于令牌桶算法的实现类,可以非常简单的完成限流特技,并且根据系统的实际情况来调整生成token的速率.通常可应用于抢购限流防止冲垮系统:限制某接口.服务单位 ...
- SpringBoot 2.0 + 阿里巴巴 Sentinel 动态限流实战
前言 在从0到1构建分布式秒杀系统和打造十万博文系统中,限流是不可缺少的一个环节,在系统能承受的范围内既能减少资源开销又能防御恶意攻击. 在前面的文章中,我们使用了开源工具包 Guava 提供的限流工 ...
- RateLimit--使用guava来做接口限流
转:https://blog.csdn.net/jiesa/article/details/50412027 一.问题描述 某天A君突然发现自己的接口请求量突然涨到之前的10倍,没多久该接口几乎不 ...
- coding++:RateLimiter 限流算法之漏桶算法、令牌桶算法--简介
RateLimiter是Guava的concurrent包下的一个用于限制访问频率的类 <dependency> <groupId>com.google.guava</g ...
- 基于kubernetes的分布式限流
做为一个数据上报系统,随着接入量越来越大,由于 API 接口无法控制调用方的行为,因此当遇到瞬时请求量激增时,会导致接口占用过多服务器资源,使得其他请求响应速度降低或是超时,更有甚者可能导致服务器宕机 ...
- 高并发之API接口限流
在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流 缓存 缓存的目的是提升系统访问速度和增大系统处理容量 降级 降级是当服务出现问题或者影响到核心流程时,需要暂时屏蔽掉,待高峰或者问题解决后再 ...
- Spring Cloud限流详解
转自:https://blog.csdn.net/tracy38/article/details/78685707 在高并发的应用中,限流往往是一个绕不开的话题.本文详细探讨在Spring Cloud ...
随机推荐
- 世纪龙校招java开发一、二面 面经
头一天做的笔试,涉及到计组基本知识,还有几道智力题.java部分很简单(真的很简单有点基础就划过了) 第二天收简历 在隔壁教室等 叫到你 你就去面试 一面:先自我介绍 1 == 和 equals区别( ...
- 前端表格数据导出excel
使用tableExport.js导出bootstrap-table表格成excel并且支持中文 1. 下载tableExport.js https://github.com/hhurz/tableEx ...
- 剑指Offer(十八):二叉树的镜像
剑指Offer(十八):二叉树的镜像 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net/baidu ...
- sql中#与$取值
在mapper.xml中#与$都是用来取值的 <update id="addUrl"> update user_power set url = #{newurl} wh ...
- pip3 Traceback (most recent call last)错误调试
百度找的答案不知道是否正确反正不适用于deepin,就手动调试了一下,结果修复了原理不清楚. 调试环境: OS:deepin 15.11 Python3-pip 错误提示: python@python ...
- centos7yum安装mysql5.7
https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-centos-7 https://typecodes. ...
- qt学习笔记(1):qt点击运行没有反应。
因为公司的项目需要,今天开始重新学习已经忘干净了的QT, 说起qt之前在学校刚接触的时候就打心底里喜欢这个编辑器, 因为一直使用vs做项目,面对着黑洞洞的窗口总让人不舒服, 自从接触了qt感觉迎来了曙 ...
- HDU - 4370 0 or 1 最短路
HDU - 4370 参考:https://www.cnblogs.com/hollowstory/p/5670128.html 题意: 给定一个矩阵C, 构造一个A矩阵,满足条件: 1.X12+X1 ...
- lightoj 1068 - Investigation(数位dp)
An integer is divisible by 3 if the sum of its digits is also divisible by 3. For example, 3702 is d ...
- CF - 1110F Nearest Leaf
题目传送门 题解: 先用题目给定的dfs方式得到dfs序,记录下出入的dfs序. 很明显可以得知的是,以u为根的子树的dfs序在 in[u] - out[u] 的范围之内. 将每个询问先全部存到对应的 ...