上周公司里发生了一件怪事,就是我们自己系统的注册接口被人恶意频繁访问最后导致该服务不可用,该注册接口是输入电话号码然后获取验证码注册,有人用遍历的方法无限重试验证码,最终服务没抗住挂掉了。更怪的是查到这个人的ip竟然是自己内部的公网ip,大概是有人闲的无聊了在搞怪,没办法,又不能封了ip,那样大家都访问不了了。

So,今天有空研究了一下关于如何解决api接口高并发的问题,在此记录一下。

1、通过控制并发数量来实现

信号量:这应该是大学操作系统课本里的概念,它是用在多进程和多任务之间的同步的,它就像十字路口的红绿灯,保证这个路口四条路的畅通行驶。

java中也有这个概念,Java并发库的Semaphore可以很轻松完成信号量控制,Semaphore可以控制某个资源可被同时访问的个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。

写一个测试接口如下:

private final Semaphore permit = new Semaphore(10, true);
@PostMapping("/test")public String test(){try {permit.acquire();log.info("处理请求===============>");Thread.sleep(2000);}catch (Exception e){log.error("error");}finally {permit.release();}return "success";}

以上是我写了一个测试接口,这个接口最多允许同时10个并发量,超过10个则等待。

接下来我们用压力测试工具测一下这个接口,这个是我用的测试工具:

http://coolaf.com//tool/post 这是在线的,不能修改并发数,里面有本地版本,下载解压就能用。

下载解压后,在工具上输入url和并发量

这里设置并发量为50,也就是同时50个客户端访问该接口,点击开始测试,查看日志

我们可以看到,每次只有10个请求进入接口,然后过2秒后再来10个请求,效果很明显,我们想增大访问量只需要修改初始的信号量的数量即可。

2、通过控制访问速率来实现

这种方式采用令牌桶算法来实现,我们以一个恒定的速率向一个桶内放令牌,每次请求来的时候去桶里拿令牌,如果拿到了就继续后面的操作,如果没有拿到则等待。

在我们的工程实践中,通常使用Google开源工具包Guava提供的限流工具类RateLimiter来实现控制速率,该类基于令牌桶算法来完成限流,非常易于使用,而且非常高效。如我们不希望每秒的任务提交超过1个。

public static void main(String[] args) {String start = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());RateLimiter limiter = RateLimiter.create(1.0); // 这里的1表示每秒允许处理的量为1个for (int i = 1; i <= 10; i++) {double waitTime = limiter.acquire(i);// 请求RateLimiter, 超过permits会被阻塞System.out.println("cutTime=" + System.currentTimeMillis() + " call execute:" + i + " waitTime:" + waitTime);}String end = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());System.out.println("start time:" + start);System.out.println("end time:" + end);}

RateLimiter limiter = RateLimiter.create(1.0) 创建一个限流器,每秒生成1个令牌;

limiter.acquire(i) 以阻塞的方式获取令牌,随着i的增加,需要的令牌数增多,则需要等待的时间也增加。

查看输出结果:

可以看出,当 i=6时,等待时间差不多为i-1=5秒,在这里是因为RateLimiter支持预消费,来支持一定程度的突发情况。

开可以用tryAcquire(int permits, long timeout, TimeUnit unit)来设置等待超时时间的方式获取令牌,当等待超过了超时时长则立马返回。

令牌的生成策略有两种,一种是稳定模式(SmoothBursty 模式),一种为渐进模式(SmoothWarmingUp模式)。

SmoothBursty 模式:RateLimiter limiter = RateLimiter.create(5);

RateLimiter.create(5)表示桶容量为5且每秒新增5个令牌,即每隔200毫秒新增一个令牌;limiter.acquire()表示消费一个令牌,如果当前桶中有足够令牌则成功(返回值为0),如果桶中没有令牌则暂停一段时间,比如发令牌间隔是200毫秒,则等待200毫秒后再去消费令牌,这种实现将突发请求速率平均为了固定请求速率。

SmoothWarmingUp模式:RateLimiter limiter = RateLimiter.create(5,1000, TimeUnit.MILLISECONDS);

创建方式:RateLimiter.create(doublepermitsPerSecond, long warmupPeriod, TimeUnit unit),permitsPerSecond表示每秒新增的令牌数,warmupPeriod表示在从冷启动速率过渡到平均速率的时间间隔。速率是梯形上升速率的,也就是说冷启动时会以一个比较大的速率慢慢到平均速率;然后趋于平均速率(梯形下降到平均速率)。可以通过调节warmupPeriod参数实现一开始就是平滑固定速率。

写一个测试接口测试

private final RateLimiter limiter = RateLimiter.create(5.0);@PostMapping("/test2")public String test2(){try {boolean flag = limiter.tryAcquire(1,3, TimeUnit.SECONDS);if (flag){log.info("处理请求===============>");Thread.sleep(1000);}else {return "系统繁忙!";}}catch (Exception e){log.error("error");}return "success";}

每秒产生5个令牌,请求进来每次获取一个,然后超时时长是3秒,还是设置50的并发量:

查看输出结果:

可以看到,一开始预消费进来了8个请求,随后的时间里每次进来5个请求,在这之间有超时3秒没有获取到令牌的都返回超时了。返回结果如下:

至此,我所了解的解决接口并发调用的方法就是这些,欢迎大佬指出错误和不足。

如何解决api接口的并发问题?相关推荐

  1. python并发1000个http请求_php下api接口的并发http请求

    php下api接口的并发http请求 ,提高app一个页面请求多个api接口,页面加载慢的问题: func_helper.php /*** 并发http请求** [* 'url' //请求地址* 'm ...

  2. shell脚本api接口考虑并发问题的可行性操作

    当我们通过收集每台客户端数据后通过api接口上传到云服务器时,可能会由于客户端过多,几千以至于几万,这时不得不考虑个问题: 并发的问题,同时并发上传文件,可能导致api接口挂掉,但如果我们让文件错开时 ...

  3. api接口参数加密_解决API接口开发安全性的四种方案

    如今各种API接口层出不穷,一个API的好与不好有很多方面可以考量,其中"安全性"是一个API接口最基本也是最重要的一个特点.尤其是对于充值缴费类的API接口来说,如话费充值API ...

  4. 直播系统开发中如何优化API接口的并发

    概述 在直播系统中,API接口并发的优化是非常重要的,因为它可以提高系统的稳定性和性能.本文将介绍一些优化API接口并发的方法. 理解API接口并发 在直播系统中,API接口是用于处理客户端请求的关键 ...

  5. 关于vue2用vue-cli搭建环境后域名代理的http-proxy-middleware解决api接口跨域问题

    在vue中用http-proxy-middleware来进行接口代理,比如:本地运行环境为http://localhost:8080但真实访问的api为 http://www.baidu.com这时我 ...

  6. 如何用代理解决api接口跨域问题

    首先我们要了解跨域产生的原因: 域名.协议.端口有一个不同就会产生跨域,是浏览器的同源策略引起的 (所谓同源是指:域名.协议.端口相同.) 使用一个中间层来发请求.只需要前端来处理即可. 解决跨域的方 ...

  7. JAVA中文注解驱动,解决api接口返回的json里面出现中文乱码的问题

    在src/main/resources/springmvc-servlet.xml中加入 <!-- 中文注解驱动 --> <mvc:annotation-driven>< ...

  8. 盘点 8 款好用的 API 接口文档管理工具

    随着互联网的普及和发展,API 接口已经无处不在.它已经在 Web 应用程序.移动应用程序.云计算.物联网.人工智能等领域中得到广泛应用. 例如,在金融行业中,API 接口可以被用于构建支付服务.银行 ...

  9. 淘宝商品详情api接口(解决滑块支持高并发采集)

    采集淘宝商品列表和商品详情遇到滑块验证码的解决方法(带SKU和商品描述,可高并发),主要是解决了高频情况下的阿里系滑块和必须要N多小号才能解决的反扒问题,以后都可以使用本方法: 大家都知道,淘宝的反爬 ...

  10. [待解决]自定义头像时使用vue-cropper进行图片裁剪,得到的是base64格式的图片,如何对接file类型的api接口

    [待解决]自定义头像时使用vue-cropper进行图片裁剪,得到的是base64格式的图片,如何对接file类型的api接口 百度很多都没用,有想法欢迎指点.

最新文章

  1. 用C#生成随机中文汉字验证码的基本原理
  2. 微软Cortana全面升级神经网络语音,效果堪比真人发音
  3. 计算机三级考试在线免费题库,国家三级计算机考试题库.docx
  4. nodejs之http-proxy几点常见问题
  5. Android开发--传感器介绍
  6. 关于LCD的分屏与切屏 Tearing effect
  7. [HEOI2016/TJOI2016]求和
  8. 免费的HTML5连载来了《HTML5网页开发实例具体解释》连载(四)HTML5中的FileSystem接口...
  9. SAP MM模块-实施顾问岗位-面试手册-面试总结
  10. c语言正则表达式_CS143:编译原理|PA2:正则表达式和词法分析
  11. python表格写操作单元格合并
  12. Enterprise Solution 解决方案与源代码下载
  13. idea设置自定义代码模板(webstorm也是如此)
  14. 你会想待下去吗?世界上25个最惊险的屋顶
  15. Caffe学习:pycaffe利用caffemodel进行分类=批处理
  16. 20200710每日一句
  17. Tableau实战 楼市降温分析(七)现期房销售额及累计增长
  18. 【Python | 入门】 从输出打印到面对对象(五分钟速通Python)
  19. java泛型:T与?的使用及区别
  20. 计算机毕业设计Java“小蜜蜂”校园代取快递系统(源码+系统+mysql数据库+lw文档)

热门文章

  1. Codeforces Round #580 (Div. 1)(CF1205)A-E
  2. Django 09-2 模型层 字段
  3. 洛谷2805 [NOI2009]植物大战僵尸 (拓扑排序+最小割)
  4. 圆形Camera预览实现
  5. java枚举类型详解
  6. win7如何不用点击用户名 直接自动登录桌面
  7. MySQL学习十四创建和操纵表
  8. 分布式作业 Elastic Job 如何动态调整?
  9. Python Web开发
  10. 编译与运行、解释程序与编译程序