设计一个基于用户的API限流策略 Rate Limit
设计一个基于用户的API限流策略 Rate Limit
应用场景
API接口的流量控制策略:缓存、降级、限流。限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的。限流策略虽然降低了服务接口的访问频率和并发量,却换取服务接口和业务应用系统的高可用。
常用的限流策略:
Nginx
限流按照一定的规则如帐号、IP、系统间调用逻辑等在
Nginx
层面做限流业务系统限流
客户端限流
服务端限流
数据库限流
常用限流算法
计数器
计数器是最简单粗暴的算法,通过直接统计每个时间的请求数目来判断是否需要拒绝。
比如某个服务最多只能每秒钟处理
100
个请求。我们可以设置一个1
秒钟的滑动窗口,窗口中有10
个格子,每个格子100
毫秒,每100
毫秒移动一次,每次移动都需要记录当前服务请求的次数。内存中需要保存10
次的次数。可以用数据结构LinkedList
来实现。格子每次移动的时候判断一次,当前访问次数和LinkedList
中最后一个相差是否超过100
,如果超过就需要限流了。很明显,当滑动窗口的格子划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越精确。
计数器的实现简单,但是是平均分配1秒钟的请求,然而实际情况中的请求往往是动态的,流量不平滑的。
漏桶
漏桶(
Leaky Bucket
)算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率。可见这里有两个变量,一个是桶的大小,支持流量突发增多时可以存多少的水(
burst
),另一个是水桶漏洞的大小(rate
)。因为漏桶的漏出速率是固定的参数,所以,即使网络中不存在资源冲突(没有发生拥塞),漏桶算法也不能使流突发(
burst
)到端口速率.因此,漏桶算法对于存在突发特性的流量来说缺乏效率.令牌桶
令牌桶算法(
Token Bucket
)和 Leaky Bucket 效果一样但方向相反的算法,更加容易理解.随着时间流逝,系统会按恒定1/QPS
时间间隔(如果QPS=100
,则间隔是10ms
)往桶里加入Token
(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token
,如果没有Token
可拿了就阻塞或者拒绝服务.令牌桶的另外一个好处是可以方便的改变速度. 一旦需要提高速率,则按需提高放入桶中的令牌的速率. 一般会定时(比如100毫秒)往桶中增加一定数量的令牌, 有些变种算法则实时的计算应该增加的令牌的数量.
基于Redis的令牌桶算法限流策略实现
策略
因为出现了某些客户突然加大流量的情况,为了避免抢占其他用户的资源,所以设计了基于用户(限制单个用户的最大请求数)的令牌桶策略。
JAVA 实现
/*** 获取令牌** @param key 令牌类别标识(每个用户不同)* @param permits 请求的令牌数量* @param currMillSecond 当前毫秒数* @return 是否能请求到令牌*/ public boolean acquire(String key, Integer permits, long currMillSecond) {try (Jedis jedis = JedisPoolUtil.getJedisPool().getResource()) {//针对新用户创建令牌桶if (!jedis.exists(key)) {jedis.hset(key, "last_mill_second", String.valueOf(currMillSecond));jedis.hset(key, "curr_permits", "0");jedis.hset(key, "max_permits", "500");jedis.hset(key, "rate", "400");return true;}//获取令牌桶信息,上一个令牌时间,当前可用令牌数,最大令牌数,令牌消耗速率List<String> limitInfo = jedis.hmget(key, "last_mill_second", "curr_permits", "max_permits", "rate");long lastMillSecond = Long.parseLong(limitInfo.get(0));Integer currPermits = Integer.valueOf(limitInfo.get(1));Integer maxPermits = Integer.valueOf(limitInfo.get(2));Double rate = Double.valueOf(limitInfo.get(3));//向桶里面添加令牌Double reversePermitsDouble = ((currMillSecond - lastMillSecond) / 1000) * rate;Integer reversePermits = reversePermitsDouble.intValue();Integer expectCurrPermits = reversePermits + currPermits;Integer localCurrPermits = Math.min(expectCurrPermits, maxPermits);//添加令牌之后更新时间if (reversePermits > 0) {jedis.hset(key, "last_mill_second", String.valueOf(currMillSecond));}//判断桶里面剩余的令牌数目if (localCurrPermits - permits >= 0) {jedis.hset(key, "curr_permits", String.valueOf(localCurrPermits - permits));return true;} else {jedis.hset(key, "curr_permits", String.valueOf(localCurrPermits));return false;}} catch (Exception e) {return false;} }
使用方式:
if (!rateLimiterService.acquire("limiter:" + uid, 1, System.currentTimeMillis())) {throw new BusinessException(ExceptionType.TOO_BUSY); }
设计一个基于用户的API限流策略 Rate Limit相关推荐
- 一个基于用户的API限流策略 Rate Limit
1. 限流场景 在开发高并发系统时,有很多种方法可用来保护系统:缓存.降级.限流等. 缓存:提升系统访问速度,增大系统处理能力 降级:服务出现问题或影响核心流程的性能时,需要暂时屏蔽,待高峰过去或问题 ...
- 基于用户的API限流策略
应用场景 API接口的流量控制策略:缓存.降级.限流.限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的.限流策略虽然降低了服务接口的访问频率和并发量,却换取服务接口和业 ...
- 算法高级(7)-限流(Rate limit)算法详解
一.前言 保障服务稳定的三大利器:熔断降级.服务限流和故障模拟.今天和大家谈谈限流算法的几种实现方式,本文所说的限流并非是Nginx层面的限流,而是业务代码中的逻辑限流. 那么为什么需要限流呢? 按照 ...
- Java互联网架构-如何设计服务接口API限流功能
API 概念的出现,远远早于个人计算机的诞生,更不用说网络的诞生了.在公用数据处理的早期,为了一个应用能够与其它系统交互,开发者便已开始设计可公开访问并描述清晰的"接入点".早在那 ...
- 秒杀限制人群,如何设计秒杀服务的限流策略?
对于秒杀业务,大家应该比较熟悉了.比如,"某商品原价 1299 元, 双十一整点秒杀价仅 500 元,限量 100 件,先到先得" 等等.通过这段文案我们能够发现,参与秒杀活动商品 ...
- 如何设计秒杀服务器的限流策略
如果平时系统的访问量只有一万,而最大承受限制为五万,在秒杀时刻的瞬间,访问量突然增加到100W,此事系统一定会因访问量过大而宕机,此时就应该设计一个限流策略,使服务器能接收和处理的请求减少. 秒杀限流 ...
- 服务接口API限流 Rate Limit
转载:https://www.cnblogs.com/exceptioneye/p/4783904.html https://blog.csdn.net/zrg523/article/details/ ...
- 【限流02】限流算法实战篇 - 手撸一个单机版Http接口通用限流框架
本文将从需求的背景.需求分析.框架设计.框架实现几个层面一步一步去实现一个单机版的Http接口通用限流框架. 一.限流框架分析 1.需求背景 微服务系统中,我们开发的接口可能会提供给很多不同的系统去调 ...
- 基于Redis的分布式限流详解
前言 Redis除了能用作缓存外,还有很多其他用途,比如分布式锁,分布式限流,分布式唯一主键等,本文将和大家分享下基于Redis分布式限流的各种实现方案. 一.为什么需要限流 用最简单的话来说:外部请 ...
最新文章
- idea直连linux部署项目,idea项目打包和在linux的部署
- DRP问题集结(一)-Tomcat无法启动,报错java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory...
- ubuntu权限管理
- 2021-01-07 matlab数值分析 常微分方程初边值问题数值解 标准龙格库塔四阶四段公式 欧拉法
- 科研神器推荐之那些年你用过的工具
- SH1B LMR62014XMFE/NOPB
- svn 版本控制操作命令
- mysql 比较一个字符串_比较MySQL中的两个字符串?
- BUUCTF Web [GXYCTF2019]Ping Ping Ping
- LeetCode93. 复原IP地址
- scrollview 中用listview的方法
- 记录一个Lock和sychronized应用及双检锁
- 《HTTP权威指南》读书笔记(1)-HTTP简介与消息结构
- Github客户端下载以及使用方法
- 基于Android的英文电子词典
- 花两个月吃透京东T8推荐的178页京东基础架构建设之路,入职定T5
- 中级软件设计师笔记全套 看完你就过啦
- AARRR模型——激活:获客红海背后的蓝海(上)
- [原创]QQ农场外挂辅助程序-小萝莉偷菜机器人,提供下载。
- 更愿意思念更早的“金陵”