范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

一文详解四种经典限流算法,面试必备

  前言
  最近一位朋友去拼夕夕面试,被问了这么一道题:限流算法有哪些?用代码实现令牌桶算法。跟好友讨论了一波,发现大家都忘记得差不多了.所以再整理一波,常见的四种限流算法,以及简单代码实现,相信大家看完,会茅塞顿开的。
  1. 固定窗口限流算法1.1 什么是固定窗口限流算法
  固定窗口限流算法(Fixed Window Rate Limiting Algorithm)是一种最简单的限流算法,其原理是在固定时间窗口(单位时间)内限制请求的数量。该算法将时间分成固定的窗口,并在每个窗口内限制请求的数量。具体来说,算法将请求按照时间顺序放入时间窗口中,并计算该时间窗口内的请求数量,如果请求数量超出了限制,则拒绝该请求。
  假设单位时间(固定时间窗口)是1秒,限流阀值为3。在单位时间1秒内,每来一个请求,计数器就加1,如果计数器累加的次数超过限流阀值3,后续的请求全部拒绝。等到1s结束后,计数器清0,重新开始计数。如下图:
  1.2 固定窗口限流的伪代码实现   public static Integer counter = 0;  //统计请求数    public static long lastAcquireTime =  0L;    public static final Long windowUnit = 1000L ; //假设固定时间窗口是1000ms    public static final Integer threshold = 10; // 窗口阀值是10         /**      * 固定窗口时间算法      * 关注公众号:捡田螺的小男孩      * @return      */     public synchronized boolean fixedWindowsTryAcquire() {         long currentTime = System.currentTimeMillis();  //获取系统当前时间         if (currentTime - lastAcquireTime > windowUnit) {  //检查是否在时间窗口内             counter = 0;  // 计数器清0             lastAcquireTime = currentTime;  //开启新的时间窗口         }         if (counter < threshold) {  // 小于阀值             counter++;  //计数统计器加1             return true;         }          return false;     } 复制代码1.2 固定窗口算法的优缺点优点:固定窗口算法非常简单,易于实现和理解。缺点:存在明显的临界问题,比如: 假设限流阀值为5个请求,单位时间窗口是1s,如果我们在单位时间内的前0.8-1s和1-1.2s,分别并发5个请求。虽然都没有超过阀值,但是如果算0.8-1.2s,则并发数高达10,已经超过单位时间1s不超过5阀值的定义啦。
  2. 滑动窗口限流算法2.1 什么是滑动窗口限流算法
  滑动窗口限流算法是一种常用的限流算法,用于控制系统对外提供服务的速率,防止系统被过多的请求压垮。它将单位时间周期分为n个小周期,分别记录每个小周期内接口的访问次数,并且根据时间滑动删除过期的小周期。它可以解决固定窗口临界值的问题。
  用一张图解释滑动窗口算法,如下:
  假设单位时间还是1s,滑动窗口算法把它划分为5个小周期,也就是滑动窗口(单位时间)被划分为5个小格子。每格表示0.2s。每过0.2s,时间窗口就会往右滑动一格。然后呢,每个小周期,都有自己独立的计数器,如果请求是0.83s到达的,0.8~1.0s对应的计数器就会加1。
  我们来看下,滑动窗口,去解决固定窗口限流算法的临界问题,思想是怎样
  假设我们1s内的限流阀值还是5个请求,0.8~1.0s内(比如0.9s的时候)来了5个请求,落在黄色格子里。时间过了1.0s这个点之后,又来5个请求,落在紫色格子里。如果是固定窗口算法,是不会被限流的,但是滑动窗口的话,每过一个小周期,它会右移一个小格。过了1.0s这个点后,会右移一小格,当前的单位时间段是0.2~1.2s,这个区域的请求已经超过限定的5了,已触发限流啦,实际上,紫色格子的请求都被拒绝啦。
  当滑动窗口的格子周期划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越精确。2.2 滑动窗口限流算法的伪代码实现 /**      * 单位时间划分的小周期(单位时间是1分钟,10s一个小格子窗口,一共6个格子)      */     private int SUB_CYCLE = 10;      /**      * 每分钟限流请求数      */     private int thresholdPerMin = 100;      /**      * 计数器, k-为当前窗口的开始时间值秒,value为当前窗口的计数      */     private final TreeMap counters = new TreeMap<>();     /**      * 滑动窗口时间算法实现      */      public synchronized boolean slidingWindowsTryAcquire() {         long currentWindowTime = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) / SUB_CYCLE * SUB_CYCLE; //获取当前时间在哪个小周期窗口         int currentWindowNum = countCurrentWindow(currentWindowTime); //当前窗口总请求数          //超过阀值限流         if (currentWindowNum >= thresholdPerMin) {             return false;         }          //计数器+1         counters.get(currentWindowTime)++;         return true;     }     /**     * 统计当前窗口的请求数     */     private synchronized int countCurrentWindow(long currentWindowTime) {         //计算窗口开始位置         long startTime = currentWindowTime - SUB_CYCLE* (60s/SUB_CYCLE-1);         int count = 0;          //遍历存储的计数器         Iterator> iterator = counters.entrySet().iterator();         while (iterator.hasNext()) {             Map.Entry entry = iterator.next();             // 删除无效过期的子窗口计数器             if (entry.getKey() < startTime) {                 iterator.remove();             } else {                 //累加当前窗口的所有计数器之和                 count =count + entry.getValue();             }         }         return count;     } 复制代码2.3 滑动窗口限流算法的优缺点
  优点:简单易懂精度高(通过调整时间窗口的大小来实现不同的限流效果)可扩展性强(可以非常容易地与其他限流算法结合使用)
  缺点:突发流量无法处理(无法应对短时间内的大量请求,但是一旦到达限流后,请求都会直接暴力被拒绝。酱紫我们会损失一部分请求,这其实对于产品来说,并不太友好),需要合理调整时间窗口大小。3. 漏桶限流算法3.1 什么是漏桶限流算法
  漏桶限流算法(Leaky Bucket Algorithm)是一种流量控制算法,用于控制流入网络的数据速率,以防止网络拥塞。它的思想是将数据包看作是水滴,漏桶看作是一个固定容量的水桶,数据包像水滴一样从桶的顶部流入桶中,并通过桶底的一个小孔以一定的速度流出,从而限制了数据包的流量。
  漏桶限流算法的基本工作原理是:对于每个到来的数据包,都将其加入到漏桶中,并检查漏桶中当前的水量是否超过了漏桶的容量。如果超过了容量,就将多余的数据包丢弃。如果漏桶中还有水,就以一定的速率从桶底输出数据包,保证输出的速率不超过预设的速率,从而达到限流的目的。
  流入的水滴,可以看作是访问系统的请求,这个流入速率是不确定的。桶的容量一般表示系统所能处理的请求数。如果桶的容量满了,就达到限流的阀值,就会丢弃水滴(拒绝请求)流出的水滴,是恒定过滤的,对应服务按照固定的速率处理请求。3.2 漏桶限流算法的伪代码实现 /**  * LeakyBucket 类表示一个漏桶,  * 包含了桶的容量和漏桶出水速率等参数,  * 以及当前桶中的水量和上次漏水时间戳等状态。  */ public class LeakyBucket {     private final long capacity;    // 桶的容量     private final long rate;        // 漏桶出水速率     private long water;             // 当前桶中的水量     private long lastLeakTimestamp; // 上次漏水时间戳      public LeakyBucket(long capacity, long rate) {         this.capacity = capacity;         this.rate = rate;         this.water = 0;         this.lastLeakTimestamp = System.currentTimeMillis();     }      /**      * tryConsume() 方法用于尝试向桶中放入一定量的水,如果桶中还有足够的空间,则返回 true,否则返回 false。      * @param waterRequested      * @return      */     public synchronized boolean tryConsume(long waterRequested) {         leak();         if (water + waterRequested <= capacity) {             water += waterRequested;             return true;         } else {             return false;         }     }      /**      * 。leak() 方法用于漏水,根据当前时间和上次漏水时间戳计算出应该漏出的水量,然后更新桶中的水量和漏水时间戳等状态。      */     private void leak() {         long now = System.currentTimeMillis();         long elapsedTime = now - lastLeakTimestamp;         long leakedWater = elapsedTime * rate / 1000;         if (leakedWater > 0) {             water = Math.max(0, water - leakedWater);             lastLeakTimestamp = now;         }     } }  复制代码注意: tryConsume() 和 leak() 方法中,都需要对桶的状态进行同步,以保证线程安全性。3.3 漏桶限流算法的优缺点
  优点可以平滑限制请求的处理速度,避免瞬间请求过多导致系统崩溃或者雪崩。可以控制请求的处理速度,使得系统可以适应不同的流量需求,避免过载或者过度闲置。可以通过调整桶的大小和漏出速率来满足不同的限流需求,可以灵活地适应不同的场景。
  缺点需要对请求进行缓存,会增加服务器的内存消耗。对于流量波动比较大的场景,需要较为灵活的参数配置才能达到较好的效果。但是面对突发流量的时候,漏桶算法还是循规蹈矩地处理请求,这不是我们想看到的啦。流量变突发时,我们肯定希望系统尽量快点处理请求,提升用户体验嘛。4. 令牌桶算法4.1 什么是令牌桶算法
  令牌桶算法是一种常用的限流算法,可以用于限制单位时间内请求的数量。该算法维护一个固定容量的令牌桶,每秒钟会向令牌桶中放入一定数量的令牌。当有请求到来时,如果令牌桶中有足够的令牌,则请求被允许通过并从令牌桶中消耗一个令牌,否则请求被拒绝。
  4.2 令牌桶算法的伪代码实现/**  * TokenBucket 类表示一个令牌桶  */ public class TokenBucket {      private final int capacity;     // 令牌桶容量     private final int rate;         // 令牌生成速率,单位:令牌/秒     private int tokens;             // 当前令牌数量     private long lastRefillTimestamp;  // 上次令牌生成时间戳      /**      * 构造函数中传入令牌桶的容量和令牌生成速率。      * @param capacity      * @param rate      */     public TokenBucket(int capacity, int rate) {         this.capacity = capacity;         this.rate = rate;         this.tokens = capacity;         this.lastRefillTimestamp = System.currentTimeMillis();     }      /**      * allowRequest() 方法表示一个请求是否允许通过,该方法使用 synchronized 关键字进行同步,以保证线程安全。      * @return      */     public synchronized boolean allowRequest() {         refill();         if (tokens > 0) {             tokens--;             return true;         } else {             return false;         }     }      /**      * refill() 方法用于生成令牌,其中计算令牌数量的逻辑是按照令牌生成速率每秒钟生成一定数量的令牌,      * tokens 变量表示当前令牌数量,      * lastRefillTimestamp 变量表示上次令牌生成的时间戳。      */     private void refill() {         long now = System.currentTimeMillis();         if (now > lastRefillTimestamp) {             int generatedTokens = (int) ((now - lastRefillTimestamp) / 1000 * rate);             tokens = Math.min(tokens + generatedTokens, capacity);             lastRefillTimestamp = now;         }     } } 复制代码4.3 令牌桶算法的优缺点
  优点:稳定性高:令牌桶算法可以控制请求的处理速度,可以使系统的负载变得稳定。精度高:令牌桶算法可以根据实际情况动态调整生成令牌的速率,可以实现较高精度的限流。弹性好:令牌桶算法可以处理突发流量,可以在短时间内提供更多的处理能力,以处理突发流量。
  Guava的RateLimiter限流组件,就是基于令牌桶算法实现的。
  缺点:实现复杂:相对于固定窗口算法等其他限流算法,令牌桶算法的实现较为复杂。 对短时请求难以处理:在短时间内有大量请求到来时,可能会导致令牌桶中的令牌被快速消耗完,从而限流。这种情况下,可以考虑使用漏桶算法。时间精度要求高:令牌桶算法需要在固定的时间间隔内生成令牌,因此要求时间精度较高,如果系统时间不准确,可能会导致限流效果不理想。
  总体来说,令牌桶算法具有较高的稳定性和精度,但实现相对复杂,适用于对稳定性和精度要求较高的场景。

地球自转速度加快,造成了近代历史上最短的一天有理论认为,钱德勒摆动可能是地球自转加速的原因,这可能导致有史以来第一个负闰秒。你有没有觉得日子过得很快?最近的研究表明,这种观点在科学上是正确的。有新的证据表明,地球正在以更快的老酒鬼挚爱的四款白酒,口感一流不上头1董酒国密(董香)680元500ml品质上乘,酒香饱满,醇厚甘洌,饮之干爽味长,一柱琼浆激起千层泡2华世福(酱香)288500ml醇香优雅,不浓不猛,回香悠长,口感比肩飞天,不辣口北石新作一念起,万水千山旅行关乎年轻人的梦想与成长中国青年报客户端讯(中青报中青网记者蒋肖斌)环球旅行达人北石最新作品一念起,万水千山,近日由东方出版社出版。2019年,北石获得中国当代徐霞客的称号,而他的故事,要从2014年讲起夏天多给孩子做这个,营养丰富,开胃安神,孩子长个快精神好夏天多给孩子做这个,营养丰富,开胃安神,孩子长个快精神好。南瓜的营养价值众所周知,胡萝卜素蛋白质以及维生素含量都比较高,营养价值杠杠的,而且还特别容易消化哟!当然咯,最主要的是南瓜七个健康生活习惯,让你拥有健康的明天现代人生活水平日益提高,人们对自己的健康问题也愈发关注,生活中,保持良好的生活习惯,才能拥有健康的明天。以下七个健康生活习惯,希望你能保持!1hr营养均衡的早餐一顿营养的早餐,让人核酸和它的兄弟们,正在开启去泡沫疫情之下,各行业均受到了不同程度的影响,但核酸检测却是例外,这是一个彻底被疫情所激活的行业。2019年之前,很少有人听说过核酸检测这个名词,相关上市公司在资本市场中的表现也很难让投高血压,正在吃硝苯地平,医生提醒那最好别吃这些进入21世纪后,大家的生活或多或少都有一些提升,而且医疗技术的进步可以更好的帮助我们解决身体上的病痛,最能体现这一点的就是人均寿命相较于以前更高了。但高年龄也意味着高风险,抵抗力下同内存相差800元!一加AcePro和iQOO10有什么区别?哪款性价比高手机这种数码产品,价格有时候是非常干预选择的。一加AcePro这次在价格方面压的比较死,同内存情况下,一加AcePro比iQOO10优惠近800元!更是有16G大运存版本。先下结论苹果秋季发布会前瞻iPhone14M2版iPadPro该来的总会来滴滴滴,还有一个月的时间,苹果秋季新品发布会就来了!不出意外,本次发布会的主角依然是新款iPhone,即iPhone14系列。当然,其它家常菜AppleWatchM2iPadPro盘点喝牛奶的4个禁忌,如果你经常喝,不要让营养白白浪费了牛奶是我们公认的营养品,也是我们每个人从刚出生就会喝的东西,牛奶,顾名思义就是乳牛产生的奶水,它的营养成分非常的丰富,含有大量的蛋白质,对于小朋友来说,它可以帮助小朋友吸收营养的同入秋后的青菜不用买,菜地里摘一把,鲜香味美营养高,别不懂吃入秋后的青菜不用买,菜地里摘一把,鲜香味美营养高,别不懂吃立秋以后,天气转凉,一些青菜也逐渐下市了,买的时候不容易,价格还很贵。今天呢,想给大家分享一种值得多吃的当季小青菜,不用花
蚂蚁花呗公司开局不好,京东科技将筹资10亿至20亿美元上市有句话是怎么说来着?消费贷会让缺乏相关金融发展思维的穷人陷入财务困境之中。年轻人要及早进行培养学生的金融服务意识,不要做金钱的奴隶,而是要学会驾驭金钱。是谁让今天的我们学会了超前消冰川很软,比想象的要多一些冰川冰通常被认为是易碎的。你可以在冰盖上钻一个洞,就像在岩石上一样,冰川会裂开,留下垂直的冰崖。但最进一项新研究表明,冰川也有轻微的可压缩性,或者说是软软的。从某种意义上说,发现了新年换新机,新年有新机!iQOO9Pro入手体验分享前段时间iQOO正式发布了iQOO9系列,系列中包括iQOO9和iQOO9Pro两款产品。一直想试试安卓机的我,在市场上寻觅已久,最终还是被iQOO9Pro打动。作为首批搭载新一代同样怀孕,有人孕吐严重而有人却没有反应,过来人吐是件好事大家是孕吐严重的哪位?还是毫无反应的那位呢?我怀孕时,真的是反应很大,从40多天前知道自己怀孕起,我就开始孕吐的反应。刚开始是不想吃东西,特别是闻到味道重的食物就会恶心,但是为了宝腾讯应届生公司群怒怼管理层,高管连夜回应认真反思,尽快整改1月26日,多个社交媒体大V爆料,25日深夜,腾讯企业微信的一名应届生员工在部门内部大群中,因赶版本导致的高强度加班问题,发消息怒怼管理层。腾讯应届生公司群怒怼管理层,高管连夜回应欧罗巴拉齐奥VS加拉塔萨,锋霸受伤门将神坑,拉齐奥能翻身吗一场万众瞩目的欧罗巴焦点战即将打响,在本场赛前发布会上,主帅萨里面对记者表示头号锋线因莫比莱目前并没有完全恢复,本场能否出场还要看赛前的准备情况,这对于拉齐奥球迷来说是一个重磅打击海布里之王为何不选择在枪手终老?当时又有哪些不为人知的苦衷?380场比赛,226个进球,4座英超金靴,2座英超奖杯,49场不败当我们把时间的指针拨回到06年的5月7日,即将送走的过客正是93岁的枪手圣地海布里,队长亨利上演帽子戏法为这座拥有海螺共和国在美国佛罗里达群岛,沿着1号公路可到达基韦斯特世界之大无奇不有,你听说过海螺共和国吗?这是一个位于美国佛罗里达州南端的微型国家,成立于1982年,距今刚好40周年。迈阿密与古巴哈瓦那之间的基韦斯特小岛,就是海螺共和国许多人对海24英寸千元美术显示器值得入手吗?亲测体验,没入手的可以看一下各种配置的显示器,不同的需求选择不同,对于图片处理工作者而言,更偏爱专业的美术显示器。INNOCN这个品牌在美术显示器领域上,表现更加优秀出众,成为同行的标杆品牌。最近就帮同事入手宝妈考编逆袭的感觉不要太爽2020年12月底打算考编,报的粉笔的网课,孩子刚刚8个月,自己带娃,只能是在孩子睡着家务做完的闲暇之余看看书,时间真的太碎片化了,感觉看了跟没看一样。于是决定报机构全日制备考。5生活杂记2017年的牡丹(20170502)以前随手拍过一些照片,记过一些乱七八糟的东西,回头翻翻,记起了很多旧事,边看边顺,修改了一些错字别字。本文记于17年5月2日,植物园看牡丹。就植物园而言,感觉起码应该具备两点。一是