Open8

gRPCを試してみる

Teru roomTeru room

前提条件

  • 端末: Apple Mac mini
  • チップ : Apple M2 Pro
  • OS : macOS Ventura 13.2.1
  • インストーラー : Homebrew
  • インストール済コマンド : tree
  • プログラミング言語 : Go言語

参考資料

インストール

  • protocコマンドを使うためにprotobufのインストール
    • sharl@macMini ~ %
brew install protobuf
実行結果
==> Fetching dependencies for protobuf: abseil
==> Fetching abseil
==> Downloading https://ghcr.io/v2/homebrew/core/abseil/manifests/20230125.3-1
######################################################################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/abseil/blobs/sha256:c789ff211d0d81fba211ffa4abc0a0e5ce430698ae0e590057cbeeb73d
######################################################################################################################## 100.0%
==> Fetching protobuf
==> Downloading https://ghcr.io/v2/homebrew/core/protobuf/manifests/23.4
######################################################################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/protobuf/blobs/sha256:eb86d06abace7c985b21ccac17ea418131e17689c9fdeddbcaa998d7
######################################################################################################################## 100.0%
==> Installing dependencies for protobuf: abseil
==> Installing protobuf dependency: abseil
==> Pouring abseil--20230125.3.arm64_ventura.bottle.1.tar.gz
🍺  /opt/homebrew/Cellar/abseil/20230125.3: 723 files, 10.6MB
==> Installing protobuf
==> Pouring protobuf--23.4.arm64_ventura.bottle.tar.gz
==> Caveats
Emacs Lisp files have been installed to:
  /opt/homebrew/share/emacs/site-lisp/protobuf
==> Summary
🍺  /opt/homebrew/Cellar/protobuf/23.4: 389 files, 12.2MB
==> Running `brew cleanup protobuf`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
==> Caveats
==> protobuf
Emacs Lisp files have been installed to:
  /opt/homebrew/share/emacs/site-lisp/protobuf
  • sharl@macMini ~ %
protoc --version
実行結果
```bash
libprotoc 23.4
  • sharl@macMini ~ %
mkdir -p ./dev/grpc/test ; cd ./dev/grpc/test
  • sharl@macMini test %
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
実行結果
go: downloading google.golang.org/protobuf v1.31.0
go: downloading google.golang.org/grpc v1.57.0
go: downloading google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0
go: downloading google.golang.org/protobuf v1.28.1
  • sharl@macMini test %
export PATH="$PATH:$(go env GOPATH)/bin"
  • sharl@macMini ~ %
protoc-gen-go --version ; protoc-gen-go-grpc --version
実行結果
protoc-gen-go v1.31.0
protoc-gen-go-grpc 1.3.0
Teru roomTeru room

サンプルコードのインストール

  • sharl@macMini test %
git clone -b v1.57.0 --depth 1 https://github.com/grpc/grpc-go
実行結果
Cloning into 'grpc-go'...
remote: Enumerating objects: 1349, done.
remote: Counting objects: 100% (1349/1349), done.
remote: Compressing objects: 100% (1144/1144), done.
remote: Total 1349 (delta 212), reused 543 (delta 68), pack-reused 0
Receiving objects: 100% (1349/1349), 2.14 MiB | 11.10 MiB/s, done.
Resolving deltas: 100% (212/212), done.
Note: switching to '87bf02ad24f6cc071d2553eb5d62332194bba1fe'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false
  • sharl@macMini test %
cd grpc-go/examples/helloworld ; tree
実行結果
sharl@macMini helloworld % tree
.
├── README.md
├── greeter_client
│   └── main.go
├── greeter_server
│   └── main.go
└── helloworld
    ├── helloworld.pb.go
    ├── helloworld.proto
    └── helloworld_grpc.pb.go

4 directories, 6 files

サンプルコード

greeter_server/main.go
// Package main implements a server for Greeter service.
package main

import (
        "context"
        "flag"
        "fmt"
        "log"
        "net"

        "google.golang.org/grpc"
        pb "google.golang.org/grpc/examples/helloworld/helloworld"
)

var (
        port = flag.Int("port", 50051, "The server port")
)

// 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
}
greeter_client/main.go
// Package main implements a server for Greeter service.
// Package main implements a client for Greeter service.
package main

import (
        "context"
        "flag"
        "log"
        "time"

        "google.golang.org/grpc"
        "google.golang.org/grpc/credentials/insecure"
        pb "google.golang.org/grpc/examples/helloworld/helloworld"
)

const (
        defaultName = "world"
)

var (
        addr = flag.String("addr", "localhost:50051", "the address to connect to")
        name = flag.String("name", defaultName, "Name to greet")
)

func main() {
        flag.Parse()
        // Set up a connection to the server.
        conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
        if err != nil {
                log.Fatalf("did not connect: %v", err)
Teru roomTeru room

サンプルコードの実行

  • 別ターミナル起動
    • sharl@macMini ~ %
cd ./dev/grpc/test/grpc-go/examples/helloworld ; go run greeter_server/main.go
実行結果
go: downloading google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19
go: downloading google.golang.org/protobuf v1.30.0
go: downloading golang.org/x/net v0.9.0
go: downloading github.com/golang/protobuf v1.5.3
go: downloading google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54
go: downloading golang.org/x/text v0.9.0
2023/08/20 17:24:32 server listening at [::]:50051
  • 別ターミナル起動
    • sharl@macMini ~ %
cd ./dev/grpc/test/grpc-go/examples/helloworld ; go run greeter_client/main.go
実行結果
2023/08/20 17:29:05 Greeting: Hello world
Teru roomTeru room

gRPCサービスのアップデート

Protocol buffersのアップデート

  • アップデート前
helloworld/helloworld.proto
syntax = "proto3";

option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";

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;
}
  • アップデート後
    • GreeterサービスにSayHelloAgain()メソッドを追加
helloworld/helloworld.proto
........
// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
  // Sends another greeting
  rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
}
........
Teru roomTeru room

gRPCコードの再生成

  • sharl@macMini ~ %
cd dev/grpc/test/grpc-go/examples/helloworld 
protoc --go_out=. --go_opt=paths=source_relative \
    --go-grpc_out=. --go-grpc_opt=paths=source_relative \
    helloworld/helloworld.proto
  • helloworld.pb.gohelloworld_grpc.pb.goが更新されていることを確認
    • sharl@macMini helloworld %
ls -l helloworld
実行結果
total 48
-rw-r--r--  1 sharl  staff  8757  8 20 22:40 helloworld.pb.go
-rw-r--r--  1 sharl  staff  1257  8 20 17:55 helloworld.proto
-rw-r--r--  1 sharl  staff  5730  8 20 22:40 helloworld_grpc.pb.go
Teru roomTeru room

サーバーの更新

  • greeter_server/main.goにSayHelloAgain関数の追加
greeter_server/main.go
func (s *server) SayHelloAgain(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
        return &pb.HelloReply{Message: "Hello again " + in.GetName()}, nil
}

クライアントの更新

  • greeter_client/main.goのmain関数にSayHelloAgain関数の呼び出しを追加
greeter_server/main.go
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())
Teru roomTeru room

サービスの実行

  • 別ターミナルでサーバーを実行
    • sharl@macMini helloworld %
cd ./helloworld ; go run greeter_server/main.go
実行結果
stat greeter_server/main.go: no such file or directory
sharl@macMini helloworld % pwd
/Users/sharl/dev/grpc/test/grpc-go/examples/helloworld/helloworld
sharl@macMini helloworld % cd .. 
sharl@macMini helloworld % pwd
/Users/sharl/dev/grpc/test/grpc-go/examples/helloworld
sharl@macMini helloworld % cd /Users/sharl/dev/grpc/test/grpc-go/examples/helloworld ; go run greeter_server/main.go 
2023/08/20 23:20:56 server listening at [::]:50051
  • 別ターミナルでクライアントを実行
    • sharl@macMini helloworld %
cd /Users/sharl/dev/grpc/test/grpc-go/examples/helloworld ; go run greeter_client/main.go --name=高橋 
実行結果
2023/08/20 23:24:49 Greeting: Hello 高橋
2023/08/20 23:24:49 Greeting: Hello again 高橋
Teru roomTeru room
  • sharl@macMini grpc % go mod init addressbook
実行結果
go: creating new go.mod: module addressbook
go: to add module requirements and sums:
	go mod tidy