请求对冲
解释了请求对冲是什么以及如何配置它。
请求对冲
概述
对冲是 gRPC 支持的两种可配置重试策略之一。通过对冲,gRPC 客户端将同一请求的多个副本发送到不同的后端,并使用它收到的第一个响应。随后,客户端会取消所有未完成的请求,并将响应转发给应用程序。
用例
对冲是一种在大规模分布式系统中减少尾部延迟的技术。虽然简单实现可能会给后端服务器增加显著负载,但可以在适度增加负载的情况下获得大部分延迟减少效果。
有关尾部延迟的深入讨论,请参阅 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_count
减1
。 - 每个成功的 RPC 会将
token_count
增加token_ratio
。
对于对冲,第一个请求总是会发送出去,但后续的对冲请求只有在 token_count
大于阈值(定义为 max_tokens / 2
)时才会发送。如果 token_count
小于或等于阈值,对冲请求不会阻塞。相反,它们会被取消,并且如果没有其他已经发送的对冲 RPC,则失败会返回给客户端应用程序。
对于限制策略,只有以符合非致命状态码的状态码失败的请求,或者收到指示不重试的回压响应的请求,才算作失败。这避免了将服务器失败与对格式错误请求的响应(例如 INVALID_ARGUMENT
状态码)混淆。
服务器回压
服务器可以通过在其对客户端的响应中设置元数据来明确回压。如果回压指示不重试,则不会发送进一步的对冲请求。如果回压指示在给定延迟后重试,则下一个对冲请求(如果有)将在给定延迟过去后发出。
服务器回压使用元数据键 grpc-retry-pushback-ms
指定。该值是一个 ASCII 编码的带符号 32 位整数,没有不必要的零前缀,表示在发送下一个对冲请求之前需要等待多少毫秒。如果回压值为负或无法解析,则将被视为服务器要求客户端完全不重试。
资源
语言支持
语言 | 示例 |
---|---|
Java | Java 示例 |
C++ | 暂不可用 |
Go | 暂不支持 |