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

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

3天内不再提示

常用限流方式分析 怎么设计出高并发限流方案

电子工程师 来源:楼仔 作者:楼仔 2022-10-09 17:53 次阅读

来源:楼仔

常用限流方式

计数器

滑动窗口

漏桶

令牌桶

Redis + Lua 分布式限流

聊聊其它

限流对比

什么是限流呢?限流是限制到达系统的并发请求数量,保证系统能够正常响应部分用户请求,而对于超过限制的流量,则通过拒绝服务的方式保证整体系统的可用性。

根据限流作用范围,可以分为单机限流和分布式限流 ;根据限流方式,又分为计数器、滑动窗口、漏桶和令牌桶限流 ,下面我们对这块详细进行讲解。

常用限流方式

计数器

计数器是一种最简单限流算法,其原理就是:在一段时间间隔内,对请求进行计数,与阀值进行比较判断是否需要限流,一旦到了时间临界点,将计数器清零。

这个就像你去坐车一样,车厢规定了多少个位置,满了就不让上车了,不然就是超载了,被交警叔叔抓到了就要罚款的,如果我们的系统那就不是罚款的事情了,可能直接崩掉了。

程序执行逻辑:

可以在程序中设置一个变量 count,当过来一个请求我就将这个数 +1,同时记录请求时间。

当下一个请求来的时候判断 count 的计数值是否超过设定的频次,以及当前请求的时间和第一次请求时间是否在 1 分钟内。

如果在 1 分钟内并且超过设定的频次则证明请求过多,后面的请求就拒绝掉。

如果该请求与第一个请求的间隔时间大于计数周期,且 count 值还在限流范围内,就重置 count。

那么问题来了,如果有个需求对于某个接口 /query 每分钟最多允许访问 200 次,假设有个用户在第 59 秒的最后几毫秒瞬间发送 200 个请求,当 59 秒结束后 Counter 清零了,他在下一秒的时候又发送 200 个请求。

那么在 1 秒钟内这个用户发送了 2 倍的请求,这个是符合我们的设计逻辑的,这也是计数器方法的设计缺陷,系统可能会承受恶意用户的大量请求,甚至击穿系统。这种方法虽然简单,但也有个大问题就是没有很好的处理单位时间的边界。

ab27270e-46ae-11ed-96c9-dac502259ad0.png

不过说实话,这个计数引用了锁,在高并发场景,这个方式可能不太实用,我建议将锁去掉,然后将 l.count++ 的逻辑通过原子计数处理,这样就可以保证 l.count 自增时不会被多个线程同时执行,即通过原子计数的方式实现限流。

滑动窗口

滑动窗口是针对计数器存在的临界点缺陷,所谓滑动窗口(Sliding window)是一种流量控制威廉希尔官方网站 ,这个词出现在 TCP 协议中。滑动窗口把固定时间片进行划分,并且随着时间的流逝,进行移动,固定数量的可以移动的格子,进行计数并判断阀值。

ab4bea62-46ae-11ed-96c9-dac502259ad0.png

上图中我们用红色的虚线代表一个时间窗口(一分钟),每个时间窗口有 6 个格子,每个格子是 10 秒钟。每过 10 秒钟时间窗口向右移动一格,可以看红色箭头的方向。我们为每个格子都设置一个独立的计数器 Counter,假如一个请求在 0:45 访问了那么我们将第五个格子的计数器 +1(也是就是 0:40~0:50),在判断限流的时候需要把所有格子的计数加起来和设定的频次进行比较即可。

那么滑动窗口如何解决我们上面遇到的问题呢?来看下面的图:

ab5bfb96-46ae-11ed-96c9-dac502259ad0.png

当用户在 0:59 秒钟发送了 200 个请求就会被第六个格子的计数器记录 +200,当下一秒的时候时间窗口向右移动了一个,此时计数器已经记录了该用户发送的 200 个请求,所以再发送的话就会触发限流,则拒绝新的请求。

其实计数器就是滑动窗口啊,只不过只有一个格子而已,所以想让限流做的更精确只需要划分更多的格子就可以了,为了更精确我们也不知道到底该设置多少个格子,格子的数量影响着滑动窗口算法的精度,依然有时间片的概念,无法根本解决临界点问题。

漏桶

漏桶算法(Leaky Bucket),原理就是一个固定容量的漏桶,按照固定速率流出水滴。

用过水龙头都知道,打开龙头开关水就会流下滴到水桶里,而漏桶指的是水桶下面有个漏洞可以出水,如果水龙头开的特别大那么水流速就会过大,这样就可能导致水桶的水满了然后溢出。

abc2225e-46ae-11ed-96c9-dac502259ad0.png

一个固定容量的桶,有水流进来,也有水流出去。对于流进来的水来说,我们无法预计一共有多少水会流进来,也无法预计水流的速度。但是对于流出去的水来说,这个桶可以固定水流出的速率(处理速度),从而达到流量整形和流量控制的效果。

漏桶算法有以下特点:

漏桶具有固定容量,出水速率是固定常量(流出请求)

如果桶是空的,则不需流出水滴

可以以任意速率流入水滴到漏桶(流入请求)

如果流入水滴超出了桶的容量,则流入的水滴溢出(新请求被拒绝)

漏桶限制的是常量流出速率(即流出速率是一个固定常量值),所以最大的速率就是出水的速率,不能出现突发流量。

令牌桶

令牌桶算法(Token Bucket)是网络流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一种算法。典型情况下,令牌桶算法用来控制发送到网络上的数据的数目,并允许突发数据的发送。

abe49b2c-46ae-11ed-96c9-dac502259ad0.png

我们有一个固定的桶,桶里存放着令牌(token)。一开始桶是空的,系统按固定的时间(rate)往桶里添加令牌,直到桶里的令牌数满,多余的请求会被丢弃。当请求来的时候,从桶里移除一个令牌,如果桶是空的则拒绝请求或者阻塞。

令牌桶有以下特点:

令牌按固定的速率被放入令牌桶中

桶中最多存放 B 个令牌,当桶满时,新添加的令牌被丢弃或拒绝

如果桶中的令牌不足 N 个,则不会删除令牌,且请求将被限流(丢弃或阻塞等待)

令牌桶限制的是平均流入速率 (允许突发请求,只要有令牌就可以处理,支持一次拿3个令牌,4个令牌...),并允许一定程度突发流量,所以也是非常常用的限流算法。

Redis + Lua 分布式限流

单机版限流仅能保护自身节点,但无法保护应用依赖的各种服务,并且在进行节点扩容、缩容时也无法准确控制整个服务的请求限制。

而分布式限流,以集群为维度,可以方便的控制这个集群的请求限制,从而保护下游依赖的各种服务资源。

分布式限流最关键的是要将限流服务做成原子化 ,我们可以借助 Redis 的计数器,Lua 执行的原子性,进行分布式限流,大致的 Lua 脚本代码如下:

localkey="rate.limit:"..KEYS[1]--限流KEY

locallimit=tonumber(ARGV[1])--限流大小

localcurrent=tonumber(redis.call('get',key)or"0")

ifcurrent+1>limitthen--如果超出限流大小

return0

else--请求数+1,并设置1秒过期

redis.call("INCRBY",key,"1")

redis.call("expire",key,"1")

returncurrent+1

end

限流逻辑(Java 语言):

publicstaticbooleanaccquire()throwsIOException,URISyntaxException{

Jedisjedis=newJedis("127.0.0.1");

FileluaFile=newFile(RedisLimitRateWithLUA.class.getResource("/").toURI().getPath()+"limit.lua");

StringluaScript=FileUtils.readFileToString(luaFile);



Stringkey="ip:"+System.currentTimeMillis()/1000;//当前秒

Stringlimit="5";//最大限制

Listkeys=newArrayList();

keys.add(key);

Listargs=newArrayList();

args.add(limit);

Longresult=(Long)(jedis.eval(luaScript,keys,args));//执行lua脚本,传入参数

returnresult==1;

}

聊聊其它

上面的限流方式,主要是针对服务器进行限流,我们也可以对容器进行限流,比如 Tomcat、Nginx 等限流手段。

Tomcat 可以设置最大线程数(maxThreads),当并发超过最大线程数会排队等待执行;而 Nginx 提供了两种限流手段:一是控制速率,二是控制并发连接数。

对于 Java 语言,我们其实有相关的限流组件,比如大家常用的 RateLimiter,其实就是基于令牌桶算法 ,大家知道为什么唯独选用令牌桶么?

在实际的限流场景中,我们也可以控制单个 IP、城市、渠道、设备 id、用户 id 等在一定时间内发送的请求数;如果是开放平台,需要为每个 appkey 设置独立的访问速率规则。

限流对比

下面我们就对常用的线程策略,总结它们的优缺点,便于以后选型。

计数器:

优点:固定时间段计数,实现简单,适用不太精准的场景;

缺点:对边界没有很好处理,导致限流不能精准控制。

滑动窗口:

优点:将固定时间段分块,时间比“计数器”复杂,适用于稍微精准的场景;

缺点:实现稍微复杂,还是不能彻底解决“计数器”存在的边界问题。

漏桶:

优点:可以很好的控制消费频率;

缺点:实现稍微复杂,单位时间内,不能多消费,感觉不太灵活。

令牌桶:

优点:可以解决“漏桶”不能灵活消费的问题,又能避免过渡消费,强烈推荐

缺点:实现稍微复杂,其它缺点没有想到。

Redis + Lua 分布式限流:

优点:支持分布式限流,有效保护下游依赖的服务资源;

缺点:依赖 Redis,对边界没有很好处理,导致限流不能精准控制。

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

    关注

    23

    文章

    4606

    浏览量

    92778
  • 计数器
    +关注

    关注

    32

    文章

    2255

    浏览量

    94446
  • 限流
    +关注

    关注

    0

    文章

    34

    浏览量

    22520
  • Lua
    Lua
    +关注

    关注

    0

    文章

    80

    浏览量

    10556
  • Redis
    +关注

    关注

    0

    文章

    371

    浏览量

    10869

原文标题:没有10年的功力,根本不可能设计出这么好的高并发限流方案!

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

收藏 人收藏

    评论

    相关推荐

    常用限流工具RateLimiter

    今天我们继续看看Guava,其中比较常用限流工具RateLimiter Guava RateLimiter 有没有搞错,别人都在提升系统的访问并发量,你却在这搞限制? 我们都知道,服务器资源是有限
    的头像 发表于 09-25 15:03 2766次阅读
    <b class='flag-5'>常用</b>的<b class='flag-5'>限流</b>工具RateLimiter

    标准限流电路

    标准限流电路 图 标准限流电路 在简单串联稳
    发表于 07-20 15:50 1w次阅读
    标准<b class='flag-5'>限流</b>电路

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

    都是变阻器与“电表——待测电阻”系统之间的连接方式。分压是变相的并联,限流是串联。分压测量范围广,更常用限流可以保护元件,一般需要计算。所谓限流
    发表于 11-29 10:40 6.9w次阅读
    滑动变阻器<b class='flag-5'>限流</b>式与分压式的区别<b class='flag-5'>分析</b>

    混合型限流及开断威廉希尔官方网站 综述

    的应用前景。文章详细介绍了混合型限流断路器、混合型限流熔断器、混合型超导限流器和混合型液态金属限流器的工作原理及其发展现状,对不同的拓扑方案
    发表于 12-29 14:40 6次下载
    混合型<b class='flag-5'>限流</b>及开断威廉希尔官方网站
综述

    一种饱和铁心桥式故障限流

    的体积和成本;通过外加限流电感,有效提高了限流器的限流效果。首先分析饱和铁心型桥式故障限流器的工作原理,然后建立
    发表于 01-29 11:23 0次下载
    一种饱和铁心桥式故障<b class='flag-5'>限流</b>器

    限流器的作用_限流器的工作原理

    本文首先介绍了限流器的作用和特征,然后分析限流器的优缺点,最后粗略说明了限流器的工作原理并且从限流方式
    的头像 发表于 08-02 14:56 2.4w次阅读

    应对并发的手段之一自适应限流

    作为应对并发的手段之一,限流并不是一个新鲜的话题了。从Guava的Ratelimiter到Hystrix,以及Sentinel都可作为限流的工具。 Part1自适应
    的头像 发表于 05-27 15:52 2097次阅读
    应对<b class='flag-5'>高</b><b class='flag-5'>并发</b>的手段之一自适应<b class='flag-5'>限流</b>

    一文详解限流算法的实现方式

    不依赖外部库的情况下,限流算法有什么实现的思路?本文介绍了3种实现限流方式
    的头像 发表于 05-25 12:00 1405次阅读

    什么是限流,怎样使用限流

    所有输出电流都会流经限流电阻,它是一个放置在运算放大器反馈回路内的低欧姆值电阻。将限流电阻放置在反馈回路内十分必要,这样电压下降就不会在输出中显示为错误。
    的头像 发表于 11-30 11:06 4202次阅读

    Redis实现限流的三种方式分享

    当然,限流有许多种实现的方式,Redis具有很强大的功能,我用Redis实践了三种的实现方式,可以较为简单的实现其方式
    的头像 发表于 02-22 09:52 1064次阅读

    限流方案常用算法 常用限流方案

    需要注意的是借助Redis实现的限流方案可用于分布式系统,而guava实现的限流只能应用于单机环境。如果你觉得服务器端限流麻烦,可以在不改任何代码的情况下直接使用容器
    发表于 04-08 10:50 415次阅读

    限流电阻和分压电阻的区别

    限流电阻和分压电阻的区别  限流电阻和分压电阻是电路中常用的两种电阻,虽然它们都是电阻,但在实际应用中,两者存在较大的区别。本文将从定位、功能、应用等角度对限流电阻和分压电阻进行详尽、
    的头像 发表于 09-14 16:48 2660次阅读

    限流器是啥 常见的限流

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

    Redis实现分布式多规则限流方式介绍

    市面上很多介绍 Redis 如何实现限流的,但是大部分都有一个缺点,就是只能实现单一的限流,比如 1 分钟访问 1 次或者 60 分钟访问 10 次这种,但是如果想一个接口两种规则都需要满足呢,我们的项目又是分布式项目,应该如何解决,下面就介绍一下 Redis 实现分布式
    的头像 发表于 02-26 10:07 478次阅读
    Redis实现分布式多规则<b class='flag-5'>限流</b>的<b class='flag-5'>方式</b>介绍

    限流电阻怎么接入电路_限流电阻有正负极吗

    限流电阻的接入电路方式主要取决于具体的应用场景和电路要求。以下是一些常见的接入方法:   一、串联接入电路   基本串联方式:   将限流电阻直接串联在需要
    的头像 发表于 10-24 17:03 1061次阅读