4中经典限流器算法

前言

最近一位朋友去拼夕夕面试,被问了这么一道题:限流算法有哪些?用代码实现令牌桶算法。跟好友讨论了一波,发现大家都忘记得差不多了.所以再整理一波,常见的四种限流算法,以及简单代码实现,相信大家看完,会茅塞顿开的。

1. 固定窗口限流算法

1.1 什么是固定窗口限流算法

固定窗口限流算法(Fixed Window Rate Limiting Algorithm)是一种最简单的限流算法,其原理是在固定时间窗口(单位时间)内限制请求的数量。该算法将时间分成固定的窗口,并在每个窗口内限制请求的数量。具体来说,算法将请求按照时间顺序放入时间窗口中,并计算该时间窗口内的请求数量,如果请求数量超出了限制,则拒绝该请求。

假设单位时间(固定时间窗口)是1秒,限流阀值为3。在单位时间1秒内,每来一个请求,计数器就加1,如果计数器累加的次数超过限流阀值3,后续的请求全部拒绝。等到1s结束后,计数器清0,重新开始计数。如下图:

1.2 固定窗口限流的伪代码实现

    
    
  1. public static Integer counter = 0; / /统计请求数
  2. public static long lastAcquireTime = 0L;
  3. public static final Long windowUnit = 1000L ; / /假设固定时间窗口是 1000ms
  4. public static final Integer threshold = 10; / / 窗口阀值是 10
  5. / **
  6. * 固定窗口时间算法
  7. * 关注公众号:捡田螺的小男孩
  8. * @return
  9. */
  10. public synchronized boolean fixedWindowsTryAcquire() {
  11. long currentTime = System.currentTimeMillis(); / /获取系统当前时间
  12. if (currentTime - lastAcquireTime > windowUnit) { / /检查是否在时间窗口内
  13. counter = 0; / / 计数器清 0
  14. lastAcquireTime = currentTime; / /开启新的时间窗口
  15. }
  16. if (counter < threshold) { / / 小于阀值
  17. counter + +; / /计数统计器加 1
  18. return true;
  19. }
  20. return false;
  21. }
  22. 复制代码
1.2 固定窗口算法的优缺点
  • 优点:固定窗口算法非常简单,易于实现和理解。
  • 缺点:存在明显的临界问题,比如: 假设限流阀值为5个请求,单位时间窗口是1s,如果我们在单位时间内的前0.8-1s1-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. / **
  2. * 单位时间划分的小周期(单位时间是1分钟,10s一个小格子窗口,一共6个格子)
  3. */
  4. private int SUB_CYCLE = 10;
  5. / **
  6. * 每分钟限流请求数
  7. */
  8. private int thresholdPerMin = 100;
  9. / **
  10. * 计数器, k-为当前窗口的开始时间值秒,value为当前窗口的计数
  11. */
  12. private final TreeMap <Long, Integer > counters = new TreeMap <>();
  13. / **
  14. * 滑动窗口时间算法实现
  15. */
  16. public synchronized boolean slidingWindowsTryAcquire() {
  17. long currentWindowTime = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) / SUB_CYCLE * SUB_CYCLE; / /获取当前时间在哪个小周期窗口
  18. int currentWindowNum = countCurrentWindow(currentWindowTime); / /当前窗口总请求数
  19. / /超过阀值限流
  20. if (currentWindowNum >= thresholdPerMin) {
  21. return false;
  22. }
  23. / /计数器 + 1
  24. counters. get(currentWindowTime) + +;
  25. return true;
  26. }
  27. / **
  28. * 统计当前窗口的请求数
  29. */
  30. private synchronized int countCurrentWindow(long currentWindowTime) {
  31. / /计算窗口开始位置
  32. long startTime = currentWindowTime - SUB_CYCLE * ( 60s /SUB_CYCLE- 1);
  33. int count = 0;
  34. / /遍历存储的计数器
  35. Iterator <Map.Entry <Long, Integer >> iterator = counters.entrySet().iterator();
  36. while (iterator.hasNext()) {
  37. Map.Entry <Long, Integer > entry = iterator. next();
  38. / / 删除无效过期的子窗口计数器
  39. if (entry.getKey() < startTime) {
  40. iterator.remove();
  41. } else {
  42. / /累加当前窗口的所有计数器之和
  43. count = count + entry.getValue();
  44. }
  45. }
  46. return count;
  47. }
  48. 复制代码
2.3 滑动窗口限流算法的优缺点

优点

  • 简单易懂
  • 精度高(通过调整时间窗口的大小来实现不同的限流效果)
  • 可扩展性强(可以非常容易地与其他限流算法结合使用)

缺点

  • 突发流量无法处理(无法应对短时间内的大量请求,但是一旦到达限流后,请求都会直接暴力被拒绝。酱紫我们会损失一部分请求,这其实对于产品来说,并不太友好),需要合理调整时间窗口大小。

3. 漏桶限流算法

3.1 什么是漏桶限流算法

漏桶限流算法(Leaky Bucket Algorithm)是一种流量控制算法,用于控制流入网络的数据速率,以防止网络拥塞。它的思想是将数据包看作是水滴,漏桶看作是一个固定容量的水桶,数据包像水滴一样从桶的顶部流入桶中,并通过桶底的一个小孔以一定的速度流出,从而限制了数据包的流量。

漏桶限流算法的基本工作原理是:对于每个到来的数据包,都将其加入到漏桶中,并检查漏桶中当前的水量是否超过了漏桶的容量。如果超过了容量,就将多余的数据包丢弃。如果漏桶中还有水,就以一定的速率从桶底输出数据包,保证输出的速率不超过预设的速率,从而达到限流的目的。

  • 流入的水滴,可以看作是访问系统的请求,这个流入速率是不确定的。
  • 桶的容量一般表示系统所能处理的请求数。
  • 如果桶的容量满了,就达到限流的阀值,就会丢弃水滴(拒绝请求)
  • 流出的水滴,是恒定过滤的,对应服务按照固定的速率处理请求。
3.2 漏桶限流算法的伪代码实现

    
    
  1. / **
  2. * LeakyBucket 类表示一个漏桶,
  3. * 包含了桶的容量和漏桶出水速率等参数,
  4. * 以及当前桶中的水量和上次漏水时间戳等状态。
  5. */
  6. public class LeakyBucket {
  7. private final long capacity; / / 桶的容量
  8. private final long rate; / / 漏桶出水速率
  9. private long water; / / 当前桶中的水量
  10. private long lastLeakTimestamp; / / 上次漏水时间戳
  11. public LeakyBucket(long capacity, long rate) {
  12. this.capacity = capacity;
  13. this.rate = rate;
  14. this.water = 0;
  15. this.lastLeakTimestamp = System.currentTimeMillis();
  16. }
  17. / **
  18. * tryConsume() 方法用于尝试向桶中放入一定量的水,如果桶中还有足够的空间,则返回 true,否则返回 false。
  19. * @param waterRequested
  20. * @return
  21. */
  22. public synchronized boolean tryConsume(long waterRequested) {
  23. leak();
  24. if (water + waterRequested <= capacity) {
  25. water + = waterRequested;
  26. return true;
  27. } else {
  28. return false;
  29. }
  30. }
  31. / **
  32. * 。leak() 方法用于漏水,根据当前时间和上次漏水时间戳计算出应该漏出的水量,然后更新桶中的水量和漏水时间戳等状态。
  33. */
  34. private void leak() {
  35. long now = System.currentTimeMillis();
  36. long elapsedTime = now - lastLeakTimestamp;
  37. long leakedWater = elapsedTime * rate / 1000;
  38. if (leakedWater > 0) {
  39. water = Math.max( 0, water - leakedWater);
  40. lastLeakTimestamp = now;
  41. }
  42. }
  43. }
  44. 复制代码
  • 注意: tryConsume() leak() 方法中,都需要对桶的状态进行同步,以保证线程安全性。
3.3 漏桶限流算法的优缺点

优点

  • 可以平滑限制请求的处理速度,避免瞬间请求过多导致系统崩溃或者雪崩。
  • 可以控制请求的处理速度,使得系统可以适应不同的流量需求,避免过载或者过度闲置。
  • 可以通过调整桶的大小和漏出速率来满足不同的限流需求,可以灵活地适应不同的场景。

缺点

  • 需要对请求进行缓存,会增加服务器的内存消耗。
  • 对于流量波动比较大的场景,需要较为灵活的参数配置才能达到较好的效果。
  • 但是面对突发流量的时候,漏桶算法还是循规蹈矩地处理请求,这不是我们想看到的啦。流量变突发时,我们肯定希望系统尽量快点处理请求,提升用户体验嘛。

4. 令牌桶算法

4.1 什么是令牌桶算法

令牌桶算法是一种常用的限流算法,可以用于限制单位时间内请求的数量。该算法维护一个固定容量的令牌桶,每秒钟会向令牌桶中放入一定数量的令牌。当有请求到来时,如果令牌桶中有足够的令牌,则请求被允许通过并从令牌桶中消耗一个令牌,否则请求被拒绝。

4.2 令牌桶算法的伪代码实现

    
    
  1. / **
  2. * TokenBucket 类表示一个令牌桶
  3. */
  4. public class TokenBucket {
  5. private final int capacity; / / 令牌桶容量
  6. private final int rate; / / 令牌生成速率,单位:令牌 /
  7. private int tokens; / / 当前令牌数量
  8. private long lastRefillTimestamp; / / 上次令牌生成时间戳
  9. / **
  10. * 构造函数中传入令牌桶的容量和令牌生成速率。
  11. * @param capacity
  12. * @param rate
  13. */
  14. public TokenBucket(int capacity, int rate) {
  15. this.capacity = capacity;
  16. this.rate = rate;
  17. this.tokens = capacity;
  18. this.lastRefillTimestamp = System.currentTimeMillis();
  19. }
  20. / **
  21. * allowRequest() 方法表示一个请求是否允许通过,该方法使用 synchronized 关键字进行同步,以保证线程安全。
  22. * @return
  23. */
  24. public synchronized boolean allowRequest() {
  25. refill();
  26. if (tokens > 0) {
  27. tokens--;
  28. return true;
  29. } else {
  30. return false;
  31. }
  32. }
  33. / **
  34. * refill() 方法用于生成令牌,其中计算令牌数量的逻辑是按照令牌生成速率每秒钟生成一定数量的令牌,
  35. * tokens 变量表示当前令牌数量,
  36. * lastRefillTimestamp 变量表示上次令牌生成的时间戳。
  37. */
  38. private void refill() {
  39. long now = System.currentTimeMillis();
  40. if (now > lastRefillTimestamp) {
  41. int generatedTokens = (int) ((now - lastRefillTimestamp) / 1000 * rate);
  42. tokens = Math.min(tokens + generatedTokens, capacity);
  43. lastRefillTimestamp = now;
  44. }
  45. }
  46. }
  47. 复制代码
4.3 令牌桶算法的优缺点

优点:

  • 稳定性高:令牌桶算法可以控制请求的处理速度,可以使系统的负载变得稳定。
  • 精度高:令牌桶算法可以根据实际情况动态调整生成令牌的速率,可以实现较高精度的限流。
  • 弹性好:令牌桶算法可以处理突发流量,可以在短时间内提供更多的处理能力,以处理突发流量。

GuavaRateLimiter限流组件,就是基于令牌桶算法实现的。

缺点:

  • 实现复杂:相对于固定窗口算法等其他限流算法,令牌桶算法的实现较为复杂。 对短时请求难以处理:在短时间内有大量请求到来时,可能会导致令牌桶中的令牌被快速消耗完,从而限流。这种情况下,可以考虑使用漏桶算法。
  • 时间精度要求高:令牌桶算法需要在固定的时间间隔内生成令牌,因此要求时间精度较高,如果系统时间不准确,可能会导致限流效果不理想。

总体来说,令牌桶算法具有较高的稳定性和精度,但实现相对复杂,适用于对稳定性和精度要求较高的场景。

文章知识点与官方知识档案匹配,可进一步学习相关知识
算法技能树首页概览 58235 人正在系统学习中
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 自适应限流控制算法是一种用于网络流量控制的方法,旨在保护网络稳定性和消除拥塞现象。MATLAB是一种广泛应用于科学和工程计算领域的编程语言和环境,适用于开发自适应限流控制算法。下面是自适应限流控制算法MATLAB程序的实现步骤和思路: 1. 初始化:首先需要对算法进行初始化,包括设定初始的合法带宽值和流量大小等参数。 2. 流量测量:对网络流量进行实时测量,以便清楚地了解网络总体的流量大小和流量分布情况。 3. 带宽控制:根据实时测量的流量数据,计算当前需要限制的合法带宽大小,并设置相应的限制措施,如限速或限流。 4. 带宽更新:随着网络流量的变化,需要动态更新合法带宽大小。根据控制效果和流量变化情况,调整合法带宽大小,以适应不同的流量需求。 5. 调试和优化:对程序进行调试和优化,确保程序的稳定性和准确性,保障网络的正常运行。 总之,自适应限流控制算法MATLAB程序的实现需要通过多个步骤和考虑多个因素来确保其效果。在实际应用,需要根据具体的网络环境和需求来选择合适的参数和控制策略,以确保网络稳定性和流量调控的效果。 ### 回答2: 自适应限流控制算法是一种可以管理网络流量并限制带宽的算法。这种算法被广泛应用于互联网,因为它有助于提高网络的效率并确保所有用户都能够访问所需的资源。 Matlab程序可以使用自适应限流控制算法来管理网络流量。该程序在开始时会通过网络监测来测量应用程序的流量。然后,程序会根据这些数据实时地调整流量,并确保该流量不会超过所设定的阈值。 程序的核心是一个控制,该控制使用反馈控制方法来根据数据心的输入来调整流量。控制通过计算误差信号,然后将其与预先定义的阈值进行比较,以便根据需要对流量进行调整。该程序还包括一个自适应机制,当流量变化时,自适应机制会扩展或缩小阈值,以便更好的适应网络流量的变化。 此外,该程序还可以通过使用一些机学习算法来识别可能的网络攻击和访问模式,以动态调整流量。这些算法可以识别具有异常访问行为的用户并防止他们影响网络的正常运行。 总之,自适应限流控制算法matlab程序可以帮助网络管理员更好地管理网络流量,提高网络带宽的利用率,确保网络资源的公平分配,并确保网络运行顺畅。 ### 回答3: 自适应限流控制算法是一种流量控制方法,该方法可以自动调整控制参数以满足不同的网络环境和负载条件。MATLAB程序可以帮助我们实现这种控制算法,下面是程序的主要步骤: 1. 定义控制参数:首先,我们需要定义控制参数,例如最大流量阈值,初始值和调整步长等。 2. 监测流量:使用MATLAB的网络编程库可以监测网络流量,获取当前网络的实时状态。 3. 计算流量负载:接下来,我们需要计算当前网络的流量负载,这个可以用MATLAB的数学函数和算法。 4. 计算控制参数:根据当前的流量负载,我们需要计算新的控制参数,例如新的最大流量阈值,新的调整步长等。 5. 执行流量控制:最后,我们根据新的控制参数进行流量控制,例如限制最大流量,调整传输协议等。 以上就是自适应限流控制算法MATLAB程序的主要步骤,通过不断的监测和调整可以实现网络流量的自适应控制,提高网络性能和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值