Google' S GRPC是一个支持许多语言的RPC系统,并且相对广泛地使用。我认为它的受欢迎程度是由于用于Docker和Kubernetes的部分。我认为GRPC大多是很好的,但通过错误配置它令人惊讶地搞砸了。部分是因为RPC系统有挑战性。他们需要对各种各样的服务有用,从高索取率服务范围内,这些服务每秒处理数千个小型请求,需要传输大量数据的服务,或者具有数千个并发,慢速请求的服务需要几分钟的服务去完成。结果,GRPC等RPC系统需要非常可配置。不幸的是,以一种导致难以理解的错误的方式配置它也很容易。
此博客文章的其余部分将描述我最近遇到的令人讨厌的边缘案例的两个例子。我浪费了一天时间来调试并理解这些。主要是我希望如果别人遇到这些错误,他们会发现这篇文章,我可以节省时间。我也希望通过改进错误消息和记录最佳实践,GRPC团队最终将使此库更易于使用此库。
GRPC旨在重用TCP连接以获取多个请求。但是,许多网络终止了空闲时间过长的连接。例如,AWS NLB TCP负载均衡器具有350秒的超时。 TCP具有可选的核心机制。在Linux上默认启用它,但在发送第一个Keepalive之前,使用2小时超时。这对于清理长死连接是有用的,但不能通过NAT或负载均衡器保持这些连接。默认情况下,Go将TCP Keepalives配置为15秒,这应该通常足以保持网络连接。
不幸的是,TCP KeekAlives对应用程序是看不见的,可能不受某些操作系统的支持。因此,GRPC有自己的keepalives。但是,GRPC客户端Keepalive规范本身表示:"客户作者必须与服务主协调,以便是否可以接受特定客户端设置和#34;如果客户端经常发送Keepalive Ping,则服务器关闭连接。这是为了防止大量空闲客户端消耗太多资源。如果RPC调用处于活动状态,则默认为允许每5分钟一次。
在我看来,这意味着这个设置几乎无法使用,应该避免。某些负载均衡器的服务器默认值不足(例如Azure' S TCP Load Balancer默认情况下4分钟后丢弃空闲连接)。很容易出错,部署更具侵略性的配置。您必须首先部署所有服务器以允许更激进的ping,那么您需要部署客户端。如果您想撤消它,您需要执行相反的操作:首先将客户端部署到Ping少,然后部署服务器。如果您拧紧此订单,或进行配置错误,则会收到间歇性"运输正在关闭"错误。作为替代方案,始终在GRPC请求上设置截止日期,并使用合理的重试策略。如果这是困难的,那么您可以在服务器上设置Keepalive,这避免了大多数问题。我写了一个长的错误报告,要求改进GRPC文档,所以希望其他人可以避免我的错误。
对于那些可能遇到此错误的其他人,当客户端KeepAlive过于激进时,客户RPC将失败,GRPC代码不可用(14)和消息"运输正在关闭"解决方案是删除客户端keepalive配置。如果启用详细的GRPC日志,您将看到:
错误:2021/03/14 11:02:26运输:从客户端的乒乓球,关闭连接。
如果从GRPC请求返回错误,则返回状态代码,状态消息(Unicode字符串)和可选错误详细信息(未被记录但库支持)。那么当服务器意外返回一个非常大的错误消息时会发生什么?不幸的是,连接可能会关闭。通常,您只能在GRPC错误消息中返回最多约7个Kib(如果使用可选的错误详细信息,则为3 Kib)。这应该很多。但是,如果您的错误消息打印了可变长度数据结构,则正确的请求可能导致超出此限制。这就是我遇到这个问题的方式。解决方案是退回更短的错误消息。我还添加了GRPC服务器拦截器来截断错误,以确保我不小心再次这样做了。
默认情况下,GO GRPC实现默认为将错误消息限制为16个MIB。如果您超过此限制,请在客户端上,您将看到两个错误之一。在服务器上,您将看到任何内容,因为就知道,它正确地返回了错误。
C客户端将错误消息限制为8个Kib。如果超出此限制,则在客户端上,您将看到两个错误中的一个,具体取决于服务器是GO或C服务器。
错误:2021/03/05 10:13:18 [传输]标题列表大小发送违反客户端设置的最大大小(8192字节)