← 中文资源

简体中文版本

Bottleneck 令牌桶限流调度

用 Bottleneck 实现令牌桶限流:滚动速率与并发上限组合,优先级高的任务在配额紧张时优先出队。

阅读英文原文

示例说明

对接有配额的第三方 API 时,简单 sleep 节流会把延迟平摊到所有请求,无法表达突发与优先级。Bottleneck 的 reservoir 是每 60 秒刷新一次的令牌桶,maxConcurrent 与 minTime 进一步限制瞬时并发与最小间隔,schedule 的 priority 让关键调用在令牌紧张时插队。

技术要点

  • reservoir 每 60 秒刷新 20 个令牌
  • maxConcurrent 与 minTime 约束瞬时并发与间隔
  • priority 参数支持任务插队

代码解读

limiter 构造时同时给出桶容量、刷新量与刷新周期,形成令牌桶模型;callApi 把 fetch 包进 schedule 并传入优先级(数值越小越优先)。error 事件监听器用于捕获调度器内部异常,避免静默丢失任务。

使用建议

配额参数要与 API 文档的实际限额核对,留出安全余量。高优先级滥用会让普通任务饥饿,建议只给少量关键路径使用。需要跨进程限流时可接入 Bottleneck 的 Redis 集群模式。

代码示例

import Bottleneck from 'bottleneck';

const limiter = new Bottleneck({
  reservoir: 20,
  reservoirRefreshAmount: 20,
  reservoirRefreshInterval: 60_000,
  maxConcurrent: 5,
  minTime: 200,
});

limiter.on('error', (err) => console.error('limiter error:', err.message));

async function callApi(path, priority = 5) {
  return limiter.schedule({ priority }, () =>
    fetch(`https://api.example.com${path}`).then((r) => r.json()),
  );
}

const high = await callApi('/billing/summary', 1);
const normal = await callApi('/catalog/list', 5);