Skip to content

gRPC + Goのhelloworldを試してみる

Posted on:2021年8月19日 at 00:00

Image from Gyazo

こんにちは、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/[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クライアントプログラムを実行して上記のような出力が得られれば成功です。

サンプルコードに変更を加えてみる

サンプルコードそのままは動かせたので、新しいエンドポイントを作ってみます。

  1. 定義ファイルを更新
  2. 定義ファイルから再生成
  3. サーバ側プログラムを修正
  4. クライアント側プログラムを修正
  5. 実行

という流れです。

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.gohelloworld/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も含めて何か個人開発してみようと思います。

参考

Footnotes

  1. この記事を書いている際に Go 1.16.6 にバージョンアップしたのですが、手順通り go install でインストールできました。