这个机制的核心思想是:当后端服务已经过载时,如果客户端继续盲目地发送请求,不仅会浪费网络带宽,还会让后端花费额外的 CPU 资源去拒绝这些请求。因此,最好的做法是让客户端在本地直接丢弃部分请求(即“熔断”或“节流”),从而保护后端服务。
为了实现这种自适应的客户端节流,谷歌引入 requests 和 accepts,并使用了一个概率公式。以下是具体的运作原理:
核心参数定义
- requests(请求数):客户端应用程序层尝试发起的请求总数量。
- accepts(接受数):后端服务器实际接受并成功处理的请求数量(即没有因为过载而返回 HTTP 503 等拒绝状态码的请求)。
- K(倍数):一个安全乘数,谷歌通常建议将其设置为 2。
客户端拒绝概率公式
客户端计算在本地直接拦截并丢弃请求的概率公式如下:
截留概率 = max(0, (requests - K * accepts) / (requests + 1))
(注:分母中的 +1 是为了防止请求数为 0 时出现除以 0 的错误)
机制是如何运转的?
这套机制的精妙之处在于它能够根据后端的健康状态动态调整,不需要人工干预:
1. 正常状态(请求全部被处理) 假设客户端发出了 100 个请求,后端状态良好,处理了所有请求。
- requests = 100
- accepts = 100
- K = 2
- 计算:(100 - 2 * 100) / 101 = -100 / 101。
- 因为有
max(0, ...)的限制,最终概率为 0。客户端不会在本地拦截任何请求。
2. 临界状态(触发阈值) requests = K * accepts,这是节流机制开始生效的临界点。只要客户端发起的请求数量不超过后端成功处理数量的 K 倍,系统就会让所有请求通过。
3. 过载状态(触发客户端节流) 假设后端因为负载过高,最多只能处理 100 个请求,但客户端因为重试或者流量突增,发起了 300 个请求。
- requests = 300
- accepts = 100
- K = 2
- 计算:(300 - 2 * 100) / 301 = 100 / 301 ≈ 33%。
- 结果:客户端会在本地以大约 33% 的概率直接丢弃新产生的请求,并直接向前端抛出本地失败异常。这些被拦截的请求根本不会进入网络,极大地减轻了后端的压力。
为什么需要乘数 K?
你可能会问,为什么不直接比较 requests 和 accepts(即 K=1)?
引入 K(通常设为 2)是为了提供一个缓冲池。如果 K=1,只要后端偶尔拒绝了一两个请求,客户端就会立刻开始节流,这会导致系统过于敏感。设置为 2 意味着:客户端允许后端存在一定程度的波动,只有当拒绝率达到 50%(即发送的请求是成功接受请求的两倍)时,客户端才会开始介入保护。这让后端有稍微喘息和恢复的空间,同时也允许系统试探后端是否已经恢复了处理能力。