Go言語でgRPCをやることになったので、勉強を兼ねてHello Worldレベルの簡単なものを作ってみます。
gRPCとは
リモートプロシージャコール(RPC)用のフレームワークで、Googleによって次世代版として開発されたものです。 gRPCのgはGoogleのことを指していたという説もあるようですが、現在では何も意味していないそうです。
プロシージャコールとは
gRPCの前にRPCやプロシージャコール(PC)というものがありますが、まずはプロシージャコールについて説明します。 プロシージャコールと聞くと、何か難しいことをしているように聞こえますが、簡単に言ってしまうと以下のプログラムような関数を呼び出すことです。
package main import "fmt" func add(a int, b int) int { return a + b } func main() { result := add(1, 2) fmt.Println(result) // 3 }
これをリモートなサーバーにある関数を呼び出す仕組みのことをリモートプロシージャコール(RPC)と言いい、Googleによって開発されたものがgRPCです。
Hello World
今回はGo言語の開発環境が準備できていることを前提に話を進めます。執筆時点のGo言語のバージョンは1.22.4
です。
プロジェクトの準備
お決まりのコマンドを実行してプロジェクトを作成します。
go mod init main
go.mod
ファイルが作成されます。
. └── go.mod
ツールのインストール
protoc
gRPCを使うためには、プロトコルバッファをコンパイルするためのツールが必要です。
インストールする方法はいくつかありますが、今回はHomebrewを使ってインストールします。
brew install protobuf
インストールが完了したら、以下のコマンドでバージョンを確認します。
protoc --version
protoc-gen-go
Go言語のプロトコルバッファをコンパイルするためのプラグインです。
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
インストールが完了したら、以下のコマンドでバージョンを確認します。
protoc-gen-go --version
protoc-gen-go-grpc
Go言語のgRPCを使うためのプラグインです。
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
インストールが完了したら、以下のコマンドでバージョンを確認します。
protoc-gen-go-grpc --version
protoc-gen-go
とprotoc-gen-go-grpc
のバージョンが表示されればインストール完了です。
最後に、protoc-gen-go
とprotoc-gen-go-grpc
のパスを環境変数に追加します。
export PATH="$PATH:$(go env GOPATH)/bin"
これで必要なツールのインストールが完了しました。
プロトコルバッファの定義
gRPCを使うためには、プロトコルバッファを定義する必要があります。
proto
ディレクトリを作成し、hello.proto
というファイルを作成します。
mkdir proto
ファイルを作成したら次の内容を書いて保存します。
syntax = "proto3"; package Hello; option go_package = "./go_protocol_buffer"; message HelloRequest { string name = 1; } message HelloResponse { string message = 1; } service HelloService { rpc SayHello (HelloRequest) returns (HelloResponse); }
ファイルツリーでみるとこんか感じです。
. ├── go.mod └── proto └── hello.proto
プロトコルバッファのコンパイル
プロトコルバッファをコンパイルします。
protoc -I. --go_out=. --go-grpc_out=. proto/*.proto
コンパイルが成功すると、go_protocol_buffer
ディレクトリが作成されます。
. ├── go.mod ├── go_protocol_buffer │ ├── hello.pb.go │ └── hello_grpc.pb.go └── proto └── hello.proto
ここまでで、gRPCの準備が完了しました。
サーバーの実装
コードを書く前に必要なパッケージをインストールします。
go get google.golang.org/grpc
パッケージのインストールができたらserver/main.go
を作成します。
package main import ( "context" "log" "net" "google.golang.org/grpc" pb "main/go_protocol_buffer" ) type server struct { pb.UnimplementedHelloServiceServer } func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) { log.Printf("Received: %v", in.GetName()) return &pb.HelloResponse{Message: "Hello " + in.GetName()}, nil } func main() { listener, err := net.Listen("tcp", "localhost:8080") if err != nil { log.Fatalf("Error: %v", err) } grpcServer := grpc.NewServer() pb.RegisterHelloServiceServer(grpcServer, &server{}) fmt.Println("Server is running on port: 8080") if err := grpcServer.Serve(listener); err != nil { log.Fatalf("Failed to server: %v", err) } }
ポイントをかいつまんで解説します。
listener, err := net.Listen("tcp", "localhost:8080")
net.Listen
関数を使って、サーバーを起動するためのリスナーを作成します。
grpcServer := grpc.NewServer()
grpc.NewServer
関数を使って、gRPCサーバーを作成します。
pb.RegisterHelloServiceServer(grpcServer, &server{})
pb.RegisterHelloServiceServer
関数を使って、gRPCサーバーにサービスを登録します。
if err := grpcServer.Serve(listener); err != nil { log.Fatalf("Failed to server: %v", err) }
grpcServer.Serve
関数を使って、サーバーを起動します。
サーバーを試しに起動してみます。
go run server/main.go
次のようなメッセージが表示されればサーバーが起動しています。
Server is running on port: 8000
次にクライアントを作成します。
クライアントの実装
client/main.go
を作成します。
package main import ( "context" "log" "google.golang.org/grpc" pb "main/go_protocol_buffer" ) func main() { conn, err := grpc.Dial("localhost:8000", grpc.WithInsecure()) if err != nil { log.Fatalf("Failed to connect: %v", err) } defer conn.Close() client := pb.NewHelloServiceClient(conn) response, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "World"}) if err != nil { log.Fatalf("Failed to call SayHello: %v", err) } log.Printf("Response: %v", response.GetMessage()) }
ポイントをかいつまんで解説します。
conn, err := grpc.Dial("localhost:8000", grpc.WithInsecure())
grpc.Dial
関数を使って、gRPCサーバーに接続します。
client := pb.NewHelloServiceClient(conn)
pb.NewHelloServiceClient
関数を使って、gRPCクライアントを作成します。
response, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "World"})
client.SayHello
関数を使って、gRPCサーバーのSayHello
メソッドを呼び出します。
クライアントを試しに起動してみます。
go run client/main.go
次のようなメッセージが表示されればクライアントが起動しています。
2024/06/18 16:23:09 Response: Hello World
これで、gRPCのHello Worldが完了しました。
おわりに
今回はGo言語でgRPCを使ってHello Worldをしてみました。 まだ使いこなせているかは微妙ですが、これからもっと知識を深めていきたいですね。