令牌桶和漏桶算法的区别

概述

令牌桶算法和漏桶算法常用作限流器。从使用的角度,而不是算法实现的角度,两种算法其实只向我们暴露一个方法IsLimit,无入参,出参是布尔类型,代表是否限流。

令牌桶算法:有一个固定容量的桶,以恒定速率向桶里面添加令牌,我们可以从桶里面每次取出一个令牌。当取的很频繁时,就可能桶中没有令牌可取,此时被限流。

漏桶算法:有一个固定容量的桶,里面装了水,桶底部有洞,水以恒定速率向外流出,我们可以向桶里加水。当加水动作很频繁时,超过流出速度,桶里的水会满,此时被限流。

可以结合后面的代码来理解两种算法

结论

作为限流器,从使用方面,令牌桶和漏桶算法没有区别,两者均需要初始化桶容量和速率,都会以固定速率往桶里加令牌或漏水。
实现原理方面:

  • 令牌桶算法中,如果从桶中拿不到令牌,即桶空了,被限流
  • 漏桶算法中,如果桶满,则被限流

两者唯一的区别,在于使用方面。漏桶算法可以实现为一个带容量的消息队列,分别有生产者和消费者,生产者向桶中加水,消费者从桶中取水(漏水),由于消费者以固定速率取水,所以有“流量整形”的味道。在这种场景,水有了特殊的含义,不仅仅是一个计数器。且有独特的消费者。
令牌桶算法中的令牌数量,一般仅作为简单的计数器。

详细

对于令牌桶算法以固定速率生成令牌,或者是漏桶算法以固定速率漏水,具体实现,一方面可以通过独立线程去做“加令牌”或“漏水”操作,另一方面可以“惰性”操作,即记录上一次操作的时间,仅当取令牌或添水时,才计算这个时间段本应该“生成多少令牌”或“漏多少水”。

令牌桶代码实现

package main

import (
	"fmt"
	"time"
)

type TokenBucket struct {
	capacity  int
	tokens    int
	rate      int
	lastToken time.Time
}

func NewTokenBucket(capacity, rate int) *TokenBucket {
	return &TokenBucket{
		capacity:  capacity,
		tokens:    capacity,
		rate:      rate,
		lastToken: time.Now(),
	}
}

func (tb *TokenBucket) AllowRequest() bool {
	now := time.Now()
	tb.tokens += int(now.Sub(tb.lastToken).Seconds()) * tb.rate
	if tb.tokens > tb.capacity {
		tb.tokens = tb.capacity
	}
	tb.lastToken = now

	if tb.tokens > 0 {
		tb.tokens--
		return true
	}
	return false
}

func main() {
	tb := NewTokenBucket(10, 1)

	for i := 0; i < 15; i++ {
		if tb.AllowRequest() {
			fmt.Println("Request", i, "allowed")
		} else {
			fmt.Println("Request", i, "blocked")
		}
		time.Sleep(time.Second)
	}
}

漏桶算法代码实现

package main

import (
	"fmt"
	"time"
)

type LeakyBucket struct {
	capacity  int
	water     int
	rate      int
	lastLeak  time.Time
}

func NewLeakyBucket(capacity, rate int) *LeakyBucket {
	return &LeakyBucket{
		capacity: capacity,
		water:    0,
		rate:     rate,
		lastLeak: time.Now(),
	}
}

func (lb *LeakyBucket) AllowRequest() bool {
	now := time.Now()
	elapsed := int(now.Sub(lb.lastLeak).Seconds())
	lb.water -= elapsed * lb.rate
	if lb.water < 0 {
		lb.water = 0
	}
	lb.lastLeak = now

	if lb.water < lb.capacity {
		lb.water++
		return true
	}
	return false
}

func main() {
	lb := NewLeakyBucket(10, 1)

	for i := 0; i < 15; i++ {
		if lb.AllowRequest() {
			fmt.Println("Request", i, "allowed")
		} else {
			fmt.Println("Request", i, "blocked")
		}
		time.Sleep(time.Second)
	}
}

相关推荐

  1. 令牌算法区别

    2024-05-10 05:18:02       13 阅读
  2. 令牌算法算法

    2024-05-10 05:18:02       13 阅读
  3. 微服务限流(算法、令牌算法

    2024-05-10 05:18:02       35 阅读
  4. 【Go】令牌限流算法

    2024-05-10 05:18:02       18 阅读
  5. golang版本使用令牌算法来实现限流策略

    2024-05-10 05:18:02       35 阅读
  6. SpringBoot中实现API速率限制令牌算法项目

    2024-05-10 05:18:02       17 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-10 05:18:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-10 05:18:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-10 05:18:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-10 05:18:02       18 阅读

热门阅读

  1. 双网口扩展IO支持8DO输出

    2024-05-10 05:18:02       12 阅读
  2. .Net WinFrom中DataGridView控件的熟练学习

    2024-05-10 05:18:02       10 阅读
  3. Go中json的解析和反解析

    2024-05-10 05:18:02       8 阅读
  4. 【Android】EventBus收不到消息的一种情况

    2024-05-10 05:18:02       11 阅读
  5. 深入理解nginx中的signal处理机制

    2024-05-10 05:18:02       11 阅读
  6. 等保测评—Linux核查指令3

    2024-05-10 05:18:02       11 阅读
  7. 2024.5.2 —— LeetCode 高频题复盘

    2024-05-10 05:18:02       13 阅读
  8. STM32G4做一个示波器

    2024-05-10 05:18:02       9 阅读
  9. 从目标检测数据集中选出指定类别的图片和标签

    2024-05-10 05:18:02       14 阅读
  10. 1-jenkins流水线相关案例

    2024-05-10 05:18:02       13 阅读