GoでProtocol Buffersを使う

こんにちは、daihaseです。

今回はGoProtocol Buffersを使った記事を書きたいと思います。
まずProtocol Buffersですが、こちらはGoogleによって2008年に開発されたもので、一言でいうと言語やプラットフォームに依存せずに構造化されたデータをシリアライズ可能な仕組みといった感じでしょうか。

.protoというファイルに記載されたインターフェース定義言語(IDL) によって、クライアント/サーバーが共通で使用する構造を定義でき、これによってXMLやJSONと同じようにAPI通信の際に用いることが出来ます。

恐らく多くの方が使い慣れているJSONなどと比較してのメリットは、データサイズがとても小さいことや、軽量で高速、またプログラム上から簡単に使用出来るデータアクセスクラスを生成する、など色々ありますが、まずは簡単なサンプルにて使ってこちらを実感してみましょう。

※事前にGoの開発環境は構築済みとします。

Protocol Buffers コンパイラのインストール

まずProtocol Buffersを各種言語にコンパイルするために、コンパイラとターゲット言語用のランタイムが必要となります。

ターミナルより、下記にてコンパイラをインストールします。

次にGoを使って構造体をProtocol Buffersバイナリー形式にシリアライズするための、専用のGo protoドライバーをインストールする必要があります。

これで下準備は完了です。

.protoファイルの作成

早速プロジェクトファイルを作っていきます。
GOPATHの通った場所にprotobufsSampleというフォルダを作成します。

次に.protoファイルを格納するためのprotofilesフォルダを作成します。

では作ったprotofilesフォルダにperson.protoファイルを作成し、以下のように記述します。

XMLやJSONに慣れていれば、何となく雰囲気で構造が理解出来きそうですね。

まずメッセージタイプを定義します。上記でいうとPersonですね。PhoneNumberのように他のメッセージ型の中にメッセージタイプを定義することも出来ます。

また見てわかるようにメッセージ定義の各フィールドにはユニークな数値タグがあります。数値は1から始まり、これを元にフィールドを区別するため、基本的に一度決めたタグは変更はしないほうがいいでしょう。

なおenumで定義されているPhoneTypeは最初の定数は 0 にマップされており、enum定義は全て0から始める必要があると覚えておきましょう。

他には、他のメッセージ型をフィールドの型として使うことも出来ます。上記の場合は、Personメッセージ中にPhoneNumberメッセージを含めたいので、フィールドphonesの型をPhoneNumberとしています。

最後に、repeatedは後続する型の配列であることを宣言するためのものになります。

ざっくりとこんな感じでしょうか。

.protoファイルのコンパイル

作った.protoはそのままではGoから使うことができないので、これをコンパイルする必要があります。.protoを作成したprotifilesフォルダに移動し、以下コマンドを叩いてください。

すると.protoファイルと同じ名前のperson.pb.goというファイルが生成されているかと思います。中は以下のようになっています。

ちょっとボリュームがありますね…。ざっと見た感じ、.protoファイルで定義したPersonAddressBookなどの構造体が作成され、それぞれにゲッター/セッターが生成されているのがわかります。

Goから生成されたperson.pb.goを使ってみる

では最後に、この生成されたperson.pb.goのPerson構造体を使用するmain.goを作成します。protobufsSampleフォルダ直下にmain.goを作成し、以下のようなコードを記述します。

protofilesパッケージからProtocol Bufferを読み込むためにインポートしていますが、ここは自分の環境にあわせたパスになるのでご注意ください。

コードを見ていきますと、まずperson.pb.goで定義されているPerson構造体、こちらを使って新たに構造体を作成し変数pへ代入しています。次にprotofileのPerson構造体を初期化し、p1に代入しています。最初に生死した変数pをproto.Marshal関数を使ってシリアライズ化しbodyへ代入、最後にそのbodyを使ってp1にJSON形式のものをパースするといった流れです。

Printlnでそれぞれの値を出力するようになってますので、早速以下のコマンドを叩いて確認してみましょう。

すると以下のような結果がターミナル上に出力されるかと思います。

ちゃんとそれぞれの値が意図したように出力されていますね。

このサンプルだけだとJSONの代わりにProtocol Bufferを使う利点がいまいち見えてこないかもしれません。実際は今回サンプルに用いたmainとprotobufs、この2つのファイルは少ないオーバーヘッドで通信が行われています。

バイナリのサイズはテキストよりも小さいので、プロトコルマーシャリングされたデータのサイズはJSONよりも小さくなるのです。これが大きいサービスとかになってくると結構差も出てくるかと思います。また今回紹介したProtocol Buffersは何かと人気?なgRPCでもデータ層に用いられ、サーバー/クライアント間のAPI通信において非常に効力を発揮しています。

インターフェース定義言語を用いて.protoファイルとして定義し、サーバー/クライアントに必要なコードの雛形を生成、しかもGoだけでなく複数の言語に対応、これだけでも非常に便利でワクワクする技術と思いませんか!?

今度はそのgRPCを使い、よりProtocol Buffersの有用性を紹介出来たらと思います。

ちなみに今回作ったサンプルはGitHubにもあげてありますのでよかったらどうぞ〜

それでは良い開発ライフを〜

スポンサーリンク
336 x 280 レクタングル(大)
336 x 280 レクタングル(大)