截止日期(Deadlines)

解释了如何使用截止日期来有效处理不可靠的后端。

概述

截止日期用于指定一个时间点,超过该时间点客户端将不再等待服务器的响应。这个简单的概念在构建健壮的分布式系统时非常重要。客户端不再不必要地等待,服务器知道何时停止处理请求,将改善系统的资源利用率和延迟。

请注意,虽然一些语言 API 使用 截止日期 的概念,但其他语言使用的是超时(timeout)的概念。当 API 请求截止日期时,您提供一个时间点,表示调用不应超过该时间点。超时是调用所能持续的最大时间。通过将超时加到应用程序启动调用的当前时间,可以将超时转换为截止日期。为了简单起见,本文件中将只提到截止日期。

客户端的截止日期

默认情况下,gRPC 不会设置截止日期,这意味着客户端可能会无限期地等待响应。为了避免这种情况,您应该始终在客户端明确设置一个合理的截止日期。为了确定合适的截止日期,您应该根据对系统的了解(如网络延迟、服务器处理时间等)进行合理的猜测,并通过负载测试来验证。

如果服务器在处理请求时超过了截止日期,客户端将放弃并以 DEADLINE_EXCEEDED 状态失败 RPC。

服务器的截止日期

服务器可能会接收到一个客户端设置的过短截止日期,这样服务器根本没有足够的时间及时响应。这会导致服务器浪费宝贵的资源,并在最坏的情况下导致服务器崩溃。gRPC 服务器通过在客户端设置的截止日期过期后自动取消调用(CANCELLED 状态)来处理这种情况。

请注意,服务器应用程序负责停止为服务 RPC 启动的任何活动。如果您的应用程序正在运行一个长期进程,您应定期检查发起 RPC 的调用是否已被取消,如果是,停止处理。

截止日期的传播

如果您的服务器需要调用另一个服务器以生成响应,那么在这种情况下,您的服务器也充当客户端,您会希望遵循原始客户端设置的截止日期。将截止日期从传入的 RPC 自动传播到传出的 RPC 是某些 gRPC 实现所支持的功能。在某些语言中,您需要显式启用此行为(例如 C++),而在其他语言中,它是默认启用的(例如 Java 和 Go)。使用此功能可以避免在每个传出 RPC 中手动包含截止日期的错误方法。

由于截止日期是一个时间点,将其直接传播到服务器可能会有问题,因为两台服务器的时钟可能不同步。为了解决这个问题,gRPC 将截止日期转换为超时,并从中扣除已过去的时间。这可以避免时钟偏差问题。

image 2024 12 24 09 56 25 941

语言支持

语言 示例

Java

Java 示例

Go

Go 示例

C++

Python

Python 示例