[アップデート] ALBでエンドツーエンドのHTTP/2サポートによりgRPCワークロードが可能になりました

ようやくピュアな HTTP/2 が使えるぞ
2020.10.30

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

本日のアップデートにより Application Load Balancer(以下、ALB)でエンドツーエンドのHTTP/2がサポートされ、加えて gRPC プロトコルが利用可能になりました。

ALB でエンドツーエンドの HTTP/2 通信が可能に

以前より ALB は HTTP/2 に対応していましたが、ALB - ターゲット間の通信は HTTP/1.1 に変換されていました。そのため、エンドツーエンドでの HTTP/2 利用できませんでした。この仕様により、HTTP/2 をトランスポートに利用する gRPC を ALB で利用することは出来ないため、NLB または CLB を利用されていたかと思います。

今回のアップデートでターゲットへのプロトコルバージョンを「HTTP/1.1」「HTTP/2」「gRPC」から選択可能となりましたので、HTTP/1.1 に変換することなくターゲットまでの通信を HTTP/2 にすることができます。

gRPC 利用以外にもエンドツーエンドの HTTP/2 利用のメリットとしては、HTTP/1.1 に比べて TCP 接続が効率化されおりプロトコル全体のオーバーヘッドが削減されます。このため、HTTP/2 のほうがレイテンシーやデータ転送コストの節約といった点で優位と考えられます。

以下の例では、HTTP/2 のヘッダー圧縮によりパケットサイズは HTTP/1.1 よりも 33 % 削減されています。

(引用元:Elastic Load Balancing Demos

また、一部のブラウザではプロトコルバージョンが ALB で変換されることで正常に表示できない、といった問題がありましたがエンドツーエンドで一貫したプロトコルバージョンが利用できるため、これらの問題もクリアできそうです。

注意点

gRPC および HTTP/2 プロトコルバージョンに関する考慮事項は以下のとおりです。

gRPC の考慮事項

  • サポートされるリスナープロトコルは HTTPS のみ
  • リスナールールでサポートされるアクションタイプはフォワードのみ
  • サポートされているターゲットタイプは、インスタンスと IP のみ
  • ロードバランサーは gRPC リクエストを解析し、パッケージ、サービス、メソッドに基づいて適切なターゲットグループに gRPC 呼び出しをルーティングします
  • ロードバランサーは Unary、Server-side streaming、Client-side streaming、Bi-directional streaming をサポートします
  • カスタムのヘルスチェックメソッドを /package.service/method という形式で提供する必要があります
  • ターゲットからの応答が成功したかどうかをチェックする際に使用する gRPC ステータスコードを指定する必要があります
  • ターゲットとして Lambda 関数を使用することはできません

HTTP/2 の考慮事項

  • サポートされるリスナープロトコルは HTTPS のみ
  • リスナールールでサポートされるアクションタイプはフォワードのみ
  • サポートされているターゲットタイプはインスタンスと IP のみ
  • ロードバランサーはクライアントからのストリーミングをサポートしますが、ターゲットへのストリーミングはサポートしません

リクエストプロトコルとプロトコルバージョンの対応表

リクエストプロトコルとターゲットのプロトコルバージョンの組み合わせによって、通信できないパターンがあるため押さえておきましょう。

リクエストプロトコル プロトコルバージョン 結果
HTTP/1.1 HTTP/1.1 成功
HTTP/2 HTTP/1.1 成功
gRPC HTTP/1.1 エラー
HTTP/1.1 HTTP/2 エラー
HTTP/2 HTTP/2 成功
gRPC HTTP/2 ターゲットがgRPCをサポートしている場合の成功
HTTP/1.1 gRPC エラー
HTTP/2 gRPC POSTリクエストの場合は成功
gRPC gRPC 成功

やってみる

今回はエンドツーエンドでの HTTP/2 を試して、一部ブラウザで発生していた表示エラーが出ないことを確認してみたいと思います。

gRPC についての検証記事は公式ブログにあがっていますので、そちらを参照いただければと思います。

今回の構成

今回は以下のように 443 ポートでアクセスした場合には HTTP/2 へ、8443 ポートでアクセスした場合には HTTP/1.1 へ転送するような構成としています。

ターゲットグループの作成

AWS コンソールからターゲットグループの作成を開くと、プロトコルバージョン の選択メニュー増えています。今回は HTTP2 として 80 ポートへのターゲットグループを作成します。(HTTP1 の手順は割愛します)

リスナーの設定

以下のとおり 4438443 のリスナーを作成しています。443 のリクエストは HTTP/2 プロトコルバージョンを選択した http2-80 のターゲットに流れます。8443 のリクエストは HTTP1 プロトコルバージョンを選択した http1-8080 のターゲットに流れます。

確認

今回は Safari バージョン14.0 (15610.1.28.1.9, 15610) のブラウザで確認します。

HTTP/1.1 へのリクエスト

まず、従来の HTTP1.1 に変換される経路へリクエストします。Safari は上述の問題(リクエスト途中で HTTP/1.1 に変換されると正常に表示されない)に該当するブラウザですので、想定ではエラーになります。

やはり正常に開くことができませんね。サーバー側の access_log を参照すると HTTP/1.1 でリクエストが届いていることが判ります。

192.168.0.185 - - [30/Oct/2020:03:04:20 +0000] "GET / HTTP/1.1" 200 21 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15"

HTTP/2 へのリクエスト

それではエンドツーエンドで HTTP/2 の経路にリクエストします。

正常に開くことができましたね!サーバー側の access_log を参照すると HTTP/2 でリクエストが届いていることが判ります。

192.168.1.212 - - [30/Oct/2020:03:05:05 +0000] "GET / HTTP/2.0" 200 21 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15"

検証は以上です!

さいごに

エンドツーエンドの HTTP/2 が利用できるようになったことで gRPC の利用だけでなく、プロトコル全体のオーバーヘッド削減など HTTP/2 固有のメリットが受けられるようになりました。

個人的には今回検証した「HTTP2/HTTP1.1 変換による一部ブラウザで表示できない問題」に何度かハマったことがありましたので、これが解決してくれるだけでも非常に嬉しいかぎりです。

実環境での HTTP/2 利用によるパフォーマンス比較なども、おいおいブログ記事としてあがってくることでしょう。(他力本願)

以上!大阪オフィスの丸毛(@marumo1981)でした!