HTTP/2.0と今後のWebアプリケーションの開発・運用について (#cross2014)

追記 @jovi0608 さんに非常に丁寧にコメントをいただきました。

https://gist.github.com/shigeki/ba7941d114344ddd4b01

本文 CROSS 2014の次世代Webセッションに参加した。 いろいろ刺激を受けたので、特に、Webアプリケーションを開発・運用する上で、今後どう影響してくるだろうみたいな視点で整理したことを書いてみた。

次世代Webセッションは去年もUSTで見てて、めっちゃ面白かったので、今年は生で聞きに来た。 去年のセッションの議論は、 naoyaさんの記事が雰囲気がわかりやすかった。

去年、SPDYの内容とか追ってて、HTTP/1.1と何が違うのかみたいなことを調べて書いたりしてた。

次世代Webセッションの特にプロトコル編は前提知識ないと全然追いつけないという事前情報があったので、東京行く前に復習してた。 去年は、わかりやすく解説してくれる日本語記事少なかったように思うけど、この一年でいい情報増えててありがたかった。 いろいろ読んだけど、SPDYについては特に以下の記事が要点がまとまっててすばらしい感じだった。

ネットワークパフォーマンスやスケーラビリティについては以下の記事が参考になる。

今年の様子は、UstreamとTogetterがある。

去年はbreak the webという言葉がでていたけど、QUICの登場により今年は、TCP/IPを壊す という話まででてしまった。 TCP/IPの代わりみたいな話は過去に無限にあると思うけど、Webの話からの流れで、TCP/IPの代わりの話ってまずないと思う。 QUIC自体はTCP/IPを壊すというものではないけど、TCPの代わりに独自のフロー制御/輻輳制御をやるということは、Webが確実にそのレイヤに侵食しはじめたということなのかもしれない。(TCPの公平性みたいな話どう担保するのか気になる)

Webアプリケーションの開発・運用にどこまで影響するのか

HTTP/2.0を導入するメリットとか導入の際に注意するべき立場によって違うと思う。 当日の話を聞いたり、自分で調べたりして、特に自分のレイヤーに関係してきそうなことを並べてみた。 HTTP/2.0はまだ仕様が策定中なので、今後状況は変わってくるかもしれない。(セッション中に、GoogleがWebSocket over SPDYをやってみてHTTP/2.0に還元するみたいな話もあった)

ちなみに、HTTP/2.0の仕様はGitHubで管理されてる。

http2/http2-spec · GitHub

2013/01/20現在、draft-ietf-httpbis-http2-09 - Hypertext Transfer Protocol version 2.0が最新の仕様で、日本語訳もある Hypertext Transfer Protocol version 2.0 (draft-ietf-httpbis-http2-09) 日本語訳

アプリケーション実装視点

  • 1リクエストのコストが減る
  • スマートフォン環境でのレスポンスタイム削減
  • コンテンツのロード順制御
  • クライアントライブラリが実装困難
  • リファラがとれないケース
  • 1リクエストのコストが減る

まず、1リクエストのコストが減る(毎回3-wayハンドシェイクをしない)ため、クライアントサイドでの異常なキャッシュをしなくていいケースがでてくるかもしれない。

  • スマートフォン環境でのレスポンスタイム削減

次に、3-wayハンドシェイクの回数が少ないため、無線環境のような高レイテンシ環境でパケットロスによる再送が減り、結果レスポンスタイムが小さくなる。 スマートフォンアプリ/スマートフォン対応サイトにはかなり有利だと思う。 ただし、後ろでも書いてるけど、パケットロスが多すぎると、スループットがでない。

  • コンテンツのロード順制御

さらに、ストリームの優先度制御により、例えばHTML、CSS、JavaScriptなどコンテンツの種類に応じてクライアント側でレスポンスの処理順を制御できる。例えば、CSSレスポンスの処理を優先することができたりするため、CSSが適用されないページが一瞬だけ見えてしまうというような問題を避けられるかもしれない。CSS Spriteみたいな異常なテクニックがいらなくなる。 ストリームの優先度制御について、仕様には以下のように書いてある。

5.3. ストリームの優先度

新しいストリームを確立するエンドポイントは、ストリームに対して優先度を割り当てることができます。優先度は符合なし31ビット整数で表現されます。0は最も高い優先度を表し、231-1は最も低い優先度を表します。

この値の目的は、あるストリームのフレームが、他の並行するアクティブストリームよりも高い優先度で処理されることを、ストリームを開始したエンドポイントが要求できるようにすることです。これにより、あるエンドポイントが複数のストリームからインターリーブされたフレームを受信した場合、そのエンドポイントは、優先順位の低いストリームのフレームを処理するより前に、優先度の高いストリームのフレームの処理をベストエフォートで試みるべきです。 http://summerwind.jp/docs/draft-ietf-httpbis-http2-04/#section5-3

ベストエフォートと書いてあるので、優先度は絶対ではないっぽい。 必ず優先度通りにしてしまうと、クライアントのレスポンスを全部受け取らないと判断できないからだと思う。

  • クライアントライブラリが実装困難

さらに、スマートフォンアプリを含むネイティブアプリでHTTP2.0で通信しようとすると、既存のHTTPクライアントライブラリをそのまま使えなくなる。 もちろん、ライブラリが対応すれば使えるようになると思うけど、HTTP2.0やSPDYはHTTP1.xよりははるかに複雑なプロトコルになっていて、容易に実装できないので、まともに使えるライブラリは限られてくると思う。

  • リファラがとれないケース

最後に、場合によってはリファラがとれないというのがある。 HTTP2.0はTLSの上で通信する(HTTPSで通信する)ため、https://のページからhttp://のリンクにとぶと、リファラが送出されなくなる HTTP/1.1: Security Considerations。 (仕様にはSHOULD NOTと書いてあるので、絶対ではない) 会員制のサービスのように、自前のサービスで完結しているところは気にしなくていいけど、ブログサービスとかニュースサイトやっているところが、HTTPSになってしまうと、自分のサイト(https://)から広告サイト(http://)への流入量とかわからなくなるかもしれない。 なぜリファラを送出しないかというと、https:// => http:// は社内Wikiとかに外部のhttp://リンクを張ってそのリンクを踏んでしまうと、平文のリファラに社内WikiのURLが含まれてしまうなどの不都合が起きるからだと思う。 http:// => https:// についてはよくわからない。 ちなみに、TLS必須にするかどうかはまだ議論中らしい。SPDYでは必須になってる。

オペレーション視点

  • TLS処理負荷
  • サーバプッシュ
  • C10K回避
  • ストリーム優先度調整
  • ALPNのネゴシエーションキャッシュSSLセッションキャッシュ
  • CDNのHTTP2.0対応
  • TLS処理負荷

まず、HTTPS前提なのでサーバサイドでの暗号化処理の負荷が高まる。proxyの前段のSSLアクセラレータを増やすなど、CPU負荷を分散したりする必要がある GPUを用いたSSLリバースプロキシの実装について - ゆううきブログ

  • サーバプッシュ

クライアント・リバースプロキシ間だけでなく、リバースプロキシ・Webアプリケーションサーバ間もHTTP/2.0にしないと、サーバプッシュの利用の仕方が制限されるかもしれない。HTTP/2.0のサーバプッシュについては仕様に以下のような説明がある。

例えば、サーバーが複数の画像ファイルへのリンクが埋め込まれた文書のリクエストを受信し、サーバーがそれらの画像をクライアントにプッシュすることを選択したとします。このような場合、その画像リンクを含む DATA フレームよりも前に PUSH_PROMISE を送信することで、クライアントがそのリソースを見つける前に予約を確認できることを保証します。同様に、ヘッダーブロックが参照するリソース (例えば、Link ヘッダーフィールドなど) をプッシュする場合は、ヘッダーブロックを送信する前に PUSH_PROMISE を送信することで、クライアントがそのリソースにリクエストしないことを保証します。 http://summerwind.jp/docs/draft-ietf-httpbis-http2-09/#section8-2-1

上記の前後の仕様を読む限り、プッシュ対象のコンテンツの取得方法は規定されていないようにみえる。

リバースプロキシのみHTTP/2.0対応すればよいケースは以下の様な感じだと思う。 ある文章に含まれた画像リンクをリバースプロキシへのレスポンスに含まれるX-Associated-ContentヘッダにWebアプリケーションサーバが入れて、リバースプロキシは文章をまずクライアントにレスポンスしてからリクエストを待たずにX-Associated-Contentヘッダに含まれるリンクの画像を取得するとかになるかもしれない (X-Associated-Contentのやり方はmod_spdyのやつ https://code.google.com/p/mod-spdy/wiki/OptimizingForSpdy#Using_SPDY_server_push)

逆にWebアプリケーションサーバがHTTP/2.0に対応しなければならないケースは、Server Sent Eventsのように、クライアントがコネクションを切るまでサーバがリソースをプッシュし続けなければならない場合だと思う。 リソースをプッシュし続ける場合は、Webアプリケーションサーバからリバースプロキシに対して専用のHTTPヘッダをつけてプッシュして、リバースプロキシがそのプッシュを受けてクライアントにプッシュする必要がある。 ただし、リバースプロキシにWebアプリケーションサーバからのプッシュを受け付けるような機能が実装されるかどうかはわからない。 Webアプリケーションサーバからのプッシュについてはアプリケーションエンジニアの対処も必要になってきそう。

後者については、無理せずにServer Sent Events使ったらよい気がする。サービス内部のトラフィックだと、RTTがそもそも大きくないので、シンプルなアーキテクチャであるHTTP/1.1をなるべく使いたい。

  • C10K回避

あとは、多重化やサーバプッシュのおかげでとにかくコネクション数が抑えられるので、単純にC10K的な問題が抑えられそう。 ファイアフォールのトラッキングテーブル(ip_conttrackとか)溢れなんかも抑えられそう。

  • ストリーム優先度調整

特定のクライアントが悪意をもってストリーム優先度を最大にしてしまうと、そのクライアントへのレスポンスを優先してしまうというような問題があるという話もあった。 Googleが重み付き木を使った解決策を提案しているらしい。

  • SSLセッションキャッシュ

ALPNのネゴシエーションのせいで最初のコネクション確立周りのRTTが増えるので、これが気になる場合は接続情報をキャッシュしたりするかもしれない。 (01/25追記) リバースプロキシの前段にロードバランサをおいている場合、同じクライアントが同じプロキシにコネクションを張るとは限らないので、プロキシ間でmemcachedなどを使って接続情報をキャッシュする必要があるかもしれない。

SSLセッションキャッシュ: Speeding up SSL: enabling session reuse | Vincent Bernat

  • CDNのHTTP2.0対応

あまりちゃんと見てないけど、Akamaiとかが対応してくれる感じがするので、画像コンテンツをCDNにおいている場合、ほとんど何もしなくても、HTTP/2.0の恩恵が受けられる可能性がある。

SPDY and WebSocket Support at Akamai - The Akamai Blog

ちゃんと仕様を読むと、解決されている問題もあるかもしれない。 今回挙げた以外にもまだまだ影響するところはたくさんあると思う。

その他

QUICは、最初のALPNのネゴシエージョンとか含めて、TCP Fast Open的な感じでRTTを減らす感じらしい。 TCPコネクションを1本化すると、もし高レイテンシな環境でパケットが落ちまくる場合、TCPのウィンドウサイズが増えないので、スループットが全然あがらないという問題も、何かいい感じに解決してくれるらしい。(ソースがどこか忘れてしまった) 仕様もないので、具体的にやっていることがよくわからない。

WebRTCの話もあった。 自分の環境だと、WebRTCみたいなP2Pの仕組みが必要なほどレイテンシ要求がシビアなアプリケーションを触らないと思う。 LINEはサーバ介して普通に低レイテンシで捌けてるし、今のところゲームくらいしか用途がなさそうなイメージがある。 オンラインゲームを支える技術とか読むとレイテンシの厳しさがよくわかる。

オンラインゲームを支える技術  ??壮大なプレイ空間の舞台裏 (WEB+DB PRESS plus)

オンラインゲームを支える技術  ??壮大なプレイ空間の舞台裏 (WEB+DB PRESS plus)

まとめ

ゲームとかリアルタイムWeb的なアプリケーションがHTTP/2.0の恩恵を受けられるのは間違いないけど、スマートフォン時代ということを考えると、それ以外のアプリケーションでもパフォーマンス的なメリットは大きそうに思う。 一方で、ブログのようなオープンインターネット的なサービスだと、暗号化前提な世界観によりリファラがとれないなどの問題がでてきて、サービス展開に影響がでてきそうな危惧がある。

参考

High Performance Browser Networking: What every web developer should know about networking and web performance

High Performance Browser Networking: What every web developer should know about networking and web performance