東京 Ruby 会議 11 直前特集号

13:25 Invited Speaker

最速ウェブサーバの作り方

近年、ウェブの体感速度は、ネットワークのバンド幅ではなくレイテンシによって律速される傾向が強まってきています。また、それに伴い、TCP Fast Open、HTTP/2、TLS 1.3といった、レイテンシの影響を削減/隠蔽する技術の標準化が進んでいます。本セッションでは、HTTP/2サーバ「H2O」の主開発者が、レイテンシの影響削減を主目的とするサーバのプログラミング技法や、HTTP/2の更なる高速化を実現する手法として標準化提案中の「Cache Digest」等を紹介し、それらをrubyから制御する手法を検討します。

必要となる知識

TCP/IPとUnixのソケットプログラミングに関する基礎的な知識があると、分かりやすいかと思います。

奥一穂
株式会社ディー・エヌ・エー

MIT TR100、日本OSS貢献者賞受賞、未踏ソフト認定の天才プログラマー。ウェブ基盤ソフトウェアが専門。代表作にPalmscape/Xiino、Japanize、Pathtraq、Q4M等。最近の仕事はHTTP/2サーバ「H2O」の開発。


5/12 渋谷の株式会社ディー・エヌ・エーにて伺いました(話し手:奥さん、聞き手:笹田)。

発表で話をしたいこと

笹田 「最速ウェブサーバの作り方」というのは、大変キャッチーなタイトルですよね。H2O の話になると思うのですが、その要素技術の話になるんでしょうか。

H2O でやっていることになりますが、一般的に HTTP2 のサーバ実装、あるいはサーバを使うアプリケーションに要求される技術の話になると思います。プロトコルの仕様や、用いたい最適化によって、一般解は決まってくるので、そのような話をしたいと思います。

笹田 HTTP2 の知識は必須になるでしょうか。

要らないと思います。基本的に、レイテンシが重要であり、そのためにどうするか、と議論していくと思います。HTTP1 で何が問題か、といったところから HTTP2 がどう生まれてきたか、のような基本的な話も触れていこうと思います。そして、低遅延な TCP を喋るサーバをどうやって作るか、という課題があり、その辺をどう解決するか、という話になるとおもいます。

笹田 具体的にはどんなものですか。

まず、DNS は無視して話しています。現在、TCP を開くのに 1 RTT (パケット 1 往復分の時間)、TLS で 2 RTT、ページを取ってくるのに最低 1 RTT、JavaScript や CSS を取ってくるのに 2 RTT かかります。

笹田 そんなにかかるものなんですね。

はい。これを、全体で 1 RTT で終わるようにしてしまいましょう、というのが目標になります。具体的には、次のような要素技術を使います。

  1. TCP fastopen を使うことで 1 RTT を削減
  2. TLS 1.3 を使うことで 1 か 2 RTT を削減
  3. 低遅延なTCPサーバプログラミング技術用いることで、1 RTT 削減
  4. Cache digest を用いることで、さらに 1 RTT 削減

というのが、全体像になります。

笹田 凄い。1 RTT になってしまうんですね。今回は、そのような構成をご紹介頂ける、ということでしょうか。

はい。ただ、TCP fastopen や、TLS 1.3 は、自分の提案ではないので、紹介程度に留めると思います。それ以外の、自分が行なった、TCP スタックのうまい使い方や、cache digest を使う、といった話が中心になります。

笹田 それぞれ伺っていってもいいでしょうか。まず、TCP fastopen って何ですか?

TCP のコネクションを開くときに、データを乗せることができます。SYN パケットにデータを付けて。そこにリクエストの情報を付けることができるんですよ。

笹田 もう、カーネルが対応しているんですね。ルータは問題無いでしょうか。

ルータは L4 の内容は関知しないので、ほとんど問題無いです。時々問題になるのが厄介ですが。

笹田 なるほど。

その次に、TLS 1.3 では、early data という仕組みが入っているので、できます。

笹田 もう、そういうのは何もしていなくても使えている、のでしょうか。

TLS 1.3 は、今月ファイナルドラフトになるので、まだ使えません。

笹田 なるほど、まさにもうすぐこうなるよ、という世界のご紹介を頂けるわけですね。

TCP fastopen は 2014 年くらいから導入されて、OS X にも入っている。HTTP2 も、ほぼ入っています。TLS 1.3 は、今年から来年にかけて実装競争になると思います。

笹田 OS の対応を待っていればいいんでしょうか。

TLS 1.3 は、OpenSSL のようなライブラリの仕事になります。

笹田 TLS の層は作らないですよね?

いや、作ります。TLS スタックを実質的に 1 から書き直す話になります。上位互換性があるから 1.3 というバージョンになっていますがが、実質的なメジャーバージョンアップなんですよね。

笹田 え、OpenSSL みたいなものを待つわけじゃないんですね。

OpenSSL はだいぶ遅れるので、作るしかないと思っています。

笹田 あまり、人が近寄るものではないと思っていました。

TLS 1.3 で、仕様がだいぶシンプルになるのと、暗号部分は OpenSSL をそのまま使うことができるので、そこまで大変じゃないと思っています。

笹田 その辺の実装は C++ で作るんですか?

C を使っていますね。他の言語とのバインディングや、性能チューニングを考えると C++ で隠れたコストがでてきてしまうので。

笹田 今何人くらいで作っているんですか?

社内で一人、他社の方で一人、という状況です。TLS 1.3 の実装なんかは、誰かがやってくれるといいんですが。

笹田 低遅延なサーバプログラミングとはなんですか。別のプロトコルにも応用できるんでしょうか。

応用可能です。ただ、これまでは低遅延性を求めるような用途はなかったと思います。HTTP2 は後からより高い優先度のリクエストが届いた場合に、そちらに先に応答しなければならないという事情があるので、低遅延性が重要になってきます。将来に向けて QUIC プロトコルなども提案されていますが、今回は、TCP/IP の上で、システムコールをどう組み合わせていくかという話になります。

笹田 その上にHTTP2を載せるわけですね。以前、別の機会でお話されていましたね (HTTPとサーバ技術の最新動向)。

Cache digest と IETF

はい、cache digest については、以前話した内容に加え、IETF95 でどういう方向性になったのか、ということを紹介しようと思います。

笹田 IETF 95。

4月にブエノスアイレスであって、行ってきました。95 回目のカンファレンスで歴史がありますね。もう引退する、というおじいちゃんが壇上に上がっていたりもします。

笹田 cache digest の仕様が fix されるってところでしょうか。

いえ、今回初めてドラフトを提案したので、まだそういう状況じゃありません。ただ、実装はいくつかのところが出し始めています。

笹田 どういう方がワーキンググループ(WG)に参加されるんでしょうか。

HTTP については、ブラウザ屋さん、サーバ屋さん(apacheなど)、CDN の人達。だいたい同じ割合くらいです。

笹田 奥さんはサーバ屋さんとしてのご参加ですね。淡々と決まっていくんでしょうか。

割と喧々囂々な感じです。

笹田 アジェンダは既に提案されていて、それに対して議論を進めるんでしょうか。

今回、私も初めて参加したのですが。すでに提案されているドラフトから、議長が、注目度など、メーリングリストの反応を見ながら議論するものを判断して、実際に WG で執筆者が発表し、議論していく、という形ですね。

笹田 最終的な結論は、どうやって出すんですか?

WG にもよります。ML で決を採ったりもします。あと、人数の多寡で決まるのではなく、実際に使う人がいるかどうか、ユースケースがあるのか、で決めることが多いようです。

笹田 実際に、議論に参加されたと思うのですが、どういった話があったでしょうか。

今回私は cache digest の話をしてきたんですが、実はうまくいく見込みがたっていました。ドラフトは議長と共著で出したので、議論になると議長が助け舟を出してくれましたし。

笹田 うまくいく見込みがたっていたというのは??

2015年末に日本であった勉強会でプレゼンし、、そこで標準化に携わっている主立った人達にイイネと言われていたのでドラフトを出したという経緯があったのです。

笹田 それで WG で決まった、と。

ML で議論が始まり、それを整理して WG に提出したという感じです。今回の cache digest については、HTTP1 のヘッダに入れるのか、HTTP2 のフレームに含むのか、というのが議論がありました。最初の草稿ではヘッダに入れる、という提案になっていました。ブラウザの修正なしに、プログラムから制御しやすいですから。ただ、長期的に考えればフレームであるべきというのが議長の見解で、現在はフレームという話になっています。一方で、ヘッダとしての定義がないと、標準化前に試してみることが難しくなるので、フレームをメインに、ヘッダも使える、という形に落ち着きそうです。

笹田 基本的な質問ですが、cache digest とは何か、というのも教えて貰えないでしょうか。

クライアントが、どのファイルをキャッシュしているか、という情報を cache digest としてサーバに送ります。サーバは、その情報を見て、まだクライアントが持っていないファイルを送信するだけで済むことになります。

笹田 クライアントが送るものは、そのサーバから以前受信したものになるわけですよね。大きなサイトだと、膨大な量になりませんか。

今のところ、詰めようと思えば、1 ファイルあたり、2, 3 ビット程度に入ります。仕様にはサイズ制限はありませんが、1 パケットのサイズを超えないようにしたいだろう、と考えると、だいたい 1400 octet。これで、数千ファイルの情報を含めることができます。ファイル数が少なければ、1 ファイルあたりのビット数を増やすことができるので、false positive を減らすことができます。

笹田 なるほど。これを、Ruby から制御できるんですか? そもそも、どのレイヤが制御するものでしょうか。

一つは、H2O に組み込まれている mruby、そしてもう一つは Rails などのウェブアプリケーションです。HTML を返すとき、このページがどのファイルに依存しているか、ということを示す link ヘッダというものを付けますが、最近だと preload というものを指定することができます。これを、H2O なんかが解釈して、事前にプッシュしてやることができます。

笹田 なるほど。

しかし、問題があります。ウェブページを構築してから、HTTPレスポンスの一部としてLinkヘッダを送信するのでは、すでに時間が経過してしまっています。本当は、そのページを作り始める前に、それらのリソースを転送開始したいですよね。では、どうすれば良いでしょう。HTTP、あるいはRackやRailsのAPIをどのように改良すれば良いでしょうか。というのが今回の話のもうひとつの要点になります。

笹田 ご発表、とても楽しみです。今日はどうもありがとうございました。