んだ日記

ndaDayoの技術日記です

gRPC Go for Professionals 読書録 Chapter 2からChapter 3

gRPC Go for Professionals chapter01-chapter05までの読書録。

今回は、 Chapter 2からChapter 3の読書録をつけていきます。

Protobuf Primer

Chapter 2は、Protobufについてです。 ProtobufのDocs protobuf.dev gRPCのDocs grpc.io も参考にしながら、読んでいきたいと思います。

Protobufについて

まずは、Protobufについてですが、データスキーマを定義するスキーマ言語です。

gRPCとProtobufの関係についてですが、gRPCのDocsでは、以下のように説明しています。

gRPC can use protocol buffers as both its Interface Definition Language (IDL) and as its underlying message interchange format

gRPCでは、Protobufを

  • Interface Definition Language
  • message interchange format

と2つの点で使っているとゆうてますね。

論よりコードということで、実際に見ていきましょう。

syntax = "proto3";

message Person {
  optional string name = 1;
  optional int32 id = 2;
  optional string email = 3;
}

message PersonRequest {
    Person person = 1;
}

message PersonResponse {
    string result = 1;
}

service PersonService{
    rpc Person(PersonRequest) returns (PersonResponse) {};
}

で、このperson.protoコンパイルすると、person.pb.goperson_grpc.pb.goが生成される。

person.pb.goを見てみると、構造体が生成されている。

type Person struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    Name  *string `protobuf:"bytes,1,opt,name=name,proto3,oneof" json:"name,omitempty"`
    Id    *int32  `protobuf:"varint,2,opt,name=id,proto3,oneof" json:"id,omitempty"`
    Email *string `protobuf:"bytes,3,opt,name=email,proto3,oneof" json:"email,omitempty"`
}

そして、Getterも

func (x *Person) GetName() string {
    if x != nil && x.Name != nil {
        return *x.Name
    }
    return ""
}

func (x *Person) GetId() int32 {
    if x != nil && x.Id != nil {
        return *x.Id
    }
    return 0
}

func (x *Person) GetEmail() string {
    if x != nil && x.Email != nil {
        return *x.Email
    }
    return ""
}

person_grpc.pb.goには、ServerとClientのinterfaceが生成させている。このインターフェースに従って、ServerとClientを実装することで通信する。

type PersonServiceClient interface {
    Person(ctx context.Context, in *PersonRequest, opts ...grpc.CallOption) (*PersonResponse, error)
}

type PersonServiceServer interface {
    Person(context.Context, *PersonRequest) (*PersonResponse, error)
    mustEmbedUnimplementedPersonServiceServer()
}

今回は、Goにコンパイルしたが、他の言語に変換することもできる。

Protobuf versus JSON

続いての話題は、ProtobufとJSONの比較です。

本書では以下の点で、ProtobufとJSONの比較を行っています。

  • Size of serialized data
  • Readability of the data schema and the serialized data
  • Strictness of the schema

では、それぞれ見ていきましょう。

Size of serialized data

まずは、Serializationについて。 これについては、Protobufが優っておりますね。

jsonがテキストにシリアライズされるのに対して、Protobufがバイナリにシリアライズされるからです。

Readability of the data schema and the serialized data

続いて可読性について。

可読については、the data schemaの可読性とthe serialized dataの可読性の2つ分けて触れています。

まずは、the data schemaの可読性 スキーマの可読性は、明示的な型を指定できるという観点からProtobufに軍配。

続いて、serialized dataの可読性 これは、当然、テキストにシリアライズされているjsonに軍配。

この点だが、著者は、トレードオフですよね、と述べていたのに納得した。

this is a trade-off between readability and serialized data size here.

Schema strictness

最後にスキーマの厳格さ。 ここについても、著者はProtobufに軍配を上げている。

JSON Schema の話もあげているが、開発に複雑さをもたらすとゆうてますね。

うーん、ここについては、Protobufを用いた開発を行ったことがないから恩恵を実感できていないが、JSON Schemaでも困らんかったなーという感想。

Encoding details

どのようにスキーマエンコードされるかの話が続いて来るのですが、ここは理解しないとな時期が来たら理解することにします

Chapter 3

Chapter 3ではgRPCの概論的な内容になっています。 ざっと読んでみて、気になった箇所だけ掻い摘みます。

Unimplemented

Chapter2のところで、

service PersonService{
    rpc Person(PersonRequest) returns (PersonResponse) {};
}

というServiceのスキーマを例として出したが、こちらをコンパイルすると、以下のようなコードも生成される。

Unimplementedがprefixにあるコードだ。

type UnimplementedPersonServiceServer struct {
}

func (UnimplementedPersonServiceServer) Person(context.Context, *PersonRequest) (*PersonResponse, error) {
    return nil, status.Errorf(codes.Unimplemented, "method Person not implemented")
}
func (UnimplementedPersonServiceServer) mustEmbedUnimplementedPersonServiceServer() {}

これは、文字通り未実装だった際に呼び出される関数で、もしPersonが未実装だった場合にクラッシュさせずにエラーを返すというやつです。

まとめ

Chapter 3では、Encoding detailsというセクションがあり、どのようにスキーマエンコードされているかを説明している章があったのですが、ちょっと何言っているか状態だった。

深く理解しないといけないという気持ちに駆られたら再び読み込んでみようかと思います。

ひとまず、jsonとの比較やUnimplementedのあたりを軽く理解できてよかったです。

僕から以上。あったかくして寝ろよ。