Go
golang
gRPC

grpc-goのリフレクションについて調べてみた

grpc-goのExamplesにあるreflection.Register(s)が何をしているかについて調べたときのメモです。
また、gRPC command line tool(gRPC CLI)をビルドするときにエラーが出たのでその時の対処方法も記載しています。

公式にあるリフレションのチュートリアルがあるので、英語に抵抗がなければそちらを見たほうがいいと思います。

grpc-go/server-reflection-tutorial.md at master · grpc/grpc-go · GitHub


まずは、gRPCサーバのソースです。

grpc-go/main.go at master · grpc/grpc-go · GitHub

package main

import (
    "log"
    "net"

    "golang.org/x/net/context"
    "google.golang.org/grpc"
    pb "google.golang.org/grpc/examples/helloworld/helloworld"
    "google.golang.org/grpc/reflection"
)

const (
    port = ":50051"
)

// server is used to implement helloworld.GreeterServer.
type server struct{}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

func main() {
    lis, err := net.Listen("tcp", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterGreeterServer(s, &server{})
    // Register reflection service on gRPC server.
    reflection.Register(s)
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

この33行目のreflection.Register(s)は、取り外して動かしてもGreeterサービスの呼び出しには何も影響ありません。

では、何をしているのかというと、grpc/reflection.protoに定義されたサービスを追加しています。
このサービスを使うと、公開しているgRPCサーバのサービスの内容を取得することが出来ます。

gRPCのGitリポジトリには、gRPC command line tool(gRPC CLI)というツールがあり、このツールを使えばgRPCサーバがどのようなAPIを提供しているかを見ることができます。

以下はコマンドの例です。

サービス一覧
$ ./grpc_cli ls localhost:50051
grpc.reflection.v1alpha.ServerReflection
helloworld.Greeter
サービスの詳細
$ ./grpc_cli ls localhost:50051 helloworld.Greeter -l
filename: helloworld.proto
package: helloworld;
service Greeter {
  rpc SayHello(helloworld.HelloRequest) returns (helloworld.HelloReply) {}
}
メッセージの型
$ ./grpc_cli type localhost:50051 helloworld.HelloRequest
message HelloRequest {
  string name = 1[json_name = "name"];
}

gRPC command line tool(gRPC CLI)のビルド

先程の例のコマンドgrpc_cliを使うためにはビルドを行う必要があります。

Macでチュートリアルの例に従ってgRPC CLIをビルドしようとしましたが、すんなりいきませんでした。
その時の対応したときのメモです。

まず最初のmake実行時です。

$ git clone https://github.com/grpc/grpc
$ cd grpc
$ make grpc_cli
Package libcares was not found in the pkg-config search path.
Perhaps you should add the directory containing `libcares.pc'
to the PKG_CONFIG_PATH environment variable
No package 'libcares' found

DEPENDENCY ERROR

The target you are trying to run requires an OpenSSL implementation.
Your system doesn't have one, and either the third_party directory
doesn't have it, or your compiler can't build BoringSSL.

Please consult INSTALL to get more information.

If you need information about why these tests failed, run:

  make run_dep_checks

Additionally, since you are in a git clone, you can download the
missing dependencies in third_party by running the following command:

  git submodule update --init

make: *** [stop] Error 1

依存関係に問題があるようです。
エラーメッセージに書かれているgit submodule update --initを実行して再度ビルドします。

$ make grpc_cli
...
test/cpp/util/cli_credentials.cc:21:10: fatal error: 'gflags/gflags.h' file not found

今度はgFlagsが無いようです。
Homebrewにあるのでインストールします。

$ brew install gflags
...
$ cd bins/opt
$ ls
grpc_cli        grpc_cpp_plugin     grpc_node_plugin    grpc_php_plugin     grpc_ruby_plugin
grpc_cli.dSYM       grpc_csharp_plugin  grpc_objective_c_plugin grpc_python_plugin

今度は成功しました。

ドキュメントをよく見ると、ちゃんと説明がありました。orz
Linuxの例もあります。

grpc/command_line_tool.md at master · grpc/grpc · GitHub