gRPC + Goのhelloworldを試してみる
こんにちは、shootaceanです。
実務でWEBサービスのリアーキテクチャが進もうとしているので、気になっていたgRPCを学習してみます。
基本的にgrpc.ioのクイックスタートの手順で進めたのですが、エラーなどで手順どおりにならない部分もあったので、その点も含めて書いていきます。
https://grpc.io/docs/languages/go/quickstart/
前提
$ 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/protoc-gen-go@v1.26 $ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
上記のコマンドで以下のエラーが発生する場合があります。
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/protoc-gen-go-grpc@v1.1 または $ 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
-
この記事を書いている際に
Go 1.16.6
にバージョンアップしたのですが、手順通りgo install
でインストールできました。↩