📑
Bufを利用して、Grpcサーバ(Go)を爆速で作成する!
目的
以前まで、protoc のみ利用して proto ファイルから Go への変換を行なっていた。しかし,パスが間違ったり、記述方法(変数名など)がわかなかったり、複数の proto ファイルを一度に go に変換することが大変だった(makefile などに記述する必要があった). そのため proto ファイルを管理するパッケージとして Buf を利用することにした.
Buf とは
一言で言うと
proto ファイルを管理する CLI(高性能な Protocbuf コンパイラ)
- 文法のエラー検出
- lint 機能(チームでルールを統一することができる)
- 設定可能なテンプレートに基づいて protoc プラグインを呼び出すコードジェネレーター
github
実装
package のインストール
brew install bufbuild/buf/buf
buf.yaml ファイルの生成
buf.yaml
version: v1
# モジュール名
name: buf.build/tutorials/lint
# lint設定
lint:
use:
- DEFAULT # デフォルトルールを使用
Protobuf ファイルの作成(schema の作成)
todo.proto
syntax = "proto3";
package proto.todo.v1;
// Defines the Todo service
service TodoService {
// Defines a method to get a todo item
rpc GetTodo (GetTodoRequest) returns (GetTodoResponse);
// Defines a method to create a todo item
rpc CreateTodo (CreateTodoRequest) returns (CreateTodoResponse);
}
// Response message for getting a todo item
message GetTodoResponse {
int32 id = 1;
string title = 2;
string description = 3;
}
// Request message for getting a todo item
message GetTodoRequest {
int32 id = 1;
}
// Response message for creating a todo item
message CreateTodoResponse {
int32 id = 1;
string title = 2;
string description = 3;
}
// Request message for creating a todo item
message CreateTodoRequest {
string title = 1;
string description = 2;
}
buf.gen.yaml ファイルの作成
buf.gen.yaml
version: v1
# マネージドモードを有効
managed:
enabled: true
go_package_prefix:
default: github.com/JY8752/buf-demo/example/gen # デフォルトのpackage名を指定。これは必須
plugins:
# protoc-gen-goプラグイン
# - plugin: go
# out: gen/go
# opt: paths=source_relative
# リモートプラグインを使用
- plugin: buf.build/protocolbuffers/go:v1.31.0
out: gen/go
# GoのモジュールパスがProtobufファイルから相対的に解決されるよう指定
# なくてもいいがないと上で指定したdefaultのフルパスが使われる
opt: paths=source_relative
# protoc-gen-go-grpcプラグイン
- plugin: buf.build/grpc/go:v1.3.0
out: gen/go
opt: paths=source_relative
proto ファイルから go を生成
buf generate proto
gRPC サーバの実装
main.go
package main
import (
"fmt"
"log"
"net"
"os"
"os/signal"
"todoService/cmd/server/controller"
todov1 "todoService/gen/go/todo/v1"
"google.golang.org/grpc"
)
// 自作サービス構造体のコンストラクタを定義
func main() {
// 1. 8080番portのLisnterを作成
port := 8080
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
panic(err)
}
grpcTaskController := controller.NewGrpcController()
// 2. gRPCサーバーを作成
s := grpc.NewServer()
todov1.RegisterTodoServiceServer(s, grpcTaskController)
// 3. 作成したgRPCサーバーを、8080番ポートで稼働させる
go func() {
log.Printf("start gRPC server port: %v", port)
s.Serve(listener)
}()
// 4.Ctrl+Cが入力されたらGraceful shutdownされるようにする
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt)
<-quit
log.Println("stopping gRPC server...")
s.GracefulStop()
}
todo_controller.go
package controller
import (
"context"
todov1 "todoService/gen/go/todo/v1"
)
type grpcTodoController struct {
todov1.UnimplementedTodoServiceServer
}
func NewGrpcController() *grpcTodoController {
return &grpcTodoController{}
}
func (s *grpcTodoController) GetTodo(ctx context.Context, req *todov1.GetTodoRequest) (*todov1.GetTodoResponse, error) {
return &todov1.GetTodoResponse{
Id: 1,
Title: "title",
Description: "description",
}, nil
}
Discussion