Protocol Buffers (プロトコルバッファーズ)とは
Protocol Buffersは、構造化されたデータを
シリアライズするための技術スタックです。データ
通信や永続化において、効率的なデータ変換が求められる場面で重要な役割を果たします。Protocol Buffersは、定義言語、
シリアライズ形式、各言語向けのランタイムライブラリ、そしてコード生成を行うプロトコル
コンパイラから構成されています。
概要
Protocol Buffersは、シンプルさとパフォーマンスを追求して設計されており、特にXMLと比較して大幅な高速化を実現しています。
Googleの主張によると、XMLに比べてデータサイズは3〜10分の1に、処理速度は20〜100倍に向上するとされています。具体例として、XMLで69バイト以上を要するデータが、Protocol Buffersでは28バイトに圧縮され、XMLの解析に5〜10マイクロ秒かかるのに対し、Protocol Buffersでは0.1〜0.2マイクロ秒で完了するとされています。
Thriftプロトコルと類似点が多いものの、Protocol Buffersは明確なRP
Cスタックを持たない点が異なります。この点を補完するために、Protocol Buffersを基盤としたRP
Cスタックが登場しています。Protocol Buffersはオープンソースで提供されており、幅広い開発コミュニティに支えられています。
データ構造とサービスは、プロトコル定義ファイル(.proto)で定義し、protoc
コンパイラでコンパイルします。このコンパイルにより、各言語に対応したコードが生成されます。例えば、「example.proto」をコンパイルすると、「example.pb.cc」と「example.pb.h」といったファイルが生成され、定義されたメッセージやサービスに対応するクラスが含まれます。
Protocol Buffersは、あらゆるフォーマットの
シリアライズを可能にし、公式にサポートされた実装ではリフレクションインターフェースも利用できます。これにより、XMLやと同様に柔軟な
シリアライズ機構を構築できます。また、Protocol Buffersは、ネットワーク
通信の高速化だけでなく、そのシンプルさと高速性から、
C++クラスや構造体の代替手段としても活用されています。
現在、
Googleによって開発されており、
C++、
Java、
Pythonによるオリジナルの実装がオープンソース
ライセンスで公開されています。さらに、ActionScript、
C、
C#、
Clojure、
Common Lisp、
D言語、
Erlang、Go、
Haskell、
JavaScript、
Lua、MATLAB、Mercury、Objective-
C、O
Caml、
Perl、PHP、
R言語、
Ruby、
Scala、
.NET Frameworkなど、多岐にわたる言語で実装が利用可能です。
仕様
インターフェース定義言語
Protocol Buffersは、インターフェース定義言語(IDL)としての側面も持っています。これにより、異なるシステム間でデータ型を意識せずに情報のやり取りが可能になります。
型
protobuf IDLでは、bool、string、bytesを含む15種類のスカラ型と数値型が定義されています。各言語の型がprotobufの型に変換されるため、インターフェースを挟んだシステム間でも型を意識せずにデータ交換ができます。効率性を重視した設計のため、スカラ数値型には固定長と可変長が区別されています(例: fixed32とint32)。
Protocol Buffersは、
シリアライズ形式としても機能します。
エンコーディング
各フィールドは、タグ番号と3ビットの型情報とともに順番にエンコードされます。
整数値のエンコードでは、0に近い数値は少ないバイト数で表現される可変長数値表現が用いられます。7ビット以下で表現できる
整数は1バイトでエンコードされ、int32もint64もエンコード結果は同じになります。タグ番号と型情報も可変長数値表現でエンコードされますが、fixed32やfixed64を使用すると固定長でエンコードされます。
浮動小数点数も固定長でエンコードされます。
文字列やバイト配列は、先頭に長さが付加されてエンコードされます。長さは可変長数値表現で表現されるため、
32ビット制限はありません。
文字列は
UTF-8で符号化されます。
可変長数値表現は、数値をリトル
エンディアンで表現し、7ビット単位で区切って、それぞれの最上位ビットにフラグを立てて
8ビット単位のバイト列に変換します。符号付き
整数の場合は、ジグザグエンコーディングを使用し、正の数に変換してから可変長数値表現を使用します。これにより、-64〜63は1バイト、-8192〜8191は2バイトで表現され、
32ビット整数は最大5バイトで表現できます。
例
以下は、polyline.protoファイルの例です。
protobuf
message Point {
required int32 x = 1;
required int32 y = 2;
optional string label = 3;
}
message Line {
required Point start = 1;
required Point end = 2;
}
message Polyline {
repeated Point point = 1;
}
Pointメッセージは、必須フィールドであるxとy、オプションフィールドのlabelを持っています。各フィールドには一意なタグ番号が割り当てられています。LineとPolylineメッセージは、Pointメッセージを入れ子にした例です。Polylineは、Pointの繰り返しフィールドを持ち、
ベクトルとして扱われます。
メッセージのフィールドには、required、optional、repeatedのいずれかを指定できます。値の型には、プリミティブ型(
整数、
浮動小数点数、bool、string、bytes)を指定できます。optionalフィールドにはデフォルト値を設定でき、repeatedフィールドは
Javaではjava.util.Listとして扱われます。
この定義をprotocでコンパイルすると、PolyLineProtos.javaやpolyline.pb.hなどのファイルが生成され、各言語でProtocol Buffersを利用できます。
java
//
JavaでのProtocol Buffersの利用例
Polyline.Builder polylineBuilder = Polyline.newBuilder();
Point.Builder pointBuilder = Point.newBuilder();
pointBuilder.setX(10).setY(20);
polylineBuilder.addPoint(pointBuilder.build());
pointBuilder.setX(30).setY(40);
polylineBuilder.addPoint(pointBuilder.build());
Polyline polyline = polylineBuilder.build();
C++での利用例
cpp
//
C++でのProtocol Buffersの利用例
Polyline polyline;
Point
point1 = polyline.add_point();
point1->set_x(10);
point1->set_y(20);
Point point2 = polyline.add_point();
point2->set_x(30);
point2->set_y(40);
利用
Protocol Buffersは、
Google社内でデータの保存や構造化された情報の交換に広く利用されています。Protocol Buffersを基盤としたカスタマイズされたRP
C(遠隔手続き呼び出し)システムは、
Google社内のマシン間
通信の基盤となっています。
関連項目
gRPC
Abstract Syntax Notation One (ASN.1)
JavaScript Object Notation ()
Extensible Markup Language (XML)
参照
*
公式ウェブサイト