エクストーンの金です。RubyKaigi2023 では多くの注目トピックスがありましたが、ここでは HTTP/3 のはなしを紹介します。
Unleashing the Power of Asynchronous HTTP with Ruby
というタイトルで、HTTP をめぐる33年の歴史と Ruby における HTTP/3 対応の紹介がありました。
地味な題材ですが、Samuel Williams 氏によるすばらしいセッションでした。
HTTPの誕生と歴史
いま日常的に使われている HTTP は1990年に生まれました。 世の中でようやく Windows3.0 が発売された年です。 (筆者はまだ Windows すら知らず、MS-DOS を使っていました)
最初の HTTP は HTTP/0.9 というバージョンのシングルメソッドであり、扱えるメディアもテキストのみでした。いまから考えると信じられないほどシンプルで低機能です。
その後以下のような変遷を遂げます。
- HTTP/0.9
- GET のみ、扱えるメディアはテキストのみ
- 1コネクションにつき1リクエストのみ
- エラー検知もなし
- HTTP/1.0
- PUT, POST, DELETE などがサポートされマルチメソッド化
- ステータスコードをサポート
- 画像などMIMEコンテントをサポート
- リクエスト/レスポンスヘッダをサポート
- HTTP/1.1 (1999)
- コネクションの永続化によりマルチリクエスト対応
- Content-Length などもサポート
HTTP/1.1 の時点で現在に通じる HTTP の基礎形が固まったと言えます。 いまでも数々の Webサイト、Webアプリケーション が HTTP/1.1 を前提に設計・構築されています。
いやしかし、この時点でなつかしさがあふれます。
HTTP とそれを元にした WWW (World Wide Web) の世界は CERN (セルン : 欧州原子核研究機構) で生まれました。いま CERN と聞くと、ゲームやアニメでおなじみの『シュタインズ・ゲート』に登場する謎の組織を思い浮かべる人の方が多いかもしれません。しかし現実世界の CERN は HTTP と Web の発祥としてわたしたちの日常に深くかかわっています。
筆者も学生時代の計算機センターではじめて UNIX とインターネット *1 の世界に触れて、まだ数えるほどしかなかった *2 Webサイトを眺めたり、その後Webブラウザとして人気になった NCSA Mosaic をワークステーション上でコンパイルして動かしていました。*3
21世紀の HTTP へ
HTTP は本来シンプルに、かつ富豪的に、リクエストごとに通信してデータを取得するだけプロトコルでした。 しかし、シンプルさゆえにネットワークアプリケーションの基盤になってしまい、現代的な機能や動作を求められるようになります。
その後以下のような変遷を遂げます。
- HTTP/2 (2015)
- リクエストごとのリソース転送を多重化
- ヘッダ圧縮
HTTP/2 は Google が Chrome で独自に拡張していた SPDY が後追いで標準化されたものですが、Webページやアプリケーションにおいて必要となった多重リクエスト *4 を意識して拡張されています。
これ自体はすばらしい進化だったのですが、こういった多重通信をするリクエストが貧弱な通信環境で行われると十分な結果が得られないという新しい弱点も認識されました。*5
こうした弱点を解消する最新形が HTTP/3 です。
- HTTP/3 (2020)
- 信頼性の低いネットワークでの動作向上
- ストリームコントロール、TLS などのレイヤを UDP の QUIC でドライブ
HTTP/3 はトランスポート層として TCP でなく UDP を使うQUICをベースにしており、これにより信頼性の低いネットワークでも十分な動作を得られるように考えられています。*6
これまでは TCP ベースだったので、一連の通信レイヤのどこかで通信断などがあると後続の処理がすべて待たされてしまうことがあったのですが、通信断が起きたリクエストやレイヤ以外は非同期に進行できるようになりました。
Async::HTTP
こうして HTTP/3 は生まれましたが、Ruby においては HTTP/2 以降をサポートしているアダプタがほとんどありませんでした。 なぜなら、HTTP/3 をサポートするためには多重化モデルが必要であり、その点がハードルであったためです。
しかしようやく Async::HTTP が登場し、Ruby も HTTP における33年の歴史を受け止めました。
セッションでデモされたコードには、わずか10行の実装で HTTP/3 への対応ができていました。しかしここには「33年ぶんの蓄積」が入っていると強調されました。 おおざっぱに言ってしまうと、「node.js のような非同期実行を前提とした記述ができるようになった」と言えばイメージが伝わるでしょうか? この Async::HTTP によって、共有インスタンスやファンアウト同時実行などが実現されます。
個人的には、この実装が HTTP::Async ではなく、Async::HTTP であるのは大きな意味があるように思います。「最初に非同期の Async という概念と動作があり、それをベースにドライブされる HTTP」という考え方を感じました。
おわりに
かくして Ruby においても HTTP/3 の時代がやってきたわけですが、Samuel 氏の発表は内容もすばらしく、話の構成も参加者を引き込む仕掛け満載で、しかもとても平易で聞きやすい英語でした。
アフターフォローとして本セッションに関連した資料・サンプルコードなども公開されていますので、興味を持った方はぜひ HTTP/3 の世界をのぞいてみてください。
*1:世間的にはまだインターネットという言葉も存在も普及しておらず、ネットと言えばパソコン通信という認識だった
*2:国内で新しく立ち上がったWebサイトを網羅的に紹介する "What's New in Japan" というサイトが成立するほどでした
*3:Netscape Navigator がブームになって界隈を席捲するのも後のはなしで、Googleにいたっては起業すらされていませんでした
*4:ひとつのコンテンツを取得するために画像、CSSなど複数のリクエストが必要になる
*5:単一のHTTPリクエストとしても暗号化を行うTLSなど、複数のセッションが必要となる
*6:移動体通信などにおいては、通信経路変更などによる接続回復が重要