请求对冲

解释了请求对冲是什么以及如何配置它。

请求对冲

解释了请求对冲是什么以及如何配置它。

概述

对冲是 gRPC 支持的两种可配置重试策略之一。通过对冲,gRPC 客户端将同一请求的多个副本发送到不同的后端,并使用它收到的第一个响应。随后,客户端会取消所有未完成的请求,并将响应转发给应用程序。

Basic hedging diagram

用例

对冲是一种在大规模分布式系统中减少尾部延迟的技术。虽然简单实现可能会给后端服务器增加显著负载,但可以在适度增加负载的情况下获得大部分延迟减少效果。

有关尾部延迟的深入讨论,请参阅 Jeff Dean 和 Luiz André Barroso 的开创性文章《规模化尾部效应》(The Tail At Scale)。

在 gRPC 中配置对冲

对冲可通过gRPC 服务配置进行配置,粒度可达每个方法。配置包含以下参数:

"hedgingPolicy": {
  "maxAttempts": INTEGER,
  "hedgingDelay": JSON proto3 Duration type,
  "nonFatalStatusCodes": JSON array of grpc status codes (int or string)
}
  • maxAttempts:等待成功响应时最大飞行中请求数。这是一个必填字段,必须指定。如果指定值大于 5,gRPC 将使用 5
  • hedgingDelay:等待成功响应时,客户端发送下一个请求前需要经过的时间量。此字段是可选的,如果未指定,将导致 maxAttempts 数量的请求同时发送。
  • nonFatalStatusCodes:gRPC 状态码的可选列表。如果任何对冲请求以不在该列表中的状态码失败,所有未完成的请求将被取消,并将响应返回给应用程序。

对冲策略

当应用程序进行包含服务配置中 hedgingPolicy 配置的 RPC 调用时,原始 RPC 会像标准非对冲调用一样立即发送。如果在 hedgingDelay 时间过去后仍未收到成功响应,则会发出第二个 RPC。如果再次经过 hedgingDelay 时间后两个 RPC 都未收到响应,则会发送第三个 RPC,依此类推,直到达到 maxAttempts。gRPC 调用截止时间适用于整个对冲请求链。一旦截止时间过去,无论是否有飞行中的 RPC 以及对冲配置如何,操作都会失败。

当收到成功响应(对任何对冲请求的响应)时,所有未完成的对冲请求都将被取消,并将响应返回给客户端应用程序层。

如果从对冲请求收到带有非致命状态码(由 nonFatalStatusCodes 字段控制)的错误响应,则队列中的下一个对冲请求会立即发送,从而缩短其对冲延迟。如果收到任何其他状态码,所有未完成的 RPC 都将被取消,并且错误将返回给客户端应用程序层。

如果对冲 RPC 的所有实例都失败,则不会有额外的重试尝试。本质上,对冲可以看作是在收到失败之前就重试原始 RPC。

如果在对冲请求的响应中收到指定不重试的服务器回压,则不应再为该调用发出任何进一步的对冲请求。

限制对冲 RPC

gRPC 提供了一种限制对冲 RPC 的方式,以防止服务器过载。也可以通过服务配置并使用 RetryThrottlingPolicy 消息来配置限制。限制配置包含以下内容:

"retryThrottling": {
  "maxTokens": 10,
  "tokenRatio": 0.1
}

对于每个服务器名称,gRPC 客户端维护一个 token_count,其初始值设置为 max_tokens。每个传出的 RPC(无论调用的是服务还是方法)都会按如下方式更改 token_count

  • 每个失败的 RPC 会将 token_count1
  • 每个成功的 RPC 会将 token_count 增加 token_ratio

对于对冲,第一个请求总是会发送出去,但后续的对冲请求只有在 token_count 大于阈值(定义为 max_tokens / 2)时才会发送。如果 token_count 小于或等于阈值,对冲请求不会阻塞。相反,它们会被取消,并且如果没有其他已经发送的对冲 RPC,则失败会返回给客户端应用程序。

对于限制策略,只有以符合非致命状态码的状态码失败的请求,或者收到指示不重试的回压响应的请求,才算作失败。这避免了将服务器失败与对格式错误请求的响应(例如 INVALID_ARGUMENT 状态码)混淆。

服务器回压

服务器可以通过在其对客户端的响应中设置元数据来明确回压。如果回压指示不重试,则不会发送进一步的对冲请求。如果回压指示在给定延迟后重试,则下一个对冲请求(如果有)将在给定延迟过去后发出。

服务器回压使用元数据键 grpc-retry-pushback-ms 指定。该值是一个 ASCII 编码的带符号 32 位整数,没有不必要的零前缀,表示在发送下一个对冲请求之前需要等待多少毫秒。如果回压值为负或无法解析,则将被视为服务器要求客户端完全不重试。

资源

语言支持

语言示例
JavaJava 示例
C++暂不可用
Go暂不支持
上次修改时间:2023年10月3日:添加请求对冲指南 (#1199) (d357308)