[翻译]gRPC与deadlines
Contents
gRPC 与 Deadlines
TL;DR(Too long, Don’t read 的首字母缩写, 也用于句首的消息摘要): 总是设置 deadline
. 这篇文章解释了为什么我们建议要有意设置 deadlines
, 以及展示了一些代码片断来告诉如何设置.
当你使用 gRPC 时, gRPC 库会负责通信, 编码, 解码以及强制执行 deadline
. Deadlines
允许 gRPC 客户端在 RPC 以一个错误 DEADLINE_EXCEEDED
终止之前愿意为 RPC 完成而等待多长时间. 默认情况下 deadline
是一个非常大的数值, 取决于特定语言的实现. 如何指定一个 deadlines
也是取决语言的. 一些语言的 API 使用术语 deadline
, RPC 应该在某个固定的时间点就要完成. 其他的语言使用 timeout
, 它是一个时间段, 即 RPC time out 了.
通常, 当你不设置 deadline
时, 则所有正在进行请求所持有的资源都将保留, 并且所有请求都有可能达到最大的 timeout .这会导致服务会处于一个耗尽资源的危险中(例如内存), 这会导致服务增加延时, 最坏的情况下, 整个服务都会崩溃掉.
为了避免这种情况, 服务应该指定它们在技术支持上最长的默认的 deadline
, 以及客户端应该等到响应不再对它们有用时为止. 对于该服务, 可以像在 .proto
文件中提供注释一样简单. 对于客户端来说, 这涉及设置一个常用的 deadline
.
“什么是一个好的 deadline/timeout 值?” 这并没有单一的答案. 你的服务可能像我们的快速开始指南中的 Greeter 那样简单, 这种情况下 100 ms 是个比较好的值. 你的服务可能跟一个全局分布式以及强一致数据库那样复杂. 对于一个客户端查询所设置的 deadline
将会有所不同于应该为删除它们的表要等待多久.
那么你需要考虑如何在 deadline
作出明智的选择? 要考虑的因素包含整个系统的端到端的延迟, 哪些 RPC 是串行的, 哪些是并行的. 你应该能够估算一个大概的数字, 尽管它是一个粗略的计算. 工程师需要了解该服务, 然后为客户端和服务器之间设置一个有意的 deadline
在 gRPC 中, 客户端和服务器都对远程调用 (RPC) 是否成功进行了独立的本地判断. 这意味着它们的结论可能不匹配! 在服务器成功完成的 RPC 可能会在客户端发生故障. 例如,服务器可以发送回复, 但回复可以在 deadline
过期后达到客户端. 客户端已经以状态错误 DEADLINE_EXCEDED
终止. 这应该在应用程序级别检查和管理.
设置一个 deadline
对于客户端来说, 应该总是设置一个
deadline
来表示你将会愿意等待多久从服务器中得到一个回复.
Go
clientDeadline := time.Now().Add(time.Duration(*deadlineMs) * time.Millisecond)
ctx, cancel := context.WithDeadline(ctx, clientDeadline)
java
response = blockingStub.withDeadlineAfter(deadlineMs, TimeUnit.MILLISECONDS).sayHello(request);
检测 deadline
在服务器端, 服务器可以查询一个特定的 RPC 是否不再需要了. 在服务器开始响应之前去检测是否仍有一个客户端在等待它, 这是非常重要的. 这对于开始一些昂贵(译注: 即耗时或耗资源之类的操作)的操作之间特别重要.
Go
if ctx.Err() == context.Canceled {
return status.New(codes.Canceled, "Client cancelled, abandoning.")
}
Java
if (Context.current().isCancelled()) {
responseObserver.onError(Status.CANCELLED.withDescription("Cancelled by client").asRuntimeException());
return;
}