重试 (Retry)

gRPC 消除了失败的压力!通过 OpenCensus 和 OpenTelemetry 支持,获得精细化的重试控制和详细的洞察。

概述

重试是使服务更加可靠的关键模式。通过重新尝试失败的操作,应用程序可以克服网络或服务器故障等暂时性问题。这对于现代云应用程序至关重要,帮助它们处理不可避免的瞬时故障。

最佳实践是,应用程序应了解哪些失败的操作适合重试,定义重试延迟的指数退避参数,确定重试尝试次数,并监控重试指标。

gRPC 客户端重试工作原理

gRPC 内建的重试逻辑会保存调用的历史记录,以便在需要时进行重试,并且会监控 RPC 事件。即使没有配置重试策略,gRPC 仍然会保存调用历史,以便在需要时执行透明重试(后续将讨论)。请注意,"重试" 指的是用新的调用替换失败的调用,并在新创建的调用上重放该调用的历史记录。

如果满足某些条件 —— RPC 以匹配重试策略的可重试状态码关闭,并且在重试尝试限制范围内 —— gRPC 会在指数退避延迟后创建新的重试流。

gRPC 还支持其他特性,如重试限流和服务器推送回退。有关更多详细信息,请参考 gRFC 客户端重试文档。

一旦收到响应头,RPC 就会被提交。不会再进行进一步的重试,gRPC 会将 RPC 交给应用程序。

以下是 gRPC 内部重试的架构概览:

image 2024 12 24 12 05 05 596

重试配置

重试默认是启用的,但没有默认的重试策略。如果没有配置重试策略,gRPC 在大多数情况下无法安全地重试 RPC。只有由于低级竞争条件(race conditions)导致的失败才会进行重试,且仅当 gRPC 确定 RPC 没有被服务器处理时,才会进行这种 “透明重试”(transparent retry)。您可以配置重试策略,允许 gRPC 在更多情况下和更积极地进行重试。您还可以在创建通道时完全禁用重试,这将禁用透明重试及任何配置的重试策略。

透明重试

故障可能发生在不同阶段。即使没有明确的重试策略,gRPC 也可能执行透明重试。透明重试的程度取决于故障发生的时机:

  • 如果 RPC 从未离开客户端,gRPC 可能会执行无限次的透明重试。

  • 如果 RPC 达到 gRPC 服务器库,但从未被服务器应用程序逻辑处理过,gRPC 会执行一次透明重试。需要注意的是,这种重试会给网络带来额外的负担。

您可以通过关注 gRPC 支持的关键步骤和配置来优化应用程序的重试功能。

  • 最大重试次数

  • 指数退避

  • 可重试的状态码集合

重试可以通过 gRPC 服务配置进行配置,按方法粒度进行。配置包含以下选项:

"retryPolicy": {
  "maxAttempts": 4,
  "initialBackoff": "0.1s",
  "maxBackoff": "1s",
  "backoffMultiplier": 2,
  "retryableStatusCodes": [
    "UNAVAILABLE"
  ]
}

为了避免大量客户端同时对服务器造成压力,退避延迟会应用正负 20% 的抖动。在上述示例配置中,initialBackoff 设置为 100 毫秒,因此第一次重试后的实际退避延迟将在 [80ms, 120ms] 的范围内随机选择。

gRPC 支持重试的限流配置,以防止由于重试导致服务器过载。以下是重试限流配置的示例:

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

对于每个服务器,gRPC 客户端跟踪一个 token_count(初始值为 maxTokens)。失败的 RPC 会使计数减少 1,成功的 RPC 会使计数增加 tokenRatio。如果 token_count 低于 maxTokens 的一半,重试将暂停,直到计数恢复。

此外,Hedging(请求调度)是重试的一个补充特性,并且可以类似地进行配置。有关更多详细信息,请参阅 Hedging 指南

重试可观察性

当启用重试功能时,gRPC 支持暴露 OpenCensus 和 OpenTelemetry 度量指标。以下是 OpenTelemetry 提供的重试尝试统计信息示例:

  • grpc.client.attempt.started

  • grpc.client.attempt.duration

  • grpc.client.attempt.sent_total_compressed_message_size

  • grpc.client.attempt.rcvd_total_compressed_message_size

每个调用级别的度量指标:

  • grpc.client.call.duration

以及服务器端度量指标:

  • grpc.server.call.started

  • grpc.server.call.sent_total_compressed_message_size

  • grpc.server.call.rcvd_total_compressed_message_size

  • grpc.server.call.duration

有关深入的指标和追踪信息,以及配置说明,请参阅 gRFC 中的 Otel 指标重试状态

语言指南和示例

语言 示例 文档

C++

Go

Go 示例

Java

Java 示例

Java 文档

Python

Python 示例