概要
GolangでgRPCに入門する。
gRPCとは
gRPCとは、Googleが開発したRPC※実現のためのプロトコル。HTTP/2の利用を前提としている。
gRPCではGoogleが開発しているProtocol BuffersというIDL(インターフェース定義言語)でAPI仕様を定義するシリアライズフォーマットを使用する。
gRPCの通信方式にはHTTP/2の仕様に則った4つのパターンがある。
- Unary RPCs
- 1リクエスト1レスポンス
- Server Streming RPCs
- 1リクエスト複数レスポンス
- サーバープッシュ(HTTP/2の仕組みで、コンテンツをサーバーからプッシュすることができる)型の実装に利用できる
- Client Streaming RPCs
- 複数リクエスト1レスポンス
- サーバーはリクエストが完了するまでレスポンスを返さず、ストリームからメッセージを読み続ける
- Duplex Streaming RPCs
- 複数リクエスト複数レスポンス
- 双方向ストリーミング
gRPCのメリットについては以下のような点がある。
- Protocol Buffersによる送信データのシリアライズ(バイナリに変換される)により、送信データ量が圧縮され、通信の高速化になる
- HTTP/2の恩恵
- HTTP1.1とよりもヘッダ部が圧縮される(HTTP1.1はヘッダ部が大きい分、ボディ部が小さい)
- ステートフルな通信の実現
- バイナリベース
- リクエストやレスポンスや「フレーム」と呼ばれるバイナリの通信プロトコルを利用しているため、テキストの解析が効率化され、通信の高速化につながった
- ストリーミング
- 1つのTCPコネクションで複数のHTTPリクエストとレスポンスを並列に処理することができる
- IDLでのAPI定義により、特定のプログラミング言語への依存無い
- IDLが最新のインターフェース仕様となるため、ソースコードとAPI仕様書の乖離が減る
- IDLからのコード自動生成による実装コスト削減
一方でデメリットについては以下のような点が考えられる。
- HTTP/2のみのサポート
- grpc-gatewayを利用するとHTTP1.1も対応できるらしい。HTTP3についてもproxyでとりあえずワークアラウンドな解決ができる? cf.medium.com - gRPC over HTTP/3
- API定義をわかりやすいUIなどで出力するツールがない(Swaggerのようなツール)
- OSSとかでいい感じのツールあるかも?
- データの受信側はデータのデシリアライズが必要
- データがシリアライズされているため、通信内容の監視がしづらい
- デバッグ辛そう?
上記のようなメリット・デメリットからマイクロサービス間の通信などでよく採用されているケース(通信速度や複数言語の採用など相性が良い)が見受けられる。
※RPCについてはWikipediaの一文を引用する。
遠隔手続き呼出し(英: remote procedure call、リモートプロシージャコール、略してRPC)とは、プログラムから別のアドレス空間(通常、共有ネットワーク上の別のコンピュータ上)にあるサブルーチンや手続きを実行することを可能にする技術
感覚的な説明を加えるとすると、「あるホストから別のホスト上のプログラム定義されたメソッドを実行することができる」というな感じだろうか。この辺はコードを見るとわかりやすかと思う。
GolangでgRPCに入門
ソースコードはgithub.com - golang-grpc-example
準備
前提として、Golangのバージョンは1.6以上である必要ある。
gRPCのインストール
go get -u google.golang.org/grpc
Protocol Buffers v3のインストール(Mac以外の場合はgithub.com/protocolbuffers/protobuf/releases
を参照)
brew install protobuf
Golangのprotocプラグインをインストール
go get -u github.com/golang/protobuf/protoc-gen-go
インターフェース定義
protoにAPI定義をする。
pkg/proto/user/user.proto
インターフェース定義からコードの自動生成
protoc --go_out=plugins=grpc:./ user.proto
上記を実行すると以下のコードが生成される。
pkg/proto/user/user.pb.go
ドキュメントを生成したい場合は、github.com - pseudomuto/protoc-gen-docというツールを使うと便利。
サービスの実装
user.pb.goの以下のインターフェースを満たすようにサービス(実処理部分)を実装していく。
pkg/proto/user/user.pb.go
user_service.go
サーバーとクライアントの実装
user.pb.goを参照して、サーバーとクライアントを実装する。
server/main.go
client/main.go
動作確認
サーバー起動
go run server/main.go
クライアント実行
go run client/main.go
所感
何となくの雰囲気は掴めた。 コード生成で楽ができるのでAPIの本質的な部分に集中しやすそう。 テストやデバッグ周りは少し慣れが必要になのかなという印象。