🐖

今更Protocol Buffers入門

2023/08/27に公開

下記の続き
https://zenn.dev/shibata/articles/6e17b79af4f819

本題

Protocol Buffers(以下、Protobuf)を触ってみます。

$ brew install protobuf
$ protoc --version

下記に.protoファイルのサンプルを書いてみます。
1・2はフィールド番号と呼ばれ、シリアライズとデシリアライズの際に使用されるのでユニーク値の設定が必要です。
バージョンは2と3があり、syntaxで定義しますが、理由がなければ3が無難です。
3系はフィールドに必須を宣言できず、全てがOptionalです。
是非については議論があったようですが、本題ではないので、ここでは詳しくは触れません。

参考
https://github.com/protocolbuffers/protobuf/issues/2497#issuecomment-267422550
https://stackoverflow.com/questions/31801257/why-required-and-optional-is-removed-in-protocol-buffers-3

syntax = "proto3";

message Person {
  string name = 1;
  int32 age = 2;
}

Goコード生成

ProtobufファイルをGoにコンパイルするには、別途protoc-gen-goも必要です。

$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

packageやoption go_packageを加えると例えば下記にようになります。

syntax = "proto3";

package tutorial;

option go_package = "./gen";

message Person {
  string name = 1;
  int32 age = 2;
}

timestampなどのWell Known Typesもインポートして使用できます。
https://protobuf.dev/reference/protobuf/google.protobuf/

# ディレクトリ例
.
└── protocolbuf
    └── tuto.proto


$ protoc -I=protocolbuf --go_out=./ protocolbuf/tuto.proto

# 生成後
.
├── gen
│   └── tuto.pb.go
└── protocolbuf
    └── tuto.proto

tuto.pb.goが自動生成されているはずです。

公式が言っているProtocol Buffersで向いていないケース

https://protobuf.dev/overview/#not-good-fit

  • 数MBを超えるメッセージで使用するとメモリの使用量が上がる
  • 同じ内容でもバイナリ表現が違う場合があるので、パース無しで比較したいケースがある
  • 他のフォーマットのほうがメッセージの圧縮で有利なるケースがある
  • 科学計算
  • FortranやIDLを使用
  • 標準規格での構築が必要

以上を踏まえて、一般にGoを使用したWebサービスのユースケースでは問題は起きにくいと考えます。
しかし、gRPCを使用する場合はProtobufは必須ですが、(protoファイルは可動性があり、スキーマファーストで構築できるというメリットはあるものの)REST APIで使うには学習コスト高くない?という問題は存在します。

これは別の3rdパーティツールであるBufが解決してくれそうなので、また次回以降で触ってみたいと思います。
https://buf.build/docs/introduction

以上、ありがとうございました。

Discussion