とほほのgRPC入門
目次
gRPCとは
- Google が開発した RPC(Remote Procedure Call)システムです。
- サーバとクライアント間で HTTP/2 を経由した関数呼び出しを実現します。
- Go, JavaScript(Node.js), PHP, Python, Ruby, Java, C/C++, C#, Dart, Kotlin などで利用可能です。
- Protocol Buffers と呼ばれるインタフェース記述言語(IDL)でインタフェースを定義します。
- ストリーミング型のインタフェースを実装することもできます。
インストール
CentOS 8 + Python の場合の例を示します。インストールにはそこそこの時間がかかります。
# CentOS 8 + Python
# yum -y install gcc-c++ python3 python3-devel
# pip3 install grpcio==1.39.0 grpcio-tools==1.39.0
プロトファイルを作成する
プロトコルバッファを定義するプロトファイル(hello.proto)を作成します。
hello.proto
syntax = "proto3";
package hello;
service HelloWorld {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
スタブを作成する
protoc を用いてスタブを作成します。
# python3 -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./hello.proto
下記のファイルが作成されます。
hello.proto hello_pb2.py hello_pb2_grpc.py
サーバプログラムを作成する
.proto から生成されたサービサーを用いて、サーバプログラム(server.py)を作成します。
server.py
from concurrent import futures
import grpc
import hello_pb2
import hello_pb2_grpc
class HelloWorld(hello_pb2_grpc.HelloWorldServicer):
def SayHello(self, request, context):
print("RECV: %s" % request.name)
message = "Hello, %s!" % request.name
print("SEND: %s" % message)
return hello_pb2.HelloReply(message=message)
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
hello_pb2_grpc.add_HelloWorldServicer_to_server(HelloWorld(), server)
server.add_insecure_port('[::]:8000')
server.start()
server.wait_for_termination()
if __name__ == '__main__':
serve()
クライアントプログラムを作成する
.proto から生成されたスタブを用いて、クライアントプログラム(client.py)を作成します。
client.py
import grpc
import hello_pb2
import hello_pb2_grpc
def run():
with grpc.insecure_channel('localhost:8000') as channel:
stub = hello_pb2_grpc.HelloWorldStub(channel)
response = stub.SayHello(hello_pb2.HelloRequest(name='Yamada'))
print("RECV: %s" % response.message)
if __name__ == '__main__':
run()
サーバとクライアントを実行する
まずはサーバを起動します。
# python3 ./server.py
次にクライアントを起動します。
# python3 ./client.py Hello, Yamada!
サーバから Hello, Yamada! というメッセージが返却されれば成功です。
Go言語の場合
Go言語の場合のサンプルを示します。Go 1.15, protoc 3.17, gRPC 1.39
- 参考:https://grpc.io/docs/languages/go/quickstart/
必要なパッケージをインストールしておきます。
# dnf -y install golang wget unzip # go version go version go1.15.13 linux/amd64
protoc コマンドをインストールします。
# mkdir ~/protoc # cd ~/protoc # wget https://github.com/protocolbuffers/protobuf/releases/download/v3.17.3/protoc-3.17.3-linux-x86_64.zip # unzip ./protoc-3.17.3-linux-x86_64.zip # ~/protoc/bin/protoc --version libprotoc 3.17.3
Go 1.12 からは GOPATH モードではなく、モジュールモードが推奨されるそうなので、モジュールモードにして、必要なモジュールをダウンロードします。
# export GO111MODULE=on # export PATH="$PATH:$(go env GOPATH)/bin" # go get google.golang.org/protobuf/cmd/protoc-gen-go@v1.27 # go get google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
サンプルとなる hello モジュールを作成します。
# mkdir ~/hello # cd ~/hello # go mod init example.com/my-name/hello
プロトファイルを作成してコンパイルします。
# mkdir ./proto # vi ./proto/hello.proto
proto/hello.proto
syntax = "proto3";
option go_package = "example.com/my-name/hello";
package hello;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
# ~/protoc/bin/protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. \ --go-grpc_opt=paths=source_relative ./proto/hello.proto
サーバプログラムを作成します。
# mkdir ./server # vi ./server/main.go
server/main.go
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "example.com/my-name/hello/proto"
)
type server struct {
pb.UnimplementedGreeterServer
}
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("RECV: %v", in.GetName())
message := "Hello, " + in.GetName() + "!"
log.Printf("SEND: %v", message)
return &pb.HelloReply{Message: message}, 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{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
クライアントプログラムを作成します。
# mkdir ./client # vi ./client/main.go
client/main.go
package main
import (
"context"
"log"
"time"
"google.golang.org/grpc"
pb "example.com/my-name/hello/proto"
)
func main() {
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)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "Yamada"})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("RECV: %s", r.GetMessage())
}
ターミナルを二つ起動し、サーバプログラムと、クライアントプログラムを実行します。いくつかのパッケージが自動インストールされます。Go 1.16 からは自動インストールはされなくなるので、いくつか事前にインストールしておく必要があるかもしれません。
# go run ./server/main.go go: finding module for package google.golang.org/grpc go: finding module for package google.golang.org/grpc/status go: finding module for package google.golang.org/protobuf/reflect/protoreflect go: finding module for package google.golang.org/protobuf/runtime/protoimpl go: finding module for package google.golang.org/grpc/codes go: downloading google.golang.org/grpc v1.39.0 go: found google.golang.org/grpc in google.golang.org/grpc v1.39.0 go: found google.golang.org/grpc/codes in google.golang.org/grpc v1.39.0 go: found google.golang.org/grpc/status in google.golang.org/grpc v1.39.0 go: found google.golang.org/protobuf/reflect/protoreflect in google.golang.org/protobuf v1.27.1 go: found google.golang.org/protobuf/runtime/protoimpl in google.golang.org/protobuf v1.27.1 go: downloading github.com/golang/protobuf v1.5.0 go: downloading golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd go: downloading google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 go: downloading golang.org/x/net v0.0.0-20200822124328-c89045814202 go: downloading golang.org/x/text v0.3.0 2021/07/25 00:54:56 RECV: Yamada 2021/07/25 00:54:56 SEND: Hello, Yamada!
# go run ./client/main.go 2021/07/25 00:54:56 RECV: Hello, Yamada!
リンク
Copyright (C) 2021 杜甫々
初版:2021年7月25日 最終更新:2021年7月25日
https://www.tohoho-web.com/ex/grpc.html