gRPC はとても効率的にサービス同士の接続を可能にします。ヘルスチェックや再接続など基本だけど自分で実装すると面倒な機能もサポートされています。マイクロサービスを構築するのに最適です。
利用できるプログラミング言語が豊富なこともプログラマには嬉しいですね。2016年12月現在、次の言語が公式にサポートされています。
C++ / Java / Python / Go / Ruby / C# / Node.js / Android / Java / Objective-C / PHP
Protocol buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data.
gRPC では好みの Serializer を使うことができます。マイクロサービスアーイテクチャで利用することを考えるとIDLがあることは必須ですし、当然サポートする言語が豊富なSerializerを使うべきでしょう。gRPC はデフォルトでは Protocol Buffers を使います。Protocol Buffers ではデータの定義だけでなく、RPCの定義も合わせて書くことができ、gRPC を実装するためのコードも出力してくれます。
Protocol Buffers では以下のような定義ファイルを作成します。service と rpc で指示子で定義されているものがRPCの定義です。ファンクション名、引数型、戻り値の型を指定します。stream 指示子は戻り値がストリームで扱われ、複数の値を返すことを意味します。
message 指示子を使ってデータ構造の定義を行います。型とプロパティ名を指定し、ナンバリングを行います。この辺は Thrift と似ていますね。enum も使えますし定義はネストして書くことができます。repeated は複数の値を持つことを意味します。配列はありません。(packed というフラグがあり、数値型なら配列っぽく扱える??)
Request が空なのは、rpc 定義の引数にvoidなどは使えないため、何も渡すものがなくても message を定義する必要があります。
これを専用プログラム protoc で対応する言語にコンバートします。簡単な使い方は Github のリポジトリにまとめました。
クライアントは protoc コマンドがジェネレートしてくれるので、クライアントを作成するにはサーバーに接続するコードを書くだけです。サーバー側はジェネレートされたコードにインターフェースが定義されているのでその通りに定義します。
FlatBuffers: FlatBuffers is an efficient cross platform serialization library
gRPC にはカスタムコーデックを定義することが可能であり、Go 言語であればとても簡単に定義することができます 。(https://github.com/google/flatbuffers/blob/master/go/grpc.go)。
最近、FlatBuffers も RPC の定義をサポートし、一部の言語で gRPC を実装するためのコードを出力できるようになりました。上記 person.proto とだいたい等価なIDLが以下になります。
table 指示子でデータ構造を定義します。Protocol Buffers のようにネストすることはできませんが、配列が使えるのとナンバリングの必要がないのが良いですね。使わなくなったプロパティには deprecated フラグを使えます。他にも union など強力な機能もありますので、興味のある方はドキュメントを読んでみてください。
rpc_message 指示子で RPC を定義します。Protocol Buffers とだいたい同じですが、stream の指定の仕方がだいぶ違います。streaming フラグで client, server or bidi のいずれかを指定できます。client であれば引数がストリーム扱いになりますし、server であれば戻り値がストリームになります。bidi は両方ストリームになります。
こちらも簡単なサンプルを作成しました。
多言語間での通信
gRPC も FlatBuffers も多言語間でのやりとりを前提に作られています。C++ と Go で通信するサンプルを作りました。
ブラウザへの対応
Android/iOS ネイティブアプリケーションであれば、JavaやObjective-CはgRPC (+Protocol Buffers) に対応しているためダイレクトに通信することができます。
現在のところとWebブラウザは機能的制限により gRPC で通信することはできません。
もしWebアプリケーションで IDL 定義を使いたい場合などは gRPC から REST へのProxyサーバでバイナリをそのままブラウザに渡し、ブラウザ側でデシリアライズするのが良いと思います。FlatBuffers ならばブラウザで直接読み込めるようなコードを出力してくれます。
gRPC-Web
gRPC をブラウザで使えるようにする取り組みは行われています。特に whatwg/streams がブラウザで動作するようになれば gRPC over HTTP2 でダイレクトにサーバーと通信ができるようになるようです。
- https://github.com/whatwg/streams
- https://github.com/grpc/grpc-experiments/issues/159
- https://github.com/grpc/grpc/issues/8682
Protocol Buffers vs FlatBuffers
FlatBuffers は特にスピードを意識しているシリアライザーであり、ベンチマークでは圧倒的な強さを見せます。
http://google.github.io/flatbuffers/flatbuffers_benchmarks.html
gRPC と組み合わせた時はどうでしょうか?
2つのほぼ等価なIDLを作成してベンチマークを取ってみました。
それぞれ、より良い実装はあると思いますが、単純な実装の比較だと Protocol Buffers の方が若干早く、メモリ消費量も少ないようです。
まとめ
サンプルを交えながら gRPC の使い方を見てきました。またカスタムコーデックとして FlatBuffers も紹介しました。
通常の用途であれば Protocol Buffers が標準のコーデックですし十分高速なので FlatBuffers を使う機会はないかもしれません。しかしながら、ゲームなどのシリアライズ/デシリアライズがよりシビアな環境では FlatBuffers を利用したい用途もあるようです。
個人的にはFlatBuffersのシンプルな構造が気に入っているので、機会があれば使っていきたいです。