最新要闻
- 索尼WF-1000XM4降噪豆发布新固件:可同时连接2台设备
- 全球报道:女子帮网友表白:单日收入过万
- 享36个月超长质保!魅族20系列1元超前预订开启:立省699元
- 《福星小子》新动画角色公开 3月2日最新话登场
- 身材抢眼!75岁“终结者”施瓦辛格首演电视剧:经典台词“我回来了”
- 要闻:全新起亚K3开启预售 新款起亚K3怎么样?
- 今热点:只要78元!《元能失控》登陆任天堂国行Switch:支持多人联机 太罕见
- 今日热闻!累计订单已超5万!比亚迪豪华MPV腾势D9 EV官宣涨价6000元
- 送女神绝佳好礼 好吃还能发圈!榴芒一刻礼盒大促:立减179元
- 环球速讯:恐怖!男子酒后吃布洛芬致皮肤大面积剥脱 医生:重度药疹
- 焦点滚动:另起炉灶?马斯克怒批ChatGPT 欲开发替代品
- 资讯:建设银行e路通不用了直接扔了吗_建设银行e路通
- 恐怕人类永远也搞不定真正的AI!
- 环球时讯:黄仁勋带着NVIDIA新品发布会来了!RTX 4070梦碎
- 大量年轻人成为“果粉” :苹果连三星大本营都快攻陷了
- 精选!AGM G2 Guardian发布:全球首款500米范围热成像手机
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
高并发场景下常见的限流算法及方案介绍
作者:京东科技 康志兴
应用场景
现代互联网很多业务场景,比如秒杀、下单、查询商品详情,最大特点就是高并发,而往往我们的系统不能承受这么大的流量,继而产生了很多的应对措施:CDN、消息队列、多级缓存、异地多活。
(资料图)
但是无论如何优化,终究由硬件的物理特性决定了我们系统性能的上限,如果强行接收所有请求,往往造成雪崩。
这时候限流熔断就发挥作用了,限制请求数,快速失败,保证系统满负载又不超限。
极致的优化,就是将硬件使用率提高到100%,但永远不会超过100%
常用限流算法
1. 计数器
直接计数,简单暴力,举个例子:
比如限流设定为1小时内10次,那么每次收到请求就计数加一,并判断这一小时内计数是否大于上限10,没超过上限就返回成功,否则返回失败。
这个算法的缺点就是在时间临界点会有较大瞬间流量。
继续上面的例子,理想状态下,请求匀速进入,系统匀速处理请求:
但实际情况中,请求往往不是匀速进入,假设第n小时59分59秒的时候突然进入10个请求,全部请求成功,到达下一个时间区间时刷新计数。那么第n+1小时刚开始又打进10个请求,等于瞬间进入20个请求,肯定不符合“1小时10次”的规则,这种现象叫做“突刺现象”。
为解决这个问题,计数器算法经过优化后,产生了滑动窗口算法:
我们将时间间隔均匀分隔,比如将一分钟分为6个10秒,每一个10秒内单独计数,总的数量限制为这6个10秒的总和,我们把这6个10秒成为“窗口”。
那么每过10秒,窗口往前滑动一步,数量限制变为新的6个10秒的总和,如图所示:
那么如果在临界时,收到10个请求(图中灰色格子),在下一个时间段来临时,橙色部分又进入10个请求,但窗口内包含灰色部分,所以已经到达请求上线,不再接收新的请求。
这就是滑动窗口算法。
但是滑动窗口仍然有缺陷,为了保证匀速,我们要划分尽可能多的格子,而格子越多,每一个格子能够接收的请求数就越少,这样就限制了系统瞬间处理能力。
2. 漏桶
漏桶算法其实也很简单,假设我们有一个固定容量的桶,流速(系统处理能力)固定,如果一段时间水龙头水流太大,水就溢出了(请求被抛弃了)。
用编程的语言来说,每次请求进来都放入一个先进先出的队列中,队列满了,则直接返回失败。另外有一个线程池固定间隔不断地从这个队列中拉取请求。
消息队列、jdk的线程池,都有类似的设计。
3. 令牌桶
令牌桶算法比漏桶算法稍显复杂。
首先,我们有一个固定容量的桶,桶里存放着令牌(token)。桶一开始是空的,token以一个固定的速率往桶里填充,直到达到桶的容量,多余的令牌将会被丢弃。每当一个请求过来时,就会尝试从桶里移除一个令牌,如果没有令牌的话,请求无法通过。
漏桶和令牌桶算法的区别:
漏桶的特点是消费能力固定,当请求量超出消费能力时,提供一定的冗余能力,把请求缓存下来匀速消费。优点是对下游保护更好。
令牌桶遇到激增流量会更从容,只要存在令牌,则可以一并消费掉。适合有突发特征的流量,如秒杀场景。
限流方案
一、容器限流
1. Tomcat
tomcat能够配置连接器的最大线程数属性,该属性maxThreads
是Tomcat的最大线程数,当请求的并发大于maxThreads
时,请求就会排队执行(排队数设置:accept-count),这样就完成了限流的目的。
2. Nginx
Nginx 提供了两种限流手段:一是控制速率,二是控制并发连接数。
控制速率
我们需要使用
limit_req_zone
配置来限制单位时间内的请求数,即速率限制,示例配置如下:limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;
第一个参数:$binary_remote_addr 表示通过remote_addr这个标识来做限制,“binary_”的目的是缩写内存占用量,是限制同一客户端ip地址。
第二个参数:zone=mylimit:10m表示生成一个大小为10M,名字为one的内存区域,用来存储访问的频次信息。
第三个参数:rate=2r/s表示允许相同标识的客户端的访问频次,这里限制的是每秒2次,还可以有比如30r/m的。
并发连接数
利用
limit_conn_zone
和limit_conn
两个指令即可控制并发数,示例配置如下limit_conn_zone $binary_remote_addr zone=perip:10m;limit_conn_zone $server_name zone=perserver:10m;server { ... limit_conn perip 10; # 限制同一个客户端ip limit_conn perserver 100;}
只有当 request header 被后端处理后,这个连接才进行计数
二、服务端限流
1. Semaphore
JUC包中提供的信号量工具,它的内部维护了一个同步队列,我们可以在每个请求进来的时候,尝试获取信号量,获取不到可以阻塞或者快速失败
简单样例:
Semaphore sp = new Semaphore(3);sp.require(); // 阻塞获取System.out.println("执行业务逻辑");sp.release();
2. RateLimiter
Guava中基于令牌桶实现的一个限流工具,使用非常简单,通过方法create()
创建一个桶,然后通过acquire()
或者tryAcquire()
获取令牌:
RateLimiter rateLimiter = RateLimiter.create(5); // 初始化令牌桶,每秒往桶里存放5个令牌rateLimiter.acquire(); // 自旋阻塞获取令牌,返回阻塞的时间,单位为秒rateLimiter.tryAcquire(); // 获取令牌,返回布尔结果,超过超时时间(默认为0,单位为毫秒)则返回失败
RateLimiter在实现时,允许暴增请求的突发情况存在。
举个例子,我们有一个速率为每秒5个令牌的RateLimiter:
当令牌桶空了的时候,如果继续获取一个令牌,那么会在下一次补充令牌的时候返回结果
但如果直接获取5个令牌,并不是等待桶内补齐5个令牌后再返回,而是仍旧会在令牌桶补充下一个令牌的时候直接返回,而预支令牌所需的补充时间会在下一次请求时进行补偿
public void testSmoothBursty() { RateLimiter r = RateLimiter.create(5); for (int i = 0; i++ < 2; ) { System.out.println("get 5 tokens: " + r.acquire(5) + "s"); System.out.println("get 1 tokens: " + r.acquire(1) + "s"); System.out.println("get 1 tokens: " + r.acquire(1) + "s"); System.out.println("get 1 tokens: " + r.acquire(1) + "s"); System.out.println("end"); }}/*** 控制台输出* get 5 tokens: 0.0s 初始化时桶是空的,直接从空桶获取5个令牌* get 1 tokens: 0.998068s 滞后效应,需要替前一个请求进行等待* get 1 tokens: 0.196288s* get 1 tokens: 0.200391s* end* get 5 tokens: 0.195756s* get 1 tokens: 0.995625s 滞后效应,需要替前一个请求进行等待* get 1 tokens: 0.194603s* get 1 tokens: 0.196866s* end*/
3. Hystrix
Netflix开源的熔断组件,支持两种资源隔离策略:THREAD(默认)或者SEMAPHORE
线程池:每个command运行在一个线程中,限流是通过线程池的大小来控制的
信号量:command是运行在调用线程中,但是通过信号量的容量来进行限流
线程池策略对每一个资源创建一个线程池以进行流量管控,优点是资源隔离彻底,缺点是容易造成资源碎片化。
使用样例:
// HelloWorldHystrixCommand要使用Hystrix功能 public class HelloWorldHystrixCommand extends HystrixCommand { private final String name; public HelloWorldHystrixCommand(String name) { super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")); this.name = name; } // 如果继承的是HystrixObservableCommand,要重写Observable construct() @Override protected String run() { return "Hello " + name; } }
调用该command:
String result = new HelloWorldHystrixCommand("HLX").execute();System.out.println(result); // 打印出Hello HLX
Hystrix已经在2018年停止开发,官方推荐替代项目Resilience4j
更多使用介绍可查看:Hystrix熔断器的使用
4. Sentinel
阿里开源的限流熔断组件,底层统计采用滑动窗口算法,限流方面有两种使用方式:API调用和注解,内部采插槽链来统计和执行校验规则。
通过为方法增加注解@SentinelResource(String name)
或者手动调用SphU.entry(String name)
方法开启流控。
使用API手动调用流控示例:
@Testpublic void testRule() { // 配置规则. initFlowRules(); int count = 0; while (true) { try (Entry entry = SphU.entry("HelloWorld")) { // 被保护的逻辑 System.out.println("run " + ++count + " times"); } catch (BlockException ex) { // 处理被流控的逻辑 System.out.println("blocked after " + count); break; } }}// 输出结果:// run 1 times// run 2 times// run 3 times
关于Sentinel的详细介绍可查看:Sentinel-分布式系统的流量哨兵
三、分布式下限流方案
线上环境下,如果对共用资源(如数据库、下游服务)做统一流量限制,那么单机限流显然不能满足,而需要分布式流控方案。
分布式限流主要采取中心系统流量管控的方案,由一个中心系统统一管控流量配额。
这种方案的缺点就是中心系统的可靠性,所以一般需要备用方案,在中心系统不可用时,退化为单机流控。
1. Tair通过incr方法实现简单窗口
实现方式是使用incr()
自增方法来计数并与阈值进行大小比较。
public boolean tryAcquire(String key) { // 以秒为单位构建tair的key String wrappedKey = wrapKey(key); // 每次请求+1,初始值为0,key的有效期设置5s Result result = tairManager.incr(NAMESPACE, wrappedKey, 1, 0, 5); return result.isSuccess() && result.getValue() <= threshold;}private String wrapKey(String key) { long sec = System.currentTimeMillis() / 1000L; return key + ":" + sec;}
【备注】incr方法的参数说明
// 方法定义:Result incr(int namespace, Serializable key, int value, int defaultValue, int expireTime)/* 参数含义:namespace - 申请时分配的 namespacekey - key 列表,不超过 1kvalue - 增加量defaultValue - 第一次调用 incr 时的 key 的 count 初始值,第一次返回的值为 defaultValue + value。expireTime - 数据过期时间,单位为秒,可设相对时间或绝对时间(Unix 时间戳)。*/
2. Redis通过lua脚本实现简单窗口
与Tair实现方式类似,不过redis的incr()
方法不能原子性的设置过期时间,所以需要使用lua脚本,在第一次调用返回1时,设置下过期时间为1秒。
local currentcurrent = redis.call("incr",KEYS[1])if tonumber(current) == 1 then redis.call("expire",KEYS[1],1)endreturn current
3. Redis通过lua脚本实现令牌桶
实现思路是获取令牌后,用SET记录“请求时间”和“剩余token数量”。
每次请求令牌时,通过这两个参数和请求的时间、流速等参数进行计算,返回是否获取令牌成功。
获取令牌lua脚本:
local ratelimit_info = redis.pcall("HMGET",KEYS[1],"last_time","current_token")local last_time = ratelimit_info[1]local current_token = tonumber(ratelimit_info[2])local max_token = tonumber(ARGV[1])local token_rate = tonumber(ARGV[2])local current_time = tonumber(ARGV[3])local reverse_time = 1000/token_rateif current_token == nil then current_token = max_token last_time = current_timeelse local past_time = current_time-last_time local reverse_token = math.floor(past_time/reverse_time) current_token = current_token+reverse_token last_time = reverse_time*reverse_token+last_time if current_token>max_token then current_token = max_token endendlocal result = 0if(current_token>0) then result = 1 current_token = current_token-1end redis.call("HMSET",KEYS[1],"last_time",last_time,"current_token",current_token)redis.call("pexpire",KEYS[1],math.ceil(reverse_time*(max_token-current_token)+(current_time-last_time)))return result
初始化令牌桶lua脚本:
local result=1redis.pcall("HMSET",KEYS[1],"last_mill_second",ARGV[1],"curr_permits",ARGV[2],"max_burst",ARGV[3],"rate",ARGV[4])return result
高并发场景下常见的限流算法及方案介绍
组合数学笔记-计数原理
索尼WF-1000XM4降噪豆发布新固件:可同时连接2台设备
全球报道:女子帮网友表白:单日收入过万
享36个月超长质保!魅族20系列1元超前预订开启:立省699元
《福星小子》新动画角色公开 3月2日最新话登场
身材抢眼!75岁“终结者”施瓦辛格首演电视剧:经典台词“我回来了”
记录--如何优雅地校验后端接口数据
世界今亮点!New Bing怼人、说谎、PUA,ChatGPT已经开始胡言乱语了
要闻:全新起亚K3开启预售 新款起亚K3怎么样?
今热点:只要78元!《元能失控》登陆任天堂国行Switch:支持多人联机 太罕见
今日热闻!累计订单已超5万!比亚迪豪华MPV腾势D9 EV官宣涨价6000元
送女神绝佳好礼 好吃还能发圈!榴芒一刻礼盒大促:立减179元
环球速讯:恐怖!男子酒后吃布洛芬致皮肤大面积剥脱 医生:重度药疹
焦点滚动:另起炉灶?马斯克怒批ChatGPT 欲开发替代品
全球播报:Rust 知识积累(1)
世界百事通!让WPF中的DataGrid像Excel一样可以筛选
全球头条:Codeforces Round #854 by cybercats (Div. 1+2) 1799 A~G 题解
全球报道:2363. 合并相似的物品
【天天速看料】c语言运算符优先级实例解析
资讯:建设银行e路通不用了直接扔了吗_建设银行e路通
恐怕人类永远也搞不定真正的AI!
环球时讯:黄仁勋带着NVIDIA新品发布会来了!RTX 4070梦碎
大量年轻人成为“果粉” :苹果连三星大本营都快攻陷了
精选!AGM G2 Guardian发布:全球首款500米范围热成像手机
全球时讯:不怕停电了?董明珠:格力开始研究将储能技术应用冰箱上
新消息丨.NET MAUI
外敷仙人掌的禁忌和副作用_外敷仙人掌的禁忌
环球热文:官宣定档3月6日 领创科技旗舰荣耀Magic5系列即将国内亮相
需要去看医生的呼噜声什么样?这三种情况要特别注意:有危险
蔚来:阿尔卑斯全系车型采用800V方案 还将共享使用三代换电站
【全球新视野】男子反复发烧20多天被诊出黑热病:发病率仅0.0108/10万
环球快报:一加Buds Pro 2轻享版上架:48dB深度降噪
今热点:11 款顶级 MySQL 图形化工具汇总,总有一款适合你!(建议收藏)
【速看料】Python实战项目3-前后端连接/首页轮播图表设计
热头条丨剑指 Offer 55 - II. 平衡二叉树(java解题)
焦点速讯:安装node并创建vue项目
报告称每天工作超8小时心脏病风险增8成:很多公司拒绝996、启用四天工作制
比亚迪专业个性化品牌曝光:首车性能对标奔驰大G 年内发布
苹果将成本转嫁给果粉!2024年iPad Pro要大涨价
LOL帧率近乎翻倍!Intel Arc A750新驱动测试:大幅提升、最大短板没有了
丰田有队友了!宝马氢燃料SUV将路试:16磅氢能跑500公里
世界速读:CSS中的BFC、IFC、GFC、FFC
环球即时:Synchronized,我要一层一层剥开你的心
全球视点!轻松玩转makefile|基础知识
环球聚焦:曝吴秀波儿子家暴成性,女方晒照满嘴是血,指证男方出轨乱约
周杰伦演唱会数百万人疯抢!演唱会门票30秒卖光
环球新资讯:长安发律师函控诉银河之光抄袭 吉利回应:毫无根据、误导公众
环球微速讯:【同步、共享和内容协作软件】上海道宁与ownCloud让您的团队随时随地在任何设备上轻松处理数据
全白外观拥有硬核实力!影驰Z790金属大师D5 Wi-Fi白金版主板评测:内存轻松提速10%
环球快讯:越来越多PC用户不愿买显卡了:2022年Q4桌面独显销量暴跌43%
世界第一次!中国空间站看到了在轨航天员的“三维皮肤”
【时快讯】89元 小米无线键鼠套装2上架:鼠标轻至45g
环球精选!运酒撞破酒缸1分钟损失5万!男子:一坛酒1000斤 1斤50块钱
天天快看点丨易基因|独家分享:高通量测序后的下游实验验证方法——DNA甲基化篇
IPO参考:联域光电拟深市主板IPO 郝氏控股二次递表港交所
【全球快播报】感冒的食疗偏方秘方_感冒的食疗偏方
8尺夫人面对面!《生化危机8 VR》IGN 8分 MTC用户9.7分
环球热点评!40多万的车没有语音控制功能!宝马遭X3车主集体投诉
今日聚焦!一加Ace 2V搭载旗舰级2.8D微弧玻璃:手感温润如玉
世界讯息:续航1整年!小米智能门锁M20大屏猫眼版开售:首发1899元
世界要闻:《艾尔登法环》原子之心机械姐妹花Mod 性感吸睛
自得其乐是什么意思?自得其乐的名人例子有哪些?
12%是零点几?12%公积金是什么档次?
给据邮件是什么意思?给据邮件如何填写?
男主角性格冰冷的小说有哪些?男主角性格冰冷的小说推荐
兔子能喝牛奶吗?兔子吃的食物有哪些?
小米手机屏幕校准在哪里?小米手机屏幕有多大?
集成显卡可以玩英雄联盟吗?集成显卡和独立显卡有什么区别?
华为mate9哪一年生产的?华为mate9参数配置
可视化图表之奥妙——百分比堆积条形图
看热讯:基于开源IM即时通讯框架MobileIMSDK:RainbowChat-iOS端v6.2版已发布
常用的xpath
环球观察:mybatis plus映射postgreSQL数组
世界资讯:redis实现用户查询次数限制
军用三防手机有哪些?军用三防手机推荐
苏泊尔电磁炉滴滴响不加热是什么原因?苏泊尔电磁炉滴滴响不加热怎么解决?
最新资讯:完美全面屏!努比亚Z50 Ultra官宣3月7日发布
新消息丨控告抄袭!长安给吉利发去律师函
【环球新要闻】BBA压力来了!李想:今年理想将挑战30-50万豪华SUV市场20%份额
环球快消息!SRC挖掘之Access验证校验的漏洞挖掘
【世界热闻】tomcat源码分析(一)如何启动服务
协同办公领域未来三大趋势(协同办公带来的机遇)
彻底理解 HashMap 及 LinkedHashMap,面试官请随便问!
当前焦点!轻量级CI/CD发布部署环境搭建及使用_02_docker安装jenkins
世界微速讯:理想汽车2022年亏损额创新高达20.32亿元
天天热议:腾势D9首创双枪充电 赵长江:比高压充电更节省社会成本
当前视讯!DXO排名全球第一!京东方认领荣耀Magic5/Pro屏幕
【全球播资讯】史诗级更新!雷军:小米12S Ultra 2倍变焦快捷按键正式上线
环球时讯:巧妙利用“慧言”机器人在安全场景中实践
每日消息!iOS封闭垄断 俄罗斯怒罚苹果9.06亿卢布:后者服软已悄悄支付
李想:比亚迪汽车毛利率20%左右 跟理想汽车很接近 良心
世界最新:梅西第七次当选世界足球先生 FIFA年度最佳球员!网友泪目:实至名归
全球消息!游戏第一神U上新!AMD锐龙9 7950X3D超频后更强:性能完秒13900KS
天天热点!40吨重 我国长征九号重型火箭未来将发射大型天文望远镜:探测地外生命
湖人官方:詹姆斯明日因右脚伤势缺战灰熊
全球热消息:世界第二大水电站16台机组全部通过验收:自主研制 登顶世界水电
全球观速讯丨增程是落后技术?李想:理想汽车单车型研发投入中国行业最高
环球今热点:10多天还没到 市民吐槽快递延误 客服:你投诉去吧
读Java性能权威指南(第2版)笔记04_ Java SE API技巧下