存根的 gRPC 并发

Posted

技术标签:

【中文标题】存根的 gRPC 并发【英文标题】:gRPC Concurrency for Stubs 【发布时间】:2020-03-24 14:14:43 【问题描述】:

在 gRPC 中,我想了解有关服务器处理请求方式的更多信息。

请求是否并行执行?或者服务器是否为每个请求生成一个新线程,并并行执行它们?有没有办法修改这种行为?我知道在客户端流式传输 rpc 中,消息顺序是有保证的。

如果我将请求 A 和请求 B 发送到同一个 RPC,是否可以保证 A 在 B 开始处理之前先执行?还是它们各自都有自己的线程并并行执行,不能保证 A 在 B 之前完成。

理想情况下,我想向服务器发送请求,服务器确认收到请求,然后将请求添加到队列中以按顺序处理,并在处理完毕后返回响应。我正在探索的一种方法是使用外部任务队列(如 RabbitMQ)对服务完成的工作进行排队,但我想知道是否有更好的方法。

另外——在一个有点相关的注释上——gRPC 是否有一个本机重试计数器机制?我有一个特别容易出错的 RPC,它可能必须重试多达 3 次(重试之间有任意延迟)才能成功。这也可以用 RabbitMQ 实现。

【问题讨论】:

【参考方案1】:

grpc-java 使用ServerBuilder.executor(Executor) 提供的Executor 将RPC 传递给服务,如果没有提供执行程序,则使用cached thread pool。

同时发生的 RPC 之间没有排序。 RPC 可以按任何顺序到达。

您可以使用服务器流式 RPC 来允许服务器响应两次,一次用于确认,一次用于完成。您可以在响应消息中使用oneof 来允许发送两个不同的响应。

grpc-java 作为实验性重试支持。 gRFC A6 描述了支持。配置通过服务配置传递给客户端。默认情况下重试是禁用的,所以总的来说你会想要channelBuilder.defaultServiceConfig(serviceConfig).enableRetry()这样的东西。也可以参考hedging example,与重试非常相似。

【讨论】:

谢谢!有没有办法将 RPC 本地设置为同步?这意味着服务器一次只执行一个,其余的等待?我可以在服务实现中使用某种锁定。 不,你不能让一个 RPC 等待另一个。您可以为executor() 使用单个线程,但这只会序列化回调,并且每个 RPC 都有多个回调,因此仍然可以重新排序。但是即使存在这样的事情,也没有什么需要首先接收您首选的 RPC。即使同时允许多个 RPC,您也应该能够使用锁定。 那么,例如在使用 proto 和 GRPC 的 Java 中,推荐的方法是锁定生成的“ImplBase”类的实现?只是想确认一下。 我不会说“推荐”,因为有许多可能的解决方案,它们的复杂性和适用性因您的服务而异。但是,是的,在扩展生成的 ImplBase 的类中使用锁就可以了。

以上是关于存根的 gRPC 并发的主要内容,如果未能解决你的问题,请参考以下文章

7.Go语言高并发与微服务实战 --- 远程过程调用 RPC

grpc客户端并发请求对端服务时,是否存在所谓连接池?

gRPC 中的通道/存根是线程安全的吗

csharp中的grpc通道/存根线程是不是安全

分布式高并发中,如何发挥gRPC的威力?来看看它的底层实现原理!

腾讯 Tars 开源 Go 版本 Tars-Go,并发性能比 gRPC 高 5 倍