请求对冲
解释什么是请求对冲以及如何配置它。
请求对冲
概述
对冲是 gRPC 支持的两种可配置的重试策略之一。通过对冲,gRPC 客户端将同一请求的多个副本发送到不同的后端,并使用它收到的第一个响应。随后,客户端取消任何未完成的请求并将响应转发给应用程序。
用例
对冲是一种在大型分布式系统中减少尾部延迟的技术。虽然简单的实现可能会给后端服务器增加显著的负载,但有可能在仅适度增加负载的情况下获得大部分延迟降低的效果。
有关尾部延迟的深入讨论,请参阅 Jeff Dean 和 Luiz André Barroso 的开创性文章,规模化的尾部延迟。
在 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。如果两个 RPC 在 hedgingDelay
再次经过后都没有收到响应,则会发送第三个 RPC,依此类推,最多达到 maxAttempts
。gRPC 调用截止期限适用于整个对冲请求链。一旦截止期限已过,无论正在进行的 RPC 如何,也无论对冲配置如何,操作都会失败。
当收到成功响应(响应任何对冲请求)时,所有未完成的对冲请求都会被取消,并将响应返回给客户端应用程序层。
如果从对冲请求收到带有非致命状态代码(由 nonFatalStatusCodes
字段控制)的错误响应,则会立即发送下一个对冲请求,从而缩短其对冲延迟。如果收到任何其他状态代码,则所有未完成的 RPC 都会被取消,并将错误返回给客户端应用程序层。
如果对冲 RPC 的所有实例都失败,则不会进行额外的重试尝试。本质上,对冲可以被视为在收到失败之前重试原始 RPC。
如果收到响应中指定的服务器回压不进行重试,则不应为该调用发出进一步的对冲请求。
限制对冲 RPC
gRPC 提供了一种限制对冲 RPC 以防止服务器过载的方法。也可以通过使用 RetryThrottlingPolicy
消息的服务配置来配置限制。限制配置包含以下内容
"retryThrottling": {
"maxTokens": 10,
"tokenRatio": 0.1
}
对于每个服务器名称,gRPC 客户端维护一个 token_count
,该 token_count
最初设置为 max_tokens
。每个传出的 RPC(无论调用哪个服务或方法)都会按如下方式更改 token_count
- 每个失败的 RPC 将使
token_count
减少1
。 - 每个成功的 RPC 将使
token_count
增加token_ratio
。
通过对冲,第一个请求始终会发送出去,但仅当 token_count
大于阈值(定义为 max_tokens / 2
)时才会发送后续的对冲请求。如果 token_count
小于或等于阈值,则对冲请求不会阻塞。相反,它们会被取消,并且如果没有其他已发送的对冲 RPC,则会将失败返回给客户端应用程序。
对于限制策略,唯一被计为失败的请求是那些因具有资格作为非致命状态代码的状态代码而失败或收到指示不重试的回压响应的请求。这避免了将服务器故障与对格式错误的请求的响应(例如 INVALID_ARGUMENT
状态代码)混淆。
服务器回压
服务器可以通过在其对客户端的响应中设置元数据来显式地进行回退(pushback)。如果回退指示不进行重试,则不会发送进一步的对冲请求。如果回退指示在给定的延迟后重试,则下一个对冲请求(如果有)将在给定的延迟时间过去后发出。
服务器回退使用元数据键 grpc-retry-pushback-ms
指定。该值是一个 ASCII 编码的有符号 32 位整数,没有不必要的前导零,表示在发送下一个对冲请求之前需要等待的毫秒数。如果回退的值为负数或无法解析,则会被视为服务器要求客户端完全不进行重试。
资源
语言支持
语言 | 示例 |
---|---|
Java | Java 示例 |
C++ | 尚未提供 |
Go | 尚未支持 |