はじめに
gRPCをGo言語で使用する基本的な例を提供します。
例では、簡単なgRPCサービスを定義し、そのサービスを実装したサーバーとクライアントを作成します。
一般的な流れ
Step 1: Protocol Buffers (protobuf) の定義
まず、.proto
ファイルを作成して、gRPCサービスとメッセージ形式を定義します。helloworld.proto
という名前のファイルを作成し、以下の内容を記述します。
syntax = "proto3";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings.
message HelloReply {
string message = 1;
}
Step 2: gRPCコードの生成
上記の.proto
ファイルから、Goのソースコードを生成する必要があります。これには、protoc
コンパイラとGo用のgRPCプラグインが必要です。
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
helloworld.proto
このコマンドを実行すると、helloworld.pb.go
と helloworld_grpc.pb.go
という2つのファイルが生成され、これらには定義したサービスに必要なGoのコードが含まれます。
Step 3: gRPCサーバーの実装
次に、gRPCサーバーを実装します。server.go
という名前のファイルを作成し、以下のコードを記述します。
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "path/to/your/helloworld" // 実際のパスに置き換えてください
)
// server is used to implement helloworld.GreeterServer.
type server struct {
pb.UnimplementedGreeterServer
}
// 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 main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Printf("server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
Step 4: gRPCクライアントの実装
最後に、サーバーに接続してメソッドを呼び出すクライアントを実装します。client.go
という名前のファイルを作成し、以下のコードを記述します。
package main
import (
"context"
"log"
"time"
"google.golang.org/grpc"
pb "path/to/your/helloworld" // 実際のパスに置き換えてください
)
func main() {
// Set up a connection to the server.
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
// Contact the server and print out its response.
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "world"})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %v", r.GetMessage())
}
実行方法
- まず、サーバーを起動します。
go run server.go
- 次に、別のターミナルウィンドウでクライアントを起動します。
go run client.go
これで、クライアントがサーバーに "Hello world" というメッセージを送信し、サーバーからの応答を受け取る基本的なgRPC通信が実装できました。
helloworld.pb.go
と helloworld_grpc.pb.go
に含まれるコードは自動的に生成されますが、server.go と client.go の実装は自動ではありません。これらのファイルは開発者によって手動で書かれ、生成されたコードを基にして具体的なビジネスロジックやサービスの振る舞いを実装します。
server.go
と client.go
は、helloworld.pb.go
と helloworld_grpc.pb.go
によって生成されたコードに基づいて書かれます。
helloworld.pb.go
と helloworld_grpc.pb.go
の役割
-
helloworld.pb.go
:-
.proto
ファイルで定義されたメッセージ型(この例ではHelloRequest
とHelloReply
)をGoの型として提供します。 - protobufメッセージをシリアライズ(エンコード)およびデシリアライズ(デコード)するための関数も含まれています。
-
-
helloworld_grpc.pb.go
:-
.proto
ファイルで定義されたサービス(この例ではGreeter
サービス)のためのgRPCのクライアントとサーバーのインターフェースを提供します。 - サーバーサイドでは、実装すべきメソッド(この例では
SayHello
)のスタブが含まれています。 - クライアントサイドでは、サーバーのメソッドをリモートで呼び出すためのメソッドが含まれています。
-
実装の流れ
-
サーバー実装 (
server.go
):-
helloworld_grpc.pb.go
に定義されたGreeterServer
インターフェースを実装することにより、サービスロジックを定義します。 - このインターフェースには、
SayHello
メソッドが含まれており、具体的なビジネスロジックを実装する必要があります。
-
-
クライアント実装 (
client.go
):-
helloworld_grpc.pb.go
に定義されたGreeterClient
インターフェースを使用して、サーバーのメソッドをリモートで呼び出します。 - このインターフェースを通じて
SayHello
メソッドを呼び出し、リクエストを送信し、レスポンスを受け取ります。
-
運用を考慮した実装
先ほどの例ではserver.go
やclient.go
を手動で記載しました。
プロジェクトやチームによっては、開発プロセスを効率化し、一貫性を保つために、自動化ツールやスクリプトを使用して一部のコードやひな形(ボイラープレート)を生成することがあります。これは、特に大きなプロジェクトや複数の人が関わる場合に、効率的かつエラーを減らす方法として広く採用されています。
今回の例の場合、例えば server.go
を手動ではなく、server.go
を自動で作成させるということです。
自動ひな形生成のメリット
- 一貫性の保持: 自動生成ツールを使用すると、プロジェクト全体でコーディングスタイルやアーキテクチャの一貫性を保つことができます。
- 開発速度の向上: ボイラープレートコードの自動生成により、開発者はビジネスロジックやアプリケーションのコア機能に集中することができ、開発プロセスが加速されます。
- エラーの減少: 手動でコードを書く際に発生しやすい、単純なミスやタイプミスを減らすことができます。
gRPCサーバーの例
例えば、server.go
がメソッド名と同じ名前でシェルスクリプトを介して自動的に生成される方法があります。これは、SayHello
メソッドのためのサーバーサイドのスタブを含む server.go
ファイルを自動的に生成することを意味しています。生成されたファイルは基本的な構造を提供し、開発者はそのファイルにビジネスロジックを追加することで、メソッドの具体的な実装を行います。
自動生成スクリプトのカスタマイズ
プロジェクトの具体的なニーズに合わせて、自動生成スクリプトやツールをカスタマイズすることも一般的です。たとえば、特定のコメントやドキュメントの追加、特定のアーキテクチャパターンへの準拠など、プロジェクト固有の要件を満たすために調整が行われることがあります。
おわりに
一般的なgRPCの使用の例と、運用を考慮したシェルでの改善例を記載しました。