パフォーマンスのベストプラクティス
パフォーマンスを向上させるための、一般的および言語固有のベストプラクティスに関するユーザーガイド。
パフォーマンスのベストプラクティス
一般
可能な限り、スタブとチャネルを再利用してください。
キープアライブPingを使用して、非アクティブ期間中にHTTP/2接続を維持し、初期RPCを遅延なく迅速に実行できるようにします(例:C++チャネル引数GRPC_ARG_KEEPALIVE_TIME_MS)。
クライアントからサーバー、サーバーからクライアント、またはその両方向の、長期にわたる論理的なデータフローを処理する場合は、ストリーミングRPCを使用してください。ストリームは、継続的なRPCの開始(クライアント側の接続ロードバランシング、トランスポートレイヤーでの新しいHTTP/2リクエストの開始、サーバー側でのユーザー定義メソッドハンドラーの呼び出しなど)を回避できます。
ただし、ストリームは一度開始されるとロードバランシングができなくなり、ストリーム障害のデバッグが困難になる場合があります。また、小規模ではパフォーマンスを向上させるかもしれませんが、ロードバランシングと複雑さのせいでスケーラビリティを低下させる可能性もあるため、アプリケーションロジックに substantial なパフォーマンスまたは単純化のメリットがある場合にのみ使用すべきです。ストリームはgRPCのためではなく、アプリケーションを最適化するために使用してください。
注記: これはPythonには適用されません(詳細はPythonセクションを参照)。
(特別トピック) 各gRPCチャネルは0個以上のHTTP/2接続を使用し、各接続は通常、同時ストリーム数に制限があります。接続上のアクティブなRPC数がこの制限に達すると、追加のRPCはクライアントでキューイングされ、送信される前にアクティブなRPCが終了するのを待つ必要があります。高負荷または長期間のストリーミングRPCを扱うアプリケーションでは、このキューイングによりパフォーマンスの問題が発生する可能性があります。2つの可能な解決策があります。
アプリケーション内の各高負荷領域に対して、個別のチャネルを作成してください。
gRPCチャネルのプールを使用して、RPCを複数の接続に分散させます(再利用を防ぐためにチャネルに異なるチャネル引数が必要です。したがって、チャネル番号などの使用固有のチャネル引数を定義してください)。
注記: gRPCチームは、これらのパフォーマンスの問題を修正するための機能を追加する予定です(詳細はgrpc/grpc#21386を参照)。したがって、複数のチャネルを作成するソリューションは、最終的には不要になる一時的な回避策です。
C++
パフォーマンスに敏感なサーバーではSync APIを使用しないでください。 パフォーマンスおよび/またはリソース消費が懸念されない場合は、低QPSサービスにとって実装が最も簡単なSync APIを使用してください。
アプリケーションがすべてのブロッキング操作を回避できる場合、またはブロッキング操作を別のスレッドに移動できる場合は、ほとんどのRPCでCallback APIを他のAPIよりも優先してください。Callback APIはCompletion-queue async APIよりも使いやすいですが、真に高QPSのワークロードでは現在遅いです。
async completion-queue APIを使用する必要がある場合は、
numcpuのスレッド数を持つことが、スケーラビリティのトレードオフとして最適です。スレッド数に対するcompletion queueの理想的な数は、gRPC C++の進化に伴って変化する可能性がありますが、gRPC 1.41(2021年9月)時点では、completion queueあたり2スレッドを使用すると最高のパフォーマンスが得られるようです。async completion-queue APIの場合、サーバーが継続的に遅いパスにスタックして、実質的にシリアルなリクエスト処理につながるのを避けるために、希望するレベルの同時実行性に対して十分なサーバーリクエストを登録してください。
(特別トピック) gRPC::GenericStubは、プロトシリアライゼーションで高い競合/CPU時間を費やす特定のケースで役立ちます。このクラスにより、アプリケーションはプロトから直接データをシリアライズするのではなく、生のgRPC::ByteBufferをデータとして直接送信できます。これは、同じデータが複数回送信される場合にも役立ちます。1回の明示的なプロトからByteBufferへのシリアライズの後、複数のByteBuffer送信を行います。
Java
RPCを並列化するために、非ブロッキングスタブを使用してください。
ワークロードに基づいてスレッド数を制限するカスタムエグゼキュータを指定してください(キャッシュ(デフォルト)、固定、フォークジョインなど)。
Python
ストリーミングRPCは、メッセージの送受信のために追加のスレッドを作成するため、gRPC Pythonでは、gRPCがサポートする他の言語とは異なり、ストリーミングRPCは単項RPCよりもはるかに遅くなります。
asyncioを使用するとパフォーマンスが向上する可能性があります。
同期スタックでFuture APIを使用すると、追加のスレッドが作成されます。可能な場合はFuture APIを避けてください。
(実験的) 実験的なシングルスレッド単項ストリーム実装が、SingleThreadedUnaryStreamチャネルオプションを介して利用可能であり、メッセージあたりのレイテンシを最大7%削減できます。