Google Guava缓存实现接口的限流

一.项目背景

最近项目中需要进行接口保护,防止高并发的情况把系统搞崩,因此需要对一个查询接口进行限流,主要的目的就是限制单位时间内请求此查询的次数,例如1000次,来保护接口。
参考了 开涛的博客聊聊高并发系统限流特技 ,学习了其中利用Google Guava缓存实现限流的技巧,在网上也查到了很多关于Google Guava缓存的博客,学到了好多,推荐一个博客文章:http://ifeve.com/google-guava-cachesexplained/,关于Google Guava缓存的更多细节或者技术,这篇文章讲的很详细;
这里我们并不是用缓存来优化查询,而是利用缓存,存储一个计数器,然后用这个计数器来实现限流。

二.效果实验

static LoadingCache<Long, AtomicLong> count = CacheBuilder.newBuilder().expireAfterWrite(2, TimeUnit.SECONDS).build(new CacheLoader<Long, AtomicLong>() {@Overridepublic AtomicLong load(Long o) throws Exception {//System.out.println("Load call!");return new AtomicLong(0L);}});

上面,我们通过CacheBuilder来新建一个LoadingCache缓存对象count,然后设置其有效时间为两秒,即每两秒钟刷新一次;缓存中,key为一个long型的时间戳类型,value是一个计数器,使用原子性的AtomicLong保证自增和自减操作的原子性, 每次查询缓存时如果不能命中,即查询的时间戳不在缓存中,则重新加载缓存,执行load将当前的时间戳的计数值初始化为0。这样对于每一秒的时间戳,能计算这一秒内执行的次数,从而达到限流的目的;
这是要执行的一个getCounter方法:

public class Counter {static int counter = 0;public static int getCounter() throws Exception{return counter++;}
}

现在我们创建多个线程来执行这个方法:

ublic class Test {public static void main(String args[]) throws Exception{for(int i = 0;i<100;i++){new Thread(){@Overridepublic void run() {try {System.out.println(Counter.getCounter());}catch (Exception e){e.printStackTrace();}}}.start();}}
}

这样执行的话,执行结果很简单,就是很快地执行这个for循环,迅速打印0到99折100个数,不再贴出。
这里的for循环执行100个进程时间是很快的,那么现在我们要限制每秒只能有10个线程来执行getCounter()方法,该怎么办呢,上面讲的限流方法就派上用场了:

public class Counter {static LoadingCache<Long, AtomicLong> count = CacheBuilder.newBuilder().expireAfterWrite(2, TimeUnit.SECONDS).build(new CacheLoader<Long, AtomicLong>() {@Overridepublic AtomicLong load(Long o) throws Exception {System.out.println("Load call!");return new AtomicLong(0L);}});static long limits = 10;static int counter = 0;public static synchronized int getCounter() throws Exception{while (true){//获取当前的时间戳作为keyLong currentSeconds = System.currentTimeMillis() / 1000;if (count.get(currentSeconds).getAndIncrement() > limits) {continue;}return counter++;}}
}

这样一来,就可以限制每秒的执行数了。对于每个线程,获取当前时间戳,如果当前时间(当前这1秒)内有超过10个线程正在执行,那么这个进程一直在这里循环,直到下一秒,或者更靠后的时间,重新加载,执行load,将新的时间戳的计数值重新为0。
执行结果:
这里写图片描述
每秒执行11个(因为从0开始),每一秒之后,load方法会执行一次;

为了更加直观,我们可以让每个for循环sleep一段时间:public class Test {public static void main(String args[]) throws Exception{for(int i = 0;i<100;i++){new Thread(){@Overridepublic void run() {try {System.out.println(Counter.getCounter());}catch (Exception e){e.printStackTrace();}}}.start();Thread.sleep(100);}}
}

在上述这样的情况下,一个线程如果遇到当前时间正在执行的线程超过limit值就会一直在while循环,这样会浪费大量的资源,我们在做限流的时候,如果出现这种情况,可以不进行while循环,而是直接抛出异常或者返回,来拒绝这次执行(查询),这样便可以节省资源。

转载于:https://www.cnblogs.com/sunp823/p/5601395.html

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

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

相关文章

javaweb 常用jar包_使用javaweb写一个登录案例

下载地址&#xff1a;https://gitee.com/dl_shrimp/java_web_login_case.githttps://www.zhihu.com/video/1241780888599699456讲一下如何使用javaweb写一个登录案例Dao就是用来操作数据库的一些类的统称&#xff08;1&#xff09;DAO是Data Access Object数据访问接口。数据访…

Vue项目中使用图片裁切器 cropperjs (头像裁切)

cropperjs官方文档 cropperjs结合element-ui 组件后的显示效果: 1. npm 安装 cropperjs cmd命令行输入&#xff1a;npm install cropperjs --save 2. 导入相关js和css文件 import cropperjs/dist/cropper.css import Cropper from cropperjs3. 用块元素&#xff08;容器&…

mysql常见问题记录

1.常见命令&#xff1a;查看mysql表结构的方法有三种&#xff1a;1、desc tablename;2、show create table tablename;3、use information_schema;select * from columns where table_nametablename例如&#xff1a;要查看jos_modules表结构的命令&#xff1a;use information_…

跳一跳python源码下载_python 微信跳一跳和源码解读

刚好周末&#xff0c;想研究一下前阵子很火的微信跳一跳 下面进入正文。 本文适用对象为WIN10系统&#xff0c;安卓用户。目的在于让丝毫没有接触过Python的小伙伴都能成功运行&#xff0c;如果你恰好是这样的对象&#xff0c;那么跟着我开始操作。我会把我自己的每一步都写下来…

HTML文件上传对象file

window.URL.createObjectURL(fileObj)

python自动化接口测试excel用例串行之行_python 读取 Excel 自动化执行测试用例

python 读取 Excel 自动化执行测试用例 Excel 测试用例的读取 安装 python 操作Excel 的库 pip install xlrd/xlwt/xlutils (安装三个操作库) 接口请求代码构建 import requests from random import randint import xlrd import json class My_request(object): # 对返回值进行…

Vue项目中使用Echarts(二)

1. 安装&#xff1a; 通过 npm 获取 echarts&#xff0c;npm install echarts --save 2. 最终页面展示效果如下&#xff1a; 三、代码实现 map-demo.vue: <template><!-- 1. 为 ECharts 准备一个具备大小&#xff08;宽高&#xff09;的 DOM --><div ref&quo…

python批量处理excel文本改为数字_Python批量修改Excel中的文件内容

import os import xlrd from xlutils.copy import copy def base_dir(filenameNone): return os.path.join(os.path.dirname(__file__),filename) """对excel进行操作""" work xlrd.open_workbook(base_dir("excel.xls")) # 索引到第…

正则表达式替换排除特定情况

1.只替换第一次出现的字符串“红豆”&#xff1b; $s"iam carl 小红豆杉苗 <a hrefabc>dfsaf<a href\"fdsafdsaf\">大红豆杉</a></a> carl fds<b>af红豆dsa</b>few"; $r preg_replace(/红豆/i, 绿豆,$s,1); var_dump…

Vue项目中使用百度地图API

百度地图官方文档 1. 申请百度账号和ak 申请 2. 引用百度地图API文件 <script type"text/javascript" src"https://api.map.baidu.com/api?v1.0&&typewebgl&ak您的密钥">3. 设置容器样式 设置容器样式大小 4. 创建地图容器元素 …

python3.6.8安装失败_centos7编译安装Python 3.6.8 后用pip3出现SSL未配置问题(import ssl失败)解决方法...

下载源码编译安装openssl https://www.openssl.org/source/openssl-1.0.2j.tar.gz ./config --prefix/usr/local/openssl ./config -t ./make && make install 下载源码编译安装python3.6.8 https://www.python.org/ftp/python/3.6.8/Python-3.6.8.tar.xz 修改python3.…

8.0/9.0 Email 设置

Email 设置一直都是Odoo的一个坑&#xff0c;巨坑。 先讲结论&#xff0c;发邮件可以用&#xff0c;收还是算了吧 1. 发邮件设置 发的设置相对简单&#xff0c;如果企业邮箱支持catcll all功能&#xff0c;基本不用改动可以直接用&#xff0c;否则需要安装第三方模块&#xff0…

Vue v-model 指令详解以及sync修饰符的使用场景(结合父子组件通信案例)

参考Vue官方文档 一、需求如下&#xff1a; 二、代码如下 三、分步解析&#xff1a; 父组件给子组件传值&#xff1a; 子组件给父组件传值&#xff1a; 四、sync修饰符的使用 vue.js官方文档 如果已经使用了v-model双向绑定了一个数据&#xff0c;但是还想要实现另一个数…

stm32F1使用SD卡实现IAP

最近在做一个项目&#xff0c;想使用uSD卡来实现在应用编程&#xff0c;首先需要一些知识 我所使用的单片机是STM32F103ZE&#xff0c;内部flash&#xff0c;超始地址为0x8000000&#xff0c;大小为0x80000&#xff08;0x80000/1024也就是512kByte&#xff09;要实现IAP&#x…

父组件访问子组件中的数据(父子组件通信案例:父组件访问子组件$refs[‘子组件‘],子组件传递数据给父组件(父组件中使用v-model))

一、需求 二、在父组件upload-cover中&#xff1a; 通过$refs[子组件的ref属性值]就能拿到子组件对象 三、在子组件imgae-list&#xff08;相对于父组件upload-cover来说&#xff0c;image-list组件是子组件&#xff09;中 通过在data中定义一个selected&#xff0c;来保存…

[设计模式]6. C++与职责链模式(chain of rsponsibility pattern)

默默地EEer&#xff0c;原文地址&#xff1a; http://www.cnblogs.com/hebaichuanyeah/p/5625233.html 职责链模式指使多个对象多有机会处理请求&#xff0c;避免请求发送者和接受者的耦合关系。 将这些接受处理的对象连成一条链&#xff0c;并沿着该链处理请求。 一个传说中的…

python删除为空值的列_python如何删除列为空的行

1.摘要 dropna()方法&#xff0c;能够找到DataFrame类型数据的空值&#xff08;缺失值&#xff09;&#xff0c;将空值所在的行/列删除后&#xff0c;将新的DataFrame作为返回值返回。 2.函数详解 函数形式&#xff1a;dropna(axis0, howany, threshNone, subsetNone, inplaceF…

axios请求拦截器、响应拦截器、vue-router路由导航守卫的使用(案例)

axios官方文档 一、请求拦截器 设置headers,给所有请求加上Authorization&#xff1a;token值 二、响应拦截器 直接去访问/article,发现可以进入到article内容管理页面 原因是在vue路由拦截器中&#xff0c;我们是这样来判断用户是否有权限访问除了登录页面之外的其他页面&a…

gdb交叉编译

gdb交叉编译网上有很多教程&#xff0c;在编译时&#xff0c;会碰到一条错误&#xff1a; configure: error: no termcap library found一般的解决是下载termcap代码&#xff0c;然后编译成目标系统的lib&#xff0c;放入目标系统编译环境中&#xff0c;但是—————— 有时…

Vue项目部署,打包发布上线

参考vuecli官方文档 一、构建打包 在发布上线之前&#xff0c;我们需要执行构建打包&#xff0c;将 .less、.vue、.js 等相关资源进行编译打包&#xff0c;转换成浏览器可以直接识别运行的普通 css、js、html。 # yarn run build 或者 yarn build npm run buildVueCLI 会把打…