gRPCアプリをAWS ELBで負荷分散してみた

2016.09.26

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、大瀧です。
先月GAを迎えたGoogle製RPCフレームワークgRPCをちまちま触っています。

gRPCクライアントからgRPCサーバーへの負荷分散は、GitHubでクライアントサイドの例が紹介されていますが、今回はAWSのELB(Elastic Load Balancer)を用いたL4ロードバランサによる負荷分散を試してみた様子をレポートします。

ELBのgRPCサポート状況

gRPCは、HTTP/2上にProtocol Buffers形式でデータの送受を行います。HTTP/2サポートと言うと、AWSでは最近追加されたApplication Load Balancer(ALB)を連想するところですが、ALBがHTTP/2に対応しているのはリスナーであり、ターゲット(バックエンド)へのHTTP/2転送には対応していません。また、こちらのブログ記事に倣いALBのバックエンドにnghttpxを置いてHTTP/1.1からHTTP/2へのリバースプロキシとして組み合わせてみましたが、ALBがTEヘッダを転送しないようでうまく接続できませんでした。以下のGoogleグループでも話題になっています。

Classic Load Balancerは、HTTP/2には非対応ですがL4(TCP)ロードバランサーとして設定することでgRPCのトラフィックを転送することができます。というわけで今回はClassic Load BalancerのTCPモードで試してみます。

検証環境

  • EC2 : Amazon Linux AMI 2016.03.3 (HVM), SSD Volume Type - ami-374db956

サーバー側は、gRPCのGo版サンプルのサーバーアプリケーション("Hello world"というメッセージを返す)を以下のユーザーデータでDockerコンテナとして実行しました。

#!/bin/bash
yum install -y docker
service docker start
chkconfig docker on
docker run -d \
	-p 50051:50051 \
	grpc/go:latest \
	go run /go/src/google.golang.org/grpc/examples/helloworld/greeter_server/main.go

ポート番号50051番でListenするので、ELBからアクセスできるようにセキュリティグループを調整しましょう。

続いてClassic Load Balancerを作成します。今回はTCP:50051からTCP:50051に転送するように設定しました。

grpc-elb01

ヘルスチェックも同じTCP:50051にしておきます。

grpc-elb02

これでOKです。手元からはNode.js版サンプルのクライアントの接続先を以下のように変更しました。

   var client = new hello_proto.Greeter('XXXXXXXX.ap-northeast-1.elb.amazonaws.com:50051',
                                        grpc.credentials.createInsecure());

では、実行してみます。

$ node greeter_client.js
Greeting: Hello world
$

正常に接続することが出来ました!

まとめ

ELBをgRPCサーバーのロードバランサとして利用するために、Classic Load BalancerのTCPモードをご紹介しました。今回は単発のリクエスト/レスポンスの例でしたが用途によってはLong Pollingなど長時間接続する場合もあると思うので、Classic Load Balancerのアイドルタイムアウトの設定を調整すると良いと思います。

また、今回はTCPモードなので取れませんが、プロキシなどでアクセスログを取得しデバッグするときはgRPCのGitHubのHTTP/2仕様が有用だと思います。

余談

SSL Terminationもできるかな?とACMの証明書をClassic Load BalancerにセットしてリスナをSSL(セキュアTCP)にしてみましたが、Missing selected ALPN propertyというエラーになったので、Classic Load BalancerがTLSのALPN拡張に対応してなさそうでした。