gRPC

2022.08.04
gRPCについて
protobufとgRPC
gRPCはRemote Procedure Call(ネットワーク越しのメソッド呼び出し)を実現するためにGoogleが開発したプロトコルです。protobufはデータフォーマットの1種です。
よく使われる通信プロトコルとしては他に
- REST API + JSON
- GraphQL
があります。REST APIとgRPCが, protobufとJSONが対応していると考えると分かりやすいです。 gRPC + protobuf を採用するメリットはprotobufが軽量で速い, gRPCがHTTP/2で速い, よって合わせるととても速い...ここに尽きると思います。
実装の流れ
- protoファイルにprotocol bufferでserviceを定義
- protocコマンドでコードを生成
- 自動生成されたコードをインターフェースとして実装
サンプルと解説
protoファイルを定義
/proto/service.proto
に以下のファイルを定義。
syntax = "proto3";
option go_package = "<module_path>"; // これがないとコードが生成されない
package <package name>;
service SampleService {
rpc CreateSample(CreateSampleRequest) returns (SampleResponse);
}
message CreateSampleRequest {
string key1 = 1;
string key2 = 2;
}
message SampleResponse {
string status = 1;
string description = 2;
}
コード生成
/proto
ディレクトリ内で
$ protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
service.proto
を実行すると/proto
内にservice.pb.goとservice_grpc.pb.goの2つのファイルが生成されます。
service.pb.goはクライアント側, service_grpc.pb.goにはサーバー側で使うgoのコードが生成されており、これを使って実装していきます。
grpcurl
grpcはHTTP/2で速いと先ほど書きました。そのためせっかくサーバー側を実装してもHTTP/1.1までしか対応していないcurlでは呼び出すことができません。そこでcurlのようにgrpcを呼び出せるgrpcurlを紹介します。
$ grpcurl -plaintext -d '{"key1": "value1", "key2":"value2"}' localhost:<port> <package name>.SampleService/CreateSample
のように呼び出せます。
streaming RPC
gRPCがHTTP/2で実装されていると何回も繰り返し述べてきましたがHTTP/2がHTTP/1.1の大きな違いをご存知でしょうか? それは「ストリーム」という概念でこれによって1つのTCPコネクション内で並行して複数のリクエスト/レスポンスが処理できるようになりました。当然gRPCでも明示的にstreamを使うことができます。
Server-side streaming RPC
クライアントからのrequestがstreamか、サーバーからのresponseがstreamかでRPCは4つに大別できます。詳細はgRPC Basic Tutotialに譲りますがこのTutorialからServer-side streaming RPCを紹介します。 Server-side streaming RPCはクライアントからのリクエストを元にサーバーがstreamを返すRPCのことです。以下がサーバーの実装例です。
func (s *routeGuideServer) ListFeatures(rect *pb.Rectangle, stream pb.RouteGuide_ListFeaturesServer) error {
for _, feature := range s.savedFeatures {
if inRange(feature.Location, rect) {
if err := stream.Send(feature); err != nil {
return err
}
}
}
return nil
}
このようにサーバー側ではクライアントのリクエストの他にstreamを受け取り、stream.Send()を呼び出すごとにレスポンスを返しています。最後に手続きが終わったと知らせる目的でnilをreturnする必要があります。
まとめ
gRPCについて一通り紹介しました。gRPCには一通りミドルウェアも揃っているようなのでこのあたりも試そうと思います。
参考サイト
protobufスキーマとgRPC通信 gRPC Basic Tutotial github.com/fullstorydev/grpcurl 普及が進む「HTTP/2」の仕組みとメリットとは