首页 > 解决方案 > GRPC:用 Java/Scala 制作高吞吐量客户端

问题描述

我有一项以相当高的速率传输消息的服务。

目前它由 akka-tcp 提供服务,每分钟发送 350 万条消息。我决定试一试grpc。不幸的是,它导致吞吐量小得多:每分钟约 500k 条消息甚至更少。

你能推荐一下如何优化它吗?

我的设置

硬件:32 核,24Gb 堆。

grpc 版本:1.25.0

消息格式和端点

消息基本上是一个二进制 blob。客户端将 100K - 1M 和更多消息流式传输到同一个请求(异步),服务器不响应任何内容,客户端使用无操作观察器

service MyService {
    rpc send (stream MyMessage) returns (stream DummyResponse);
}

message MyMessage {
    int64 someField = 1;
    bytes payload = 2;  //not huge
}

message DummyResponse {
}

问题:与 akka 实现相比,消息率较低。我观察到 CPU 使用率很低,所以我怀疑 grpc 调用实际上在内部阻塞,尽管它另有说明。打电话onNext()确实不会立即返回,但桌面上也有 GC。

我试图产生更多的发件人来缓解这个问题,但没有得到太大的改进。

我的发现 Grpc 在序列化它时实际上为每条消息分配了一个 8KB 字节的缓冲区。查看堆栈跟踪:

java.lang.Thread.State:在 com.google.common.io.ByteStreams.createBuffer(ByteStreams.java:58) 在 com.google.common.io.ByteStreams.copy(ByteStreams.java: 105) 在 io.grpc.internal.MessageFramer.writeToOutputStream(MessageFramer.java:274) 在 io.grpc.internal.MessageFramer.writeKnownLengthUncompressed(MessageFramer.java:230) 在 io.grpc.internal.MessageFramer.writeUncompressed(MessageFramer.java :168) io.grpc.internal.MessageFramer.writePayload(MessageFramer.java:141) io.grpc.internal.AbstractStream.writeMessage(AbstractStream.java:53) io.grpc.internal.ForwardingClientStream.writeMessage(ForwardingClientStream. java:37) 在 io.grpc.internal.DelayedStream.writeMessage(DelayedStream.java:252) 在 io.grpc.internal。ClientCallImpl.sendMessageInternal(ClientCallImpl.java:473) 在 io.grpc.internal.ClientCallImpl.sendMessage(ClientCallImpl.java:457) 在 io.grpc.ForwardingClientCall.sendMessage(ForwardingClientCall.java:37) 在 io.grpc.ForwardingClientCall.sendMessage (ForwardingClientCall.java:37) 在 io.grpc.stub.ClientCalls$CallToStreamObserverAdapter.onNext(ClientCalls.java:346)

任何有关构建高吞吐量 grpc 客户端的最佳实践的帮助表示赞赏。

标签: javascalagrpc

解决方案


ManagedChannel我通过为每个目的地创建多个实例解决了这个问题。尽管文章说 aManagedChannel本身可以产生足够多的连接,所以一个实例就足够了,但在我的情况下并非如此。

性能与 akka-tcp 实现相当。


推荐阅读