← 中文资源

简体中文版本

重试预算

重试预算把重试流量限制为成功流量的一定比例,防止故障期间的重试风暴放大负载并拖慢恢复。

阅读英文原文

重试放大

假设 10% 的请求失败,而每个请求重试两次;失败的 10% 就变成了额外 20% 的流量,而且恰好发生在依赖最无力处理的时候。如果依赖失败率上升,重试可能把已经退化的服务推向崩溃。重试预算把额外流量限制为成功流量的受控比例。

一个简单预算

在滚动窗口内记录成功与重试,只有当 retries < successes * ratio 时才允许重试。10% 的比例、每分钟 1,000 次成功,意味着每分钟最多 100 次重试。

class RetryBudget {
  constructor(ratio = 0.1, windowMs = 60_000, now = Date.now) {
    this.ratio = ratio;
    this.windowMs = windowMs;
    this.now = now;
    this.successes = [];
    this.retries = [];
  }

  recordSuccess() {
    this.prune();
    this.successes.push(this.now());
  }

  tryRetry() {
    this.prune();
    if (this.retries.length >= this.successes.length * this.ratio) {
      return false;
    }
    this.retries.push(this.now());
    return true;
  }

  prune() {
    const cutoff = this.now() - this.windowMs;
    this.successes = this.successes.filter((t) => t >= cutoff);
    this.retries = this.retries.filter((t) => t >= cutoff);
  }
}

退避与截止时间

预算控制的是流量,不是时机。应配合指数退避与抖动,并设置总截止时间,避免重试无限延长请求。带截止时间的重试预算示例 组合了这些关注点。

何时使用

在调用共享依赖的客户端库和服务网格中使用重试预算。与每请求固定重试次数相比,预算能适应整体流量。与熔断器相比,预算减少重试负载但仍允许调用;熔断器在确认故障后停止调用。

陷阱

预算需要共享状态或按实例计数;按实例预算只是近似全局限制,在扇出场景仍可能放大。没有幂等键时绝不重试非幂等操作。同时测量重试次数和最终成功率;一个通过掩盖持续故障来提高成功率的预算并没有起作用。

相关资源