最終更新:

gRPCの仕組み — 遠くの「こんにちは」を呼び出すまで


契約を決めて、挨拶を頼む

呼び出し側:SayHello要求:name = ひよこ相手の実装で挨拶を作る応答:こんにちは、ひよこ
単項RPCの往復を時間の順に示しています。実際には要求と応答が逆方向に通信し、失敗時はステータスを受け取ります。
ひよこ ひよこ
遠くのサーバーに「こんにちは」を頼める?
ペンギン先生 ペンギン先生
gRPCではSayHelloのようなメソッドを呼び、名前を送り、挨拶を受け取れるよ。手元の関数に似た入口だけれど、裏ではネットワーク通信しているんだ。
ひよこ ひよこ
関数なら失敗しないの?
ペンギン先生 ペンギン先生
接続が切れたり、相手が応答しなかったりするよ。期限やステータスを扱う必要がある。呼び出す側が時間切れでも、相手の処理が絶対に未実行とは限らないんだ。
ひよこ ひよこ
お互いのデータ形式はどう決めるの?
ペンギン先生 ペンギン先生
一般的には.protoにメッセージとサービスを定義し、Protocol BuffersのコードとRPC用のコードを生成するよ。フィールドには番号があり、変更時にも互換性を考えるんだ。
ひよこ ひよこ
生成したらずれは完全になくなる?
ペンギン先生 ペンギン先生
同じ契約を使いやすくなるけれど、異なる版の配置や不適切なスキーマ変更、業務上の値の誤りは残るよ。番号の再利用を避け、入力内容と対応バージョンも確認するんだ。
ひよこ ひよこ
一度に何通も送れる?
ペンギン先生 ペンギン先生
単項は1回送って1回返る。サーバーストリーミングは1回の要求に複数の応答、クライアントストリーミングは複数の要求に1回の応答、双方向は双方がメッセージの列を送るよ。
ひよこ ひよこ
HTTP/2だから必ず速い?
ペンギン先生 ペンギン先生
gRPCの一般的な通信はHTTP/2を使い、一つの接続で複数のストリームを扱えるよ。ただし転送量、実装、DB処理やネットワーク次第で、必ずRESTより速いわけではない。RESTもHTTP/2を使えるんだ。
ひよこ ひよこ
ブラウザーでもそのまま呼べる?
ペンギン先生 ペンギン先生
通常のブラウザーAPIからネイティブgRPCを直接扱うのには制約があるよ。gRPC-Webなどの橋渡しを検討する。使えるストリーミングの種類は、その実装や転送方式も確認しよう。
ひよこ ひよこ
最初は何を覚えればいい?
ペンギン先生 ペンギン先生
契約を用意し、コードを生成して、相手を呼び、結果と失敗を受け取る流れだよ。Channelは通信先を扱い、Stubが呼び出し口になる。まず単項の挨拶から試すとつながりが分かるよ。

まず、呼び出しの契約を見る

「ひよこ」と送ると「こんにちは、ひよこ」と返す単項RPCを考えます。次は hello.proto の例です。

syntax = "proto3";
package hello;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest { string name = 1; }
message HelloReply { string message = 1; }

SayHello が遠隔呼び出しの入口、HelloRequest と HelloReply が送受信するメッセージの型です。1 は文字数や配列番号ではなく、フィールドの識別番号です。このファイルだけで挨拶の処理が動くわけではありません。

契約から、実装と呼び出しへ

Pythonなら独立した仮想環境に grpcio と grpcio-tools を追加し、生成します。

python -m pip install grpcio grpcio-tools
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. hello.proto

メッセージのコードとRPC用のコードができます。次にサーバー側で SayHello の処理を実装し、クライアント側ではChannelとStubを作って呼びます。起動から実行までを試す場合は、公式Pythonクイックスタートのサーバー・クライアントを使ってください。

このページのコードは契約と生成の入口です。通信先のアドレス、ポート、TLS設定、期限を確認してから実際のサーバーへ接続します。

4種類の通信を、回数で見分ける

パターン要求応答イメージ
Unary1メッセージ1メッセージ挨拶を一つ頼む
Server streaming1複数検索結果を順に受け取る
Client streaming複数1測定値を送り集計を受け取る
Bidirectional streaming複数複数互いにメッセージを送る

一つのストリーム内のメッセージ順は保たれます。双方向の二つの流れは独立しており、要求と応答が必ず一対一で交互になるわけではありません。

もう少し詳しく:期限と互換性

期限を設定して、待ち続ける呼び出しを避けます。標準では期限が設定されていない場合があるため、言語のAPIで指定方法を確認します。失敗した書き込みの再試行は、二重実行を避ける設計も必要です。

削除したprotobufのフィールド番号や名前は reserved にし、別の意味で再利用しないようにします。生成コードは業務ルールの正しさまで保証しません。

gRPCは型を共有したサービス間通信やストリーミングの候補です。ブラウザー対応、調査用ツール、運用、相手の対応方式も含めてRESTとの比較で選びましょう。

ペンギン先生のまとめ

「gRPC」って出てきたら「契約を決めて、遠くの処理を関数のように呼ぶ方法」と思えばだいたいOK! 通信なので、結果だけでなく期限と失敗も受け取るよ。

参考資料