功能说明
TokenBucket 以 Instant 记录上次补充时间,每次 try_acquire 先按经过秒数乘以速率补充令牌,上限为容量。令牌足够时扣除并返回 Ok(()),不足时用缺少的令牌数除以速率,返回需要等待的 Duration。示例容量 2、速率每秒 4 个,连续三次请求后第三次被拒绝。
关键代码
let now = Instant::now();
let elapsed = now.duration_since(self.last_refill).as_secs_f64();
self.tokens = (self.tokens + elapsed * self.refill_per_second).min(self.capacity);
self.last_refill = now;
min(capacity) 保证长时间空闲后不会积累超过容量的令牌,突发上限始终受控。
使用注意
Instant是单调时钟,不受系统时间调整影响,适合限流。- 成本必须大于 0 且不超过容量,示例用
assert!暴露非法参数。 - 结构体不是线程安全的,多线程共享需要
Mutex或原子实现。 - 返回的等待时间是最早可成功的时间,调用方仍需处理再次竞争失败的情况。
- 状态只在内存中,重启或扩容都会重置限流额度。
验证方式
示例前两次输出 allowed,第三次输出拒绝并给出约 250 毫秒的等待时间;睡眠 260 毫秒后再次请求通过。把容量改为 1 可观察无突发,把速率调低可观察等待时间变长。