3. 令牌桶算法详解

令牌桶算法(Token Bucket)是金融 API 限流中最常用的算法之一。它允许一定程度的突发流量,同时保证长期平均速率不超过设定阈值,非常适合处理交易、行情订阅等具有突发特征的金融请求。

3.1 工作机制

令牌桶的核心思想是:系统以恒定速率向一个“桶”中放入令牌,每个请求必须从桶中获取一个令牌才能被处理。如果桶中没有令牌,请求将被拒绝或等待。

关键特性: 允许突发流量——桶中最多可累积 容量(burst) 个令牌,当突发请求到来时,可以一次性消耗所有累积令牌,实现短时间内的流量爆发。
令牌桶算法工作流程 令牌生成器 速率 r 个/秒 令牌桶 容量 = b 当前令牌数 = n 请求队列 等待/丢弃 放入令牌 获取令牌 API 请求 有令牌? 是 否 请求通过 请求拒绝 说明 • 令牌按速率 r 持续生成 • 桶满时新令牌丢弃 • 请求消耗 1 个令牌 • 无令牌则请求排队或拒绝

3.2 参数配置

令牌桶算法有两个核心参数,直接决定限流效果:

参数 符号 含义 金融场景示例
速率(Rate) r 令牌生成速度,单位:个/秒 r = 100,表示每秒最多处理 100 笔交易
容量(Capacity) b 桶的最大令牌数,决定突发能力 b = 200,允许瞬间处理 200 笔积压请求
配置建议: 金融 API 中,建议 b ≥ 2 × r,以应对行情波动时的突发查询。例如,若速率设为 500 QPS,容量可设为 1000~1500,避免瞬时高峰被误杀。

3.3 Python 代码实现

以下是一个完整的令牌桶限流器实现,包含时间戳驱动的令牌补充逻辑:

import time
import threading

class TokenBucket:
    """令牌桶限流器"""

    def __init__(self, rate: float, capacity: int):
        """
        :param rate: 令牌生成速率(个/秒)
        :param capacity: 桶容量(最大令牌数)
        """
        self.rate = rate
        self.capacity = capacity
        self.tokens = capacity          # 初始满桶
        self.last_refill = time.time()  # 上次补充时间
        self.lock = threading.Lock()    # 线程安全

    def _refill(self):
        """补充令牌"""
        now = time.time()
        elapsed = now - self.last_refill
        new_tokens = elapsed * self.rate
        self.tokens = min(self.capacity, self.tokens + new_tokens)
        self.last_refill = now

    def consume(self, tokens: int = 1) -> bool:
        """
        消费令牌
        :return: True 表示允许请求,False 表示限流
        """
        with self.lock:
            self._refill()
            if self.tokens >= tokens:
                self.tokens -= tokens
                return True
            return False

# 使用示例
if __name__ == "__main__":
    # 创建限流器:每秒 10 个令牌,容量 20
    bucket = TokenBucket(rate=10, capacity=20)

    # 模拟 30 个并发请求
    for i in range(30):
        allowed = bucket.consume()
        status = "✅ 通过" if allowed else "❌ 限流"
        print(f"请求 {i+1:2d}: {status} (剩余令牌: {bucket.tokens:.1f})")
        time.sleep(0.05)  # 模拟请求间隔

3.4 可视化分析

通过模拟请求并记录令牌变化,可以直观观察令牌桶的突发吸收能力:

令牌桶模拟:速率 10/s,容量 20 0 5 10 15 20 0s 1s 2s 3s 4s 5s 6s 突发请求 图例 令牌数量 突发消耗 令牌数
可视化解读: 上图展示了令牌桶在稳定状态下的表现。前 3 秒请求平稳,令牌始终维持在容量上限(20)。第 3 秒出现突发请求,令牌被快速消耗至接近 0,但桶的容量允许这批突发通过。随后系统恢复,令牌按速率重新累积,体现了“允许突发、平滑长期”的核心特性。

3.5 金融场景适用性分析

场景 推荐配置 原因
行情订阅 API r=1000, b=3000 行情波动大,需要较大突发能力
交易下单 API r=50, b=100 交易频率低但需防刷单
账户查询 API r=200, b=400 查询请求均匀,突发需求较小
注意事项: 令牌桶算法不保证请求的公平性——如果桶中令牌不足,后到的请求可能被丢弃,而先到的请求可能因为等待而超时。在金融场景中,建议结合 请求优先级队列 或 加权令牌分配 来优化。