サーバ・クライアント間でデータをやり取りするとき、ネットワーク帯域がボトルネックになるケースは多いです。
gRPCはProtocol Buffersによってデータのシリアライズをしており変数名などはタグ化されるし、数値型はちゃんと数値データとして送信されるので、JSONに比べて通信量的に有利です。
しかし所詮はその程度なので、大量のデータをやり取りすることを考えるときちんとデータを圧縮するべきです。
go言語のgRPCパッケージにはgzip圧縮用のライブラリが組み込まれており、少ないコードで通信をgzip圧縮できます。
サーバ側
(省略)
import (
"google.golang.org/grpc"
_ "google.golang.org/grpc/encoding/gzip"
:
(省略)
"google.golang.org/grpc/encoding/gzip"をアンダースコア付でインポートする。それだけです。
こうすると、起動時にinit関数が呼ばれて、gzip圧縮ができるサーバとして動作します。
クライアント側
(省略)
import (
"google.golang.org/grpc"
"google.golang.org/grpc/encoding/gzip"
:
(省略)
func main() {
conn, err := grpc.Dial("localhost:19003", grpc.WithInsecure())
if err != nil {
log.Fatal("client connection error:", err)
}
defer conn.Close()
client := hogegrpc.NewHogegrpcClient(conn)
message := &hogegrpc.GetDataMessage{TargetCode: 0}
response, err = client.GetData(context.TODO(), message, grpc.UseCompressor(gzip.Name))
(省略)
サーバ側と同じくgzip圧縮のパッケージをimportします。こちらはアンダースコア無し。
そしてgRPCで実行する関数の可変引数部分に、grpc.UseCompressorを指定してあげます。
こうすると、クライアントからサーバに接続する時に「gzip圧縮できるよ」という情報が渡り、gzip圧縮してデータのやりとりができます。
見ての通り関数呼び出しごとに指定するため、文字列等の圧縮が効きやすいデータはgzip圧縮して通信、メディア等の圧縮済みのデータをやりとりするなら無圧縮、という使い分けが容易です。
性能試験
適当なオープンデータを垂れ流すgRPCサーバを立てて試験しました。
内容は数値半分、文字列半分。1レコードあたり400byte前後のデータになります。
送信するパターンは1レコードずつ送信・全レコード(4,900件)一括送信の2つ。
試験環境はサーバ/クライアントを同一マシン上に置いたパターンと、別マシン上に置いて無線LANで通信させるパターンで測定します。
時間は関数呼び出しの前後で取得し、「クライアントから要求を出して、クライアント上でデータのデシリアライズが終わるまで」を測定します。
1レコードずつ送信
1回400byte前後のデータをやりとりします。
通信先 | 無圧縮 | gzip圧縮 |
---|---|---|
localhost | 0.10 ms | 0.50 ms |
無線LAN上 | 1.87 ms | 2.20 ms |
えー、大々的に言ったわりにgzip圧縮は遅い。
圧縮・展開にかかるオーバーヘッドがかなり大きいことと、たかが400byte程度のペイロードでは1パケットに収まってしまうので、圧縮しようがしまいが通信量が変わらないことが原因でしょう。
全レコード一気に送信
1回1,900Kbyte程度のデータをやりとりします。
通信先 | 無圧縮 | gzip圧縮 |
---|---|---|
localhost | 15.81 ms | 30.08 ms |
無線LAN上 | 190.06 ms | 56.51 ms |
通信量が増えるとgzip圧縮の効果が見えてきます。
localhost上ではさすがにネットワーク帯域がボトルネックにならないので圧縮するだけ不利ですが、無線LAN上のマシンに対しては3~4倍近い性能差が出せています。
ちなみにスループットは100Mbps超ぐらい出ており、明らかに無線LANの帯域がボトルネックです。
まとめ
以下を満たす条件では、gzip圧縮を検討する価値があります。
- ネットワーク帯域がボトルネックだ
- 通信するデータが文字列や数値など、圧縮効果が見込める
- 一度に転送するデータが1パケットに収まらない
gRPCがなんだか遅いな、っていう人は試してみるといいんじゃないでしょうか。