非常に高速でメッセージを転送するサービスがあります。
現在、それはakka-tcpによって提供され、1分あたり350万のメッセージを作成します。grpcを試してみることにしました。残念ながら、その結果、スループットははるかに小さくなりました。1分あたり約50万メッセージはさらに少なくなります。
それを最適化する方法をお勧めしていただけませんか?
私のセットアップ
ハードウェア:32コア、24 Gbヒープ。
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:BLOCKED(オブジェクトモニター上)com.google.common.io.ByteStreams.createBuffer(ByteStreams.java:58)at com.google.common.io.ByteStreams.copy(ByteStreams.java: 105)io.grpc.internal.MessageFramer.writeUncompressed(MessageFramer.javaでio.grpc.internal.MessageFramer.writeKnownLengthUncompressed(MessageFramer.java:230)でio.grpc.internal.MessageFramer.writeToOutputStream(MessageFramer.java:274)に:168)io.grpc.internal.MessageFramer.writePayload(MessageFramer.java:141)at io.grpc.internal.AbstractStream.writeMessage(AbstractStream.java:53)at io.grpc.internal.ForwardingClientStream.writeMessage(ForwardingClientStream。 java:37)io.grpc.internal.DelayedStream.writeMessage(DelayedStream.java:252)at io.grpc.internal。ClientCallImpl.sendMessageInternal(ClientCallImpl.java:473)at io.grpc.internal.ClientCallImpl.sendMessage(ClientCallImpl.java:457)at io.grpc.ForwardingClientCall.sendMessage(ForwardingClientCall.java:37)at io.grpc.ForwardingClientCall.sendMessage (ForwardingClientCall.java:37)at io.grpc.stub.ClientCalls $ CallToStreamObserverAdapter.onNext(ClientCalls.java:346)
高スループットのgrpcクライアントを構築するためのベストプラクティスに関する支援があれば幸いです。
scalapb
。おそらく、このスタックトレースは実際にscalapb生成コードからのものでした。私はscalapbに関連するすべてのものを削除しましたが、それはwrtパフォーマンスにあまり役立ちませんでした。