0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

十分钟搞懂Java限流及常见方案

jf_ro2CN3Fa 来源:芋道源码 作者:芋道源码 2022-11-29 10:16 次阅读

限流基本概念

对一般的限流场景来说它具有两个维度的信息

时间 限流基于某段时间范围或者某个时间点,也就是我们常说的“时间窗口”,比如对每分钟、每秒钟的时间窗口做限定

资源 基于可用资源的限制,比如设定最大访问次数,或最高可用连接数

上面两个维度结合起来看,限流就是在某个时间窗口对资源访问做限制,比如设定每秒最多100个访问请求。但在真正的场景里,我们不止设置一种限流规则,而是会设置多个限流规则共同作用,主要的几种限流规则如下:

QPS和连接数控

对于连接数和QPS)限流来说,我们可设定IP维度的限流,也可以设置基于单个服务器的限流。

在真实环境中通常会设置多个维度的限流规则,比如设定同一个IP每秒访问频率小于10,连接数小于5,再设定每台机器QPS最高1000,连接数最大保持200。更进一步,我们可以把某个服务器组或整个机房的服务器当做一个整体,设置更high-level的限流规则,这些所有限流规则都会共同作用于流量控制。

传输速率

对于“传输速率”大家都不会陌生,比如资源的下载速度。有的网站在这方面的限流逻辑做的更细致,比如普通注册用户下载速度为100k/s,购买会员后是10M/s,这背后就是基于用户组或者用户标签的限流逻辑。

黑白名单

黑白名单是各个大型企业应用里很常见的限流和放行手段,而且黑白名单往往是动态变化的。举个例子,如果某个IP在一段时间的访问次数过于频繁,被系统识别为机器人用户或流量攻击,那么这个IP就会被加入到黑名单,从而限制其对系统资源的访问,这就是我们俗称的“封IP”。

我们平时见到的爬虫程序,比如说爬知乎上的美女图片,或者爬券商系统的股票分时信息,这类爬虫程序都必须实现更换IP的功能,以防被加入黑名单。

有时我们还会发现公司网络无法访问12306这类大型公共网站,这也是因为某些公司的出网IP是同一个地址,因此在访问量过高的情况下,这个IP地址就被对方系统识别,进而被添加到了黑名单。使用家庭宽带的同学们应该知道,大部分网络运营商都会将用户分配到不同出网IP段,或者时不时动态更换用户的IP地址。

白名单就更好理解了,相当于御赐金牌在身,可以自由穿梭在各种限流规则里,畅行无阻。比如某些电商公司会将超大卖家的账号加入白名单,因为这类卖家往往有自己的一套运维系统,需要对接公司的IT系统做大量的商品发布、补货等等操作。

分布式环境

分布式区别于单机限流的场景,它把整个分布式环境中所有服务器当做一个整体来考量。比如说针对IP的限流,我们限制了1个IP每秒最多10个访问,不管来自这个IP的请求落在了哪台机器上,只要是访问了集群中的服务节点,那么都会受到限流规则的制约。

我们最好将限流信息保存在一个“中心化”的组件上,这样它就可以获取到集群中所有机器的访问状态,目前有两个比较主流的限流方案:

网关层限流 将限流规则应用在所有流量的入口处

中间件限流 将限流信息存储在分布式环境中某个中间件里(比如Redis缓存),每个组件都可以从这里获取到当前时刻的流量统计,从而决定是拒绝服务还是放行流量

sentinel,springcloud生态圈为微服务量身打造的一款用于分布式限流、熔断降级等组件

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

项目地址:https://github.com/YunaiV/ruoyi-vue-pro

视频教程:https://doc.iocoder.cn/video/

限流方案常用算法

令牌桶算法

Token Bucket令牌桶算法是目前应用最为广泛的限流算法,顾名思义,它有以下两个关键角色:

令牌 获取到令牌的Request才会被处理,其他Requests要么排队要么被直接丢弃

桶 用来装令牌的地方,所有Request都从这个桶里面获取令牌 主要涉及到2个过程:

令牌生成

这个流程涉及到令牌生成器和令牌桶,前面我们提到过令牌桶是一个装令牌的地方,既然是个桶那么必然有一个容量,也就是说令牌桶所能容纳的令牌数量是一个固定的数值。

对于令牌生成器来说,它会根据一个预定的速率向桶中添加令牌,比如我们可以配置让它以每秒100个请求的速率发放令牌,或者每分钟50个。注意这里的发放速度是匀速,也就是说这50个令牌并非是在每个时间窗口刚开始的时候一次性发放,而是会在这个时间窗口内匀速发放。

在令牌发放器就是一个水龙头,假如在下面接水的桶子满了,那么自然这个水(令牌)就流到了外面。在令牌发放过程中也一样,令牌桶的容量是有限的,如果当前已经放满了额定容量的令牌,那么新来的令牌就会被丢弃掉。

令牌获取

每个访问请求到来后,必须获取到一个令牌才能执行后面的逻辑。假如令牌的数量少,而访问请求较多的情况下,一部分请求自然无法获取到令牌,那么这个时候我们可以设置一个“缓冲队列”来暂存这些多余的令牌。

缓冲队列其实是一个可选的选项,并不是所有应用了令牌桶算法的程序都会实现队列。当有缓存队列存在的情况下,那些暂时没有获取到令牌的请求将被放到这个队列中排队,直到新的令牌产生后,再从队列头部拿出一个请求来匹配令牌。

当队列已满的情况下,这部分访问请求将被丢弃。在实际应用中我们还可以给这个队列加一系列的特效,比如设置队列中请求的存活时间,或者将队列改造为PriorityQueue,根据某种优先级排序,而不是先进先出。

漏桶算法

Leaky Bucket,又是个桶,限流算法是跟桶杠上了,那么漏桶和令牌桶有什么不同呢,

漏桶算法的前半段和令牌桶类似,但是操作的对象不同,令牌桶是将令牌放入桶里,而漏桶是将访问请求的数据包放到桶里。同样的是,如果桶满了,那么后面新来的数据包将被丢弃。

漏桶算法的后半程是有鲜明特色的,它永远只会以一个恒定的速率将数据包从桶内流出。打个比方,如果我设置了漏桶可以存放100个数据包,然后流出速度是1s一个,那么不管数据包以什么速率流入桶里,也不管桶里有多少数据包,漏桶能保证这些数据包永远以1s一个的恒定速度被处理。

漏桶 vs 令牌桶的区别

根据它们各自的特点不难看出来,这两种算法都有一个“恒定”的速率和“不定”的速率。令牌桶是以恒定速率创建令牌,但是访问请求获取令牌的速率“不定”,反正有多少令牌发多少,令牌没了就干等。而漏桶是以“恒定”的速率处理请求,但是这些请求流入桶的速率是“不定”的。

从这两个特点来说,漏桶的天然特性决定了它不会发生突发流量,就算每秒1000个请求到来,那么它对后台服务输出的访问速率永远恒定。而令牌桶则不同,其特性可以“预存”一定量的令牌,因此在应对突发流量的时候可以在短时间消耗所有令牌,其突发流量处理效率会比漏桶高,但是导向后台系统的压力也会相应增多。

滑动窗口

比如说,我们在每一秒内有5个用户访问,第5秒内有10个用户访问,那么在0到5秒这个时间窗口内访问量就是15。如果我们的接口设置了时间窗口内访问上限是20,那么当时间到第六秒的时候,这个时间窗口内的计数总和就变成了10,因为1秒的格子已经退出了时间窗口,因此在第六秒内可以接收的访问量就是20-10=10个。

滑动窗口其实也是一种计算器算法,它有一个显著特点,当时间窗口的跨度越长时,限流效果就越平滑。打个比方,如果当前时间窗口只有两秒,而访问请求全部集中在第一秒的时候,当时间向后滑动一秒后,当前窗口的计数量将发生较大的变化,拉长时间窗口可以降低这种情况的发生概率

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

项目地址:https://github.com/YunaiV/yudao-cloud

视频教程:https://doc.iocoder.cn/video/

常用的限流方案

合法性验证限流

比如验证码、IP 黑名单等,这些手段可以有效的防止恶意攻击和爬虫采集;

Guawa限流

在限流领域中,Guava在其多线程模块下提供了以RateLimiter为首的几个限流支持类,但是作用范围仅限于“当前”这台服务器,也就是说Guawa的限流是单机的限流,跨了机器或者jvm进程就无能为力了 比如说,目前我有2台服务器[Server 1,Server 2],这两台服务器都部署了一个登陆服务,假如我希望对这两台机器的流量进行控制,比如将两台机器的访问量总和控制在每秒20以内,如果用Guava来做,只能独立控制每台机器的访问量<=10。

尽管Guava不是面对分布式系统的解决方案,但是其作为一个简单轻量级的客户端限流组件,非常适合来讲解限流算法

网关层限流

服务网关,作为整个分布式链路中的第一道关卡,承接了所有用户来访请求,因此在网关层面进行限流是一个很好的切入点 上到下的路径依次是:

用户流量从网关层转发到后台服务

后台服务承接流量,调用缓存获取数据

缓存中无数据,则访问数据库

流量自上而下是逐层递减的,在网关层聚集了最多最密集的用户访问请求,其次是后台服务。

然后经过后台服务的验证逻辑之后,刷掉了一部分错误请求,剩下的请求落在缓存上,如果缓存中没有数据才会请求漏斗最下方的数据库,因此数据库层面请求数量最小(相比较其他组件来说数据库往往是并发量能力最差的一环,阿里系的MySQL即便经过了大量改造,单机并发量也无法和Redis、Kafka之类的组件相比)

目前主流的网关层有以软件为代表的Nginx,还有Spring Cloud中的Gateway和Zuul这类网关层组件

Nginx限流

在系统架构中,Nginx的代理与路由转发是其作为网关层的一个很重要的功能,由于Nginx天生的轻量级和优秀的设计,让它成为众多公司的首选,Nginx从网关这一层面考虑,可以作为最前置的网关,抵挡大部分的网络流量,因此使用Nginx进行限流也是一个很好的选择,在Nginx中,也提供了常用的基于限流相关的策略配置.

Nginx 提供了两种限流方法:一种是控制速率,另一种是控制并发连接数。

控制速率

我们需要使用 limit_req_zone 用来限制单位时间内的请求数,即速率限制,

因为Nginx的限流统计是基于毫秒的,我们设置的速度是 2r/s,转换一下就是500毫秒内单个IP只允许通过1个请求,从501ms开始才允许通过第2个请求。

控制速率优化版

上面的速率控制虽然很精准但是在生产环境未免太苛刻了,实际情况下我们应该控制一个IP单位总时间内的总访问次数,而不是像上面那样精确到毫秒,我们可以使用 burst 关键字开启此设置

burst=4意思是每个IP最多允许4个突发请求

控制并发数

利用 limit_conn_zone 和 limit_conn 两个指令即可控制并发数

其中 limit_conn perip 10 表示限制单个 IP 同时最多能持有 10 个连接;limit_conn perserver 100 表示 server 同时能处理并发连接的总数为 100 个。

注意:只有当 request header 被后端处理后,这个连接才进行计数。

中间件限流

对于分布式环境来说,无非是需要一个类似中心节点的地方存储限流数据。打个比方,如果我希望控制接口的访问速率为每秒100个请求,那么我就需要将当前1s内已经接收到的请求的数量保存在某个地方,并且可以让集群环境中所有节点都能访问。那我们可以用什么技术来存储这个临时数据呢?

那么想必大家都能想到,必然是redis了,利用Redis过期时间特性,我们可以轻松设置限流的时间跨度(比如每秒10个请求,或者每10秒10个请求)。同时Redis还有一个特殊技能–脚本编程,我们可以将限流逻辑编写成一段脚本植入到Redis中,这样就将限流的重任从服务层完全剥离出来,同时Redis强大的并发量特性以及高可用集群架构也可以很好的支持庞大集群的限流访问。【reids + lua】

限流组件

除了上面介绍的几种方式以外,目前也有一些开源组件提供了类似的功能,比如Sentinel就是一个不错的选择。Sentinel是阿里出品的开源组件,并且包含在了Spring Cloud Alibaba组件库中,Sentinel提供了相当丰富的用于限流的API以及可视化管控台,可以很方便的帮助我们对限流进行治理

从架构维度考虑限流设计

在真实的项目里,不会只使用一种限流手段,往往是几种方式互相搭配使用,让限流策略有一种层次感,达到资源的最大使用率。在这个过程中,限流策略的设计也可以参考前面提到的漏斗模型,上宽下紧,漏斗不同部位的限流方案设计要尽量关注当前组件的高可用。

以我参与的实际项目为例,比如说我们研发了一个商品详情页的接口,通过手机淘宝导流,app端的访问请求首先会经过阿里的mtop网关,在网关层我们的限流会做的比较宽松,等到请求通过网关抵达后台的商品详情页服务之后,再利用一系列的中间件+限流组件,对服务进行更加细致的限流控制

具体的实现限流的手段

1)Tomcat 使用 maxThreads来实现限流。

2)Nginx的limit_req_zone和 burst来实现速率限流。

3)Nginx的limit_conn_zone和 limit_conn两个指令控制并发连接的总数。

4)时间窗口算法借助 Redis的有序集合可以实现。

5)漏桶算法可以使用Redis-Cell来实现。

6)令牌算法可以解决Google的guava包来实现。

需要注意的是借助Redis实现的限流方案可用于分布式系统,而guava实现的限流只能应用于单机环境。如果你觉得服务器端限流麻烦,可以在不改任何代码的情况下直接使用容器限流(Nginx或Tomcat),但前提是能满足项目中的业务需求。

Tomcat限流

Tomcat 8.5 版本的最大线程数在 conf/server.xml 配置中,maxThreads 就是 Tomcat 的最大线程数,当请求的并发大于此值(maxThreads)时,请求就会排队执行,这样就完成了限流的目的。

注意:

maxThreads 的值可以适当的调大一些,Tomcat默认为 150(Tomcat 版本 8.5),但这个值也不是越大越好,要看具体的服务器配置,需要注意的是每开启一个线程需要耗用 1MB 的 JVM 内存空间用于作为线程栈之用,并且线程越多 GC 的负担也越重。

最后需要注意一下,操作系统对于进程中的线程数有一定的限制,Windows 每个进程中的线程数不允许超过 2000,Linux 每个进程中的线程数不允许超过 1000。

审核编辑 :李倩

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 服务器
    +关注

    关注

    12

    文章

    9109

    浏览量

    85310
  • JAVA
    +关注

    关注

    19

    文章

    2964

    浏览量

    104689
  • 线程
    +关注

    关注

    0

    文章

    504

    浏览量

    19674

原文标题:十分钟搞懂Java限流及常见方案

文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    INA122U如何让上电就能在短时间让ADC采集值趋于稳定?

    如图1所示电路,仪表放大器输出通过RC接单片机ADC口,对于传感器零点或某定点,单片机ADC口采集上电时AD值上升,达到某值后稳定,波形类似图2,但此过程时间较长,约在十分钟左右,方能趋于稳定
    发表于 09-11 08:17

    十分钟入门基础Go Java小子版

    语法与 C 相近,但功能上有:内存安全,GC,结构形态及 CSP-style 并发计算。 适用范围 本篇文章适用于学习过其他面向对象语言(Java、Php),但没有学过Go语言的初学者。文章 主要从Go
    的头像 发表于 08-12 14:32 716次阅读
    三<b class='flag-5'>十分钟</b>入门基础Go <b class='flag-5'>Java</b>小子版

    滑动变阻器限流压式接法区别

    滑动变阻器是一种常见的电子元件,用于调节电路中的电阻值。在实际应用中,滑动变阻器的接法主要有两种:限流式和压式。这两种接法在电路设计和应用中有着不同的优缺点和适用范围。 一、限流式接
    的头像 发表于 08-05 14:37 2939次阅读

    限流式滑动变阻器与压式滑动变阻器的区别

    限流式滑动变阻器与压式滑动变阻器是两种常见的电子元件,它们在电路中起到调节电阻值的作用。尽管它们的基本功能相似,但在设计、工作原理、应用场景等方面存在一些差异。 一、结构差异 限流
    的头像 发表于 08-05 14:32 1212次阅读

    安徽合肥启动全省首条无人机医疗物资飞行航线

    据了解,此次无人机航线由迅蚁科技独家运营,能在短短几分钟内完成原本需数十分钟车程的任务,保障急需医疗用品的迅速到达,降低患者长时间等待的风险。
    的头像 发表于 05-17 14:27 302次阅读

    stm8l051 RTC LSI作为实时时钟不准怎么校准?

    (CLK_RTCCLKSource_LSI, CLK_RTCCLKDiv_1); CLK_PeripheralClockConfig(CLK_Peripheral_RTC, ENABLE); 现在以LSI作为实时时钟,十分钟内快了2分钟,分频2后右边慢了 请问大神么 这个
    发表于 04-30 07:13

    STM32CubeIDE编译就卡住是什么原因导致的?

    安装后就创建stm的项目, 在CubeMX里随便加了IO, 使能了uart, 之后就产生Code, 啥也没改过, 先编译看一下速度 结果就一直卡在18%, 等了差不多十分钟。 有碰到类似问题的吗? 是什么问题?
    发表于 04-19 07:08

    用stm32cubemx的串口中断接收时,过一段时间串口中断不进了怎么解决?

    我用stm32cubemx建的工程本来跑的挺好的,最近发现有bug。 我用uart1 在TIM3里边 1s定时发送数据,采用问答式通讯,对端收到了之后发送8个字节的应答。问题是跑了几十分钟之后或者一
    发表于 04-17 06:48

    限流器是啥 常见限流

    限流器通常会根据特定条件对电流进行调整。当电流超过设定的阈值时,限流器将引入额外的电阻或其他形式的阻抗,以限制电流的流动。
    的头像 发表于 02-06 13:51 3631次阅读

    无功补偿的原理、作用及常见方

    无功补偿的原理、作用及常见方式  无功补偿是电力系统中的一项重要技术措施,用于改善电力质量和提高能源利用效率。本文将详细介绍无功补偿的原理、作用以及常见的补偿方式。 一、无功补偿的原理 无功功率
    的头像 发表于 01-19 14:19 8888次阅读

    压与限流的选取原则

    压与限流是电子元器件中常见的两种保护措施。压是指通过合理的电阻网络将电压分为多个部分,以降低电压到合适的范围;而限流则是通过设置电流限制
    的头像 发表于 01-10 14:29 5523次阅读

    锂电池回收企业间的竞争变得十分激烈

    2023年随着锂盐价格大幅下跌及锂电池回收行业的产能大幅度增长,锂电池回收企业间的竞争变得十分激烈。
    的头像 发表于 12-29 10:26 1450次阅读
    锂电池回收企业间的竞争变得<b class='flag-5'>十分</b>激烈

    压式接法和限流式接法区别

    压式接法和限流式接法区别 压式接法和限流式接法是电路中常用的两种接法方式。它们在应用领域、工作原理以及在实际电路中的应用等方面存在一定的区别。下面将详尽、详实、细致地介绍这两种接法
    的头像 发表于 12-27 11:28 3037次阅读

    压器和限流器的区别

    压器和限流器的区别 压器和限流器是电子电路中常用的两种元件,它们具有不同的作用和原理。在电子元件和电路设计中,正确理解和合理使用这两种元件是非常重要的。 一、
    的头像 发表于 12-20 15:35 1195次阅读