这是一个非常重要且常用的流量整形和速率限制算法。它的核心思想非常直观和优雅。

  1. 核心概念
    想象一个桶,这个桶有固定的容量。系统会以一个恒定的速率向这个桶里放入“令牌”。每当一个请求(或数据包)到来时,它需要从桶中取出一个(或多个)令牌才能被处理。

桶的容量 (Capacity):桶最多能存放的令牌数量。这决定了在短时间内能允许的突发流量最大值。

令牌放入速率 (Rate):系统每隔多久向桶中放入一个令牌。这个速率决定了长期来看的平均请求处理速率。

  1. 算法工作原理
    初始化:桶开始时是满的,里面有 capacity 个令牌。

添加令牌:系统以一个固定的时间间隔(例如,每 1/rate 秒)向桶中添加一个令牌。如果桶已经满了,新添加的令牌会被丢弃。

处理请求:当一个请求到达时:

如果桶中有足够数量的令牌(比如需要 1 个),则取出相应数量的令牌,请求被立即放行处理。

如果桶中没有足够的令牌,那么这个请求会被等待(排队)或直接丢弃/拒绝(取决于具体的实现策略),直到桶中有新的令牌加入。

  1. 一个简单的例子
    假设我们有一个令牌桶,其参数如下:

速率 (Rate):每秒 2 个令牌 → 即每 0.5 秒加一个令牌。

容量 (Capacity):10 个令牌。

情景模拟:

时间 0s:桶是满的,有 10 个令牌。

时间 0s:突然来了 5 个请求。每个请求消耗 1 个令牌。桶里还剩 5 个令牌。所有 5 个请求都被立即处理。这体现了处理突发流量的能力。

时间 0.5s:系统添加一个令牌,桶里有 6 个令牌。

时间 1.0s:系统添加一个令牌,桶里有 7 个令牌。

时间 1.5s:系统添加一个令牌,桶里有 8 个令牌。

时间 5.0s:此时桶已经被重新加满到 10 个令牌(因为添加令牌的速率大于消耗速率)。

时间 6.0s:突然又来了 15 个请求。

前 10 个请求可以立即被处理,消耗掉所有令牌。

剩下的 5 个请求无法立即得到令牌,它们必须等待。由于每 0.5 秒才会产生一个新令牌,这些请求将根据新的令牌产生速率被逐个处理(大约每 0.5 秒处理一个)。

从这个例子可以看出:

长期平均速率被限制为每秒 2 个请求。

短期突发流量最多可以处理 10 个请求(桶的容量)。

  1. 算法实现(伪代码/Python风格)
    在实际编程中,我们通常不会真的启动一个定时器来添加令牌,而是采用“惰性计算”的方式,在请求到来时计算自上次检查以来应该产生多少新令牌。

python
import time

class TokenBucket:
def init(self, capacity, rate):
self.capacity = capacity # 桶的容量
self.rate = rate # 令牌放入速率 (个/秒)
self.tokens = capacity # 当前令牌数量
self.last_time = time.time() # 上次更新时间戳

def consume(self, tokens_needed=1):
    now = time.time()
    elapsed = now - self.last_time # 计算经过的时间

    # 计算这段时间内应该添加多少令牌
    new_tokens = elapsed * self.rate
    # 更新当前令牌数量(不能超过桶容量)
    self.tokens = min(self.capacity, self.tokens + new_tokens)
    self.last_time = now

    # 判断是否有足够的令牌
    if self.tokens >= tokens_needed:
        self.tokens -= tokens_needed
        return True  # 获取令牌成功
    else:
        return False # 获取令牌失败(请求被限流)
  1. 优点
    允许突发流量:这是相对于另一种漏桶算法的主要优点。因为桶有容量,它可以应对短时间内的流量高峰。

平滑流量:长期来看,输出速率是稳定的,等于令牌生成的速率,不会对下游系统造成巨大压力。

易于实现:概念简单,实现起来也不复杂。

  1. 应用场景
    令牌桶算法广泛应用于网络和系统中:

API 速率限制:例如,规定每个用户每秒只能调用某个 API 10 次。使用令牌桶(capacity=10, rate=10/s)可以允许用户在前 100 毫秒内快速调用 10 次,之后就必须每秒一次地调用。

网络流量整形:限制网络接口发送数据的速率,防止网络拥堵。

CPU 调度:限制进程的 CPU 使用率。

  1. 与漏桶算法的区别
    这是一个常见的对比点:

特性 令牌桶 漏桶
核心概念 拿令牌放行请求 水(请求)从漏孔中匀速流出
速率限制 平均速率 + 突发流量 严格的恒定速率
实现关键 令牌生成 请求队列
灵活性 更灵活,适合需要一定突发量的场景 更严格,保证绝对平滑的输出
简单来说,令牌桶允许一定程度的突发,而漏桶强制要求输出绝对平滑。在大多数互联网速率限制的场景下,令牌桶因其灵活性而更受欢迎。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注