こんにちは、shootaceanです。
実務でWEBサービスのリアーキテクチャが進もうとしているので、気になっていたgRPCを学習してみます。
基本的にgrpc.ioのクイックスタートの手順で進めたのですが、エラーなどで手順どおりにならない部分もあったので、その点も含めて書いていきます。
https://grpc.io/docs/languages/go/quickstart/
前提
- macOS Catalina 10.15.7
- zsh
- go: 1.16.6
1.15.5
- protoc: 3.17.3
$ echo $SHELL
/bin/zsh
$ go version
go version go1.16.6 darwin/amd64
$ protoc --version
libprotoc 3.17.3
Procol Bufferのコンパイラをインストールする
Protocol Buffersのコンパイラ protoc
をインストールします。
$ brew install protoc
gRPCのGoプラグインをインストールする
$ go install google.golang.org/protobuf/cmd/[email protected]
$ go install google.golang.org/grpc/cmd/[email protected]
上記のコマンドで以下のエラーが発生する場合があります。
cannot use path@version syntax in gopath mode
私の場合は、go get
でインストールすることで、解決できました。1
$ go get -u google.golang.org/protobuf/cmd/protoc-gen-go
$ go get -u google.golang.org/grpc/cmd/protoc-gen-go-grpc
サンプルコードを実行してみる
サンプルコードが公開されているので git clone します
$ git clone -b v1.35.0 https://github.com/grpc/grpc-go
$ cd grpc-go/examples/helloworld
gRPCサーバープログラムを実行します。
$ go run greeter_server/main.go
別のターミナルでgRPCクライアントプログラムを実行します。
$ go run greeter_client/main.go
2021/08/19 20:30:00 Greeting: Hello world
gRPCクライアントプログラムを実行して上記のような出力が得られれば成功です。
サンプルコードに変更を加えてみる
サンプルコードそのままは動かせたので、新しいエンドポイントを作ってみます。
- 定義ファイルを更新
- 定義ファイルから再生成
- サーバ側プログラムを修正
- クライアント側プログラムを修正
- 実行
という流れです。
Protocol Buffersファイルを修正する
gRPCプログラムを変更する場合は、まず IDLであるProtocol Buffersの .proto
ファイルを修正します。
今回のサンプルコードであれば、helloworld/helloworld.proto
ファイルを修正します。
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
// 以下2行を追加する
// Sends another greeting
rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
}
修正できたらProtocol Buffersからgoプログラムを再生成します。
helloworld/helloworld.pb.go
と helloworld/helloworld_grpc.pb.go
の2ファイルが再生成されます。
$ protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
helloworld/helloworld.proto
上記のコマンド実行時に以下のエラーが発生した場合は、
前手順の protoc-gen-go-grpc
のインストールが漏れているので、インストールしてください。
protoc-gen-go-grpc: program not found or is not executable
Please specify a program using absolute path or make sure the program is available in your PATH system variable
--go-grpc_out: protoc-gen-go-grpc: Plugin failed with status code 1.
$ go install google.golang.org/grpc/cmd/[email protected]
または
$ go get -u google.golang.org/grpc/cmd/protoc-gen-go-grpc
gRPCサーバープログラムを修正する
helloworld/greeter_server.go
を修正します。
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
// ここを追加する
func (s *server) SayHelloAgain(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: "Hello again " + in.GetName()}, nil
}
gRPCクライアントプログラムを修正する
helloworld/greeter_client.go
を修正します。
main関数の最後に追記します。
func main() {
// 省略
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
// ここを追加する
r, err = c.SayHelloAgain(ctx, &pb.HelloRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
}
実行する
$ go run greeter_client/main.go Alice
2021/08/19 21:17:00 Greeting: Hello Alice
2021/08/19 21:17:00 Greeting: Hello again Alice
無事に変更点が反映されて、問題なくクライアントからサーバー関数を呼び出せています!
まとめ
gRPCはもっととっつきにくい技術かと思っていたのですが、実際に手を動かしてみると思っていたよりも簡単に試すことができました。
マイクロサービスでのサービス間通信で使われていることが多いようですが、gRPC-webでブラウザとサーバー間の通信にも利用できるようになりつつあるので、大部分の通信をgRPCで完結することもできそうです。
何よりもProcol BufferというIDLによるスキーマ駆動開発の恩恵が大きいと感じました。 REST APIでもSwaggerなどでOpen APIに沿ってのコード自動生成は可能ですが、通信方法であるgRPCとIDLであるProtocol Buffersの密接な関係により、開発時のモック用意など、よりスキーマ駆動開発がやりやすい印象です。
Goのシンプルな構文とProtocol BuffersのIDLによって、チームでの開発もやりやすそうですね。 個人的にもかなり興味がある分野なので、gRPC-webも含めて何か個人開発してみようと思います。
参考
- Basics tutorial | Go | gRPC
- Ubuntu 16.04でGOPATHエラー「go:GOPATHモードでpath @version構文を使用できません」を取得-スタックオーバーフロー
- プロトコルバッファ-protoc-gen-go-grpc:プログラムが見つからないか実行可能ではありません-スタックオーバーフロー
- Go Generated Code | Protocol Bufferss | Google Developers
Footnotes
-
この記事を書いている際に
Go 1.16.6
にバージョンアップしたのですが、手順通りgo install
でインストールできました。 ↩