読者です 読者をやめる 読者になる 読者になる

ブログのしゅーくりーむ

技術的なメモとかライフログとか。

Apache Traffic Server の設定やちょっとした制御ロジックを mruby で書けるようになるかもしれないプラグイン書いてる

mod_mrubyngx_mrubyh2o_mrubylibvmod_mruby など、さまざまな HTTP サーバの設定などを mruby スクリプトで書ける世の中になりつつありますね。 そんな風潮の後押しもあり、近頃、題意の通り mruby で ATS(Apache Traffic Server) の設定やヘッダの加工などのロジックを mruby で記述可能にするプラグインts_mruby をちまちまと開発しています。

ts_mruby によって例えば下記のようなロジックが mruby で書けるようになります。

  • リクエストヘッダを付与したり削除する
if server_name == "NGINX"
  Server = Nginx
elsif server_name == "Apache"
  Server = Apache
elsif server_name == "ApacheTrafficServer"
  Server = ATS
end

# rewrite request headers
r = Server::Request.new
conn = Server::Connection.new
r.headers_in["X-ATS-Plugin"] = "ts_mruby"
r.headers_in["X-Forwarded-For"] = conn.remote_ip
r.headers_in.delete("Cookie")
  • 特定 IP 以外からのリクエストを弾く
if server_name == "NGINX"
  Server = Nginx
elsif server_name == "Apache"
  Server = Apache
elsif server_name == "ApacheTrafficServer"
  Server = ATS
end

whitelist = [
  "127.0.0.1"
]

# deny if client IP isn't listed in whitelist
conn = Server::Connection.new
unless whitelist.include?(conn.remote_ip)
  Server::echo "Your access is not allowed ..."
  Server::return Server::HTTP_FORBIDDEN
end

ATS でプラグインをロードする際、グローバルプラグイン(ATS 全体に作用するプラグイン)や Remap プラグイン(各リクエストをプロキシする際に作用するプラグイン)という形態を採ることになるのですが、 ts_mruby ではそのどちらもサポートしています。 全リクエストで動作させたいのか、特定 VirtualHost や パスだけに対して動作させたいのか、など要件によって使い分けることが可能です。

  • グローバルプラグインとして使う場合、 plugin.config に下のように記述
# write here if you hope to apply all of requests
ts_mruby.so etc/trafficserver/unified_hello.rb
  • Remap プラグインとして使う場合、 remap.config に下のように記述
# write here if you hope to apply only accesses to /test
map /test http://127.0.0.1/ @plugin=ts_mruby.so @pparam=etc/trafficserver/unified_hello.rb

現状サポートしている ts_mruby の mruby 向けクラス、メソッド は mod_mruby, ngx_mruby と共通の名前、機能にするよう気をつけています。 mruby を HTTP サーバ設定の DSL として使うこともできるようになるかもしれません(ただし各サーバ固有の機能の部分はどうしても出てくるわけで、その部分をどう扱うか悩みどころです)

ts_mruby は現状、細々と個人で開発をしている状態です。なにかご意見や Pull-Request などいただけると幸いです。

JMeter で HTTP/2 リクエストを送れるようにするプラグインを書いてみた

表題の通り、 JMeter で HTTP/2 リクエストを送ることを可能にする HTTP2 サンプラーを追加するプラグインを書いてみました。

github.com

但し、今のところ単純な GET リクエストを、しかも 1 request / connection で送る程度のことしかできず、パフォーマンステストをする上で必要な機能が十分にあるとは言えない状態です。 HTTP ヘッダマネージャによるリクエストヘッダの編集、アサーションでのレスポンスコード、レスポンスメッセージ、レスポンスヘッダのチェックはできるので、何か単純なサーバの動作確認を実施する程度になら使えるかも知れません。

プラグインを導入すると、下図のように HTTP/2 Sampler という項目が追加されます。 HTTP/2 Sampler を追加して項目を埋めていくことで HTTP/2 リクエストの送信が実現できます。 f:id:syu_cream:20150706002423p:plain

HTTP サンプラーで使われるヘッダマネージャを、 HTTP/2 Sampler でも使用できます。 f:id:syu_cream:20150706002039p:plain

HTTP/2 Sampler では現在、サーバの IP 、ポート、パスを指定できるようにしています。 今後必要な項目を用意していきたいところです。(レイアウトが残念なことになっているのでそれもどうにかしたい f:id:syu_cream:20150706002832p:plain

テスト結果はアサーションで検査したりリスナーで一覧、保存できたりします。 jtl ファイルに出力させれば、 Jenkins の Performance Plugin に解釈させることも可能なはず。 f:id:syu_cream:20150706002817p:plain

RFC 7541 (HPACK) の日本語訳を公開しました

表題の通り、 RFC7541 "HPACK: Header Compression for HTTP/2"日本語訳されたドキュメント を公開しました。 今のところ GitHub の僕のリポジトリにて編集管理を行っています。(将来的には別の管理の仕方をするかもしれません)

前回日本語訳を行った時点(draft-10) から RFC になるまでの、記述上の細かい修正の追従が主になります。また、前回イマイチだった箇所の日本語訳も少し修正しています。

問題点の指摘や翻訳の改善の Pull-Request 、大歓迎です。 こちら よりお願いします。

末筆ですが、やっと HTTP/2 , HPACK の RFC が出ましたね!これまで変更を追従してきた皆様お疲れ様でした。

HPACK draft-10 の日本語訳を公開しました

表題の通り、 HPACK draft10日本語訳されたドキュメント を公開しました。 今のところ GitHub の僕のリポジトリにて編集管理を行っています。(将来的には別の管理の仕方をするかもしれません)

問題点の指摘や翻訳の改善の Pull-Request 、大歓迎です。こちら よりお願いします。

HTTP Alternative Services について

本稿は HTTP2 Advent Calendar 2014 20 日目の記事です。 本稿では HTTP/2 周辺のトピックでもやや地味な部類に入るであろう、 HTTP Alternative Services について簡単に触れていきます。

  • 2014-12-21 19:20 用語の修正

概要

HTTP Alternative Services とは、 HTTP で配信するリソースを他のプロトコル、ホスト、ポート番号でもサービス提供ができることを通知する仕組みです。 用途としては下記のようなものが想定されます。

  • メンテナンス等のためサーバをダウンさせる前に、他のサービス可能なサーバを提示する
  • 新しいプロトコルへの切り替えを提案する(HTTP/1.1 から HTTP/2 へ、など)
  • 日和見暗号(サーバ認証を行わず http スキームで暗号化通信する仕組み) の使用を提案する
  • SNI などをサポートするクライアントとそうでないクライアントを分離する
  • 他ホストにリクエストを振り分けて負荷分散する

HTTP Alternative Services は HTTP/2 とは分離された Internet-Draft になっており、 2014年12月現在、 5番目のドラフトが出ている 状態です。

HTTP Alternative Services メッセージの表現方法

HTTP Alternative Services ではサーバからクライアントへ代替が存在する旨のメッセージを通知することで使用することができます。 このメッセージでは最初にリクエストを受け取った OriginRFC6454 にあるようにスキーム、ホスト、ポートの組で識別する)を代替する Alternative service を通知するような内容になります。

例えば Origin が下記の通りだったとして、

 ("http", "www.example.com", "80")

Origin が下記のようなメッセージを送ることで、「new.example.com:81 に HTTP/2 で話すことで Origin と同様のリソースを受け取ることができる」ことを通知できます。

("h2", "new.example.com", "81")

このメッセージの表現方法について、現行のHTTP Alternative Services のドラフトでは下記2つの方法が提示されています。

  • Alt-Svc HTTP ヘッダフィールド を使用する
  • HTTP/2 において ALTSVC フレーム という拡張フレームを使用する

Alt-Svc HTTP ヘッダフィールド

Origin は、下記のようなフォーマットの Alt-Svc ヘッダを送ることで Alternative service の存在をクライアントに通知することができます。 ここでプロトコル名として提示するのは、 ALPNプロトコル識別子と同様のものになります。

Alt-Svc: h2="new.example.org:80"

Alt-Svc ヘッダの内容はキャッシュされます。デフォルトでは 24 時間後にフレッシュされますが、 Alt-Svc ヘッダの ma(max-age) パラメータによってキャッシュが失効されるまでの時間を指定することもできます。

# 1時間後に失効
Alt-Svc: h2=":443"; ma=3600

なお、クライアントは Alt-Svc を使って Alternative service にリクエストを投げる際は Alt-Used HTTP ヘッダフィールド を付加する必要があります。(MUST) これは Alternative service 切り替えのループが発生することを防ぐことと、サーバ側で負荷分散する際に Alt-Svc が使われたリクエストなのかどうかを識別することが目的です。

Alt-Svc を使って振られた Alternative service はリクエストをうまく捌けない際に 421 Misdirected Request HTTP ステータスコード を返します。 クライアントは 421 を受け取った際には Alt-Svc キャッシュから該当エントリを消す必要があります。(MUST)

ALTSVC フレーム

HTTP/2 で Alternative Services を使用する場合は、 ALTSVC フレームで Alt-Svc ヘッダと同内容のメッセージを表現します。 ALTSVC フレームは Optional なフレームタイプであり、 最新の HTTP/2 のドラフト では定義されておらず、これをサポートしていないクライアントはサーバから送られてきた ALTSVCフレームを無視しても問題ありません。 (ちなみに draft-11 から draft-13 の間は ALTSVC フレームタイプが HTTP/2 のドラフト内で定義されていたりしました)

HTTP Alternative Services の活用例

http スキームで暗号通信を行う 日和見暗号 でも HTTP Alternative Services を使用します。 Origin は日和見暗号が利用可能であればレスポンスに HTTP-TLS ヘッダを付与します。 クライアントはこれを ":443" の Alternative service として記憶することで、次回以降にユーザが http スキームでリクエストを投げる際に HTTP over TLS で通信可能な Alternative service を選択することができます。

f:id:syu_cream:20141220153046p:plain

HTTP/2 通信開始前は基本的に ALPN や HTTP Upgrade でクライアントとサーバの間でお互いに HTTP/2 を解釈可能だということを確認します。 HTTP Alternative Services を使って事前に HTTP/2 で通信可能な alternative services がいることを知っていれば、このようなプロトコルネゴシエーションをスキップして直ぐに HTTP/2 通信を開始することもできます。

f:id:syu_cream:20141220153103p:plain

  • 負荷分散する

alternative service として別ホストを指定することもできるため、 Origin が高負荷な場合は HTTP Alternative Services を使って別ホストにリクエストを振ることで負荷分散することも可能です。

f:id:syu_cream:20141220153112p:plain

これは個人の意見ですが、 HTTP Alternative Services を使って負荷分散するのは難しいのではと思っています。 まず Origin は Alternative services の負荷状況を把握しておく必要があると考えられます。でないと誤って高負荷な Alternative services にリクエストを振り続けてしまう可能性があります。 更に HTTP Alternative Services は Optional な機能のため、これで負荷をどの程度分散できるかはどの程度ブラウザが対応してくれるかに大きく依存します。

HTTP Alternative Services 周辺事情のこれまで

HTTP Alternative Services 周辺のこれまでのおおまかな流れをまとめてみました。

  • Alternate-Protocol ヘッダフィールド

Alternative Services の前身となるのは、 SPDYの仕様に含まれる Alternate-Protocol ヘッダフィールド であると思われます。 Alternate-Protocol ヘッダは、リクエストが指定ポートで他のプロトコルでも捌けることを通知するためのヘッダです。

  • Encryption for HTTP URIs Using Alternate Services

こちらの文書日和見暗号を実現するのに、 Alt-Svc ヘッダを使う提案がされています。

  • HTTP Alternate Services

こちらの文書 で、 Alternative Services が日和見暗号から分離されています。

  • HTTP/2 ALTSVC フレーム

http2 draft-11 で、 HTTP/2 で Alternative Services を使用するためのフレームタイプが定義されました。 しかしながら http2 draft-13 でこれは除去され、 HTTP Alternative Services draft-02 に分離されました。

GitHub の issues で議論された内容を元に、 HTTP Alternative Services draft-05 まで更新されています。

おわりに

HTTP Alternative Services の理解があまりなかったため、今回仕様と経緯を調査しまとめてみました。補足や誤り指摘等大歓迎です。何かありましたらコメント欄にでも書いて頂ければ幸いです。

ちなみに今回 HTTP Alternative Services に対応している実装が存在するのか気になって少々調べてみたのですが、少なくともコードベースでは Chromium, FireFox, nghttp2 には対応する実装がありそうでした。 どこまで機能するのかは未調査です。後ほど余裕があった際にでも調べます。

余談ですが, 現在の仕様では "HTTP2.0" ではなく "HTTP/2" もしくは "HTTP2" が正しい名称です.

Maygh: Building a CDN from client web browsers (EuroSys'13) を読んだ

はじめに

本稿は システム系論文紹介 Advent Calendar 2014 14 日目の記事です。

Maygh: Building a CDN from client web browsers (EuroSys'13) という論文を読みました。ざっくりと内容紹介や所感を記述します。

概要

Maygh は Web ページで要求される静的リソースを、既にそのリソースを持っている他のクライアントから P2P 通信で受け取ることによりサーバ側の帯域使用量を低減するシステムです。 Maygh は JavaScript で記述されたクライアントスクリプトという形でユーザに提供され、 WebRTC などを使ってクライアント間通信を実現します。その他専用のブラウザのプラグインなどを導入する必要はありません。 ただしコンテンツ配信者は coordinator と呼ばれるキャッシュ保持情報と保持するクライアントの IP アドレスを教えるためのサーバを提供する必要があります。 各クライアントはリソースを取得する際にまず coordinator に問い合わせ、それのキャッシュを持つ他クライアントがいれば coordinator からもらった情報を元に WebRTC 接続を確立して要求されるリソースのやり取りを行うことになります。

Maygh の評価として、ショッピングサイト Estyアクセスログを用いたシミュレーション結果が提示されています。 このシミュレーション結果によると、 Esty のワークロードにおいて約 75 %ほど帯域使用量を削減することができるとのことです。

従来のコンテンツ配信

大規模な Web サービスを運営する上で、コンテンツ配信に伴うネットワーク負荷を捌く方法は悩ましい問題です。 今日ではネットワーク設備を強化する、配信サーバの台数を増やす、静的コンテンツの配信に Akamai や Limelight などの CDN(Contents Delivery Network) を利用するなどの方法が存在します。 しかしながらこれらの方策は大きなコストが発生しがちです。

近年の別のアプローチとして、サーバ側設備を増強するのではなく、クライアント側で静的コンテンツの配信を共有し合ってもらい、サーバ側帯域使用量を提言する手法が現れてきています。 具体的な実装例として Akamai NetSession Interface などが存在します。 しかしながらこれらの既存手法は専用アプリケーションやブラウザのプラグインの導入を強いるものになっており、エンドユーザにとって導入障壁が高いものとなっています。

Maygh のデザイン

Maygh は幾つかのモダンなブラウザの提供する機能の支援を受けて、エンドユーザに専用プラグインなどの導入を強いることなくユーザ参加型のコンテンツ配信を行うシステムです。 Maygh を利用するにあたって、ユーザのブラウザには都合下記のような要件が発生します。

  • JavaScript が有効になっている

  • Indexed Database API, WebStorage をサポートしている必要がある

    • Maygh はこれら Storage API を用いて各クライアントの LocalStorage にキャッシュを保持する
  • WebRTC をサポートしている

    • Maygh クライアント間の P2P 通信に用いられる
    • WebRTC が使えない場合、 RTMFP を使用することも可能

Maygh は、各クライアントに配布される Maygh クライアントスクリプト と、コンテンツ配信者により提供される coordinator サーバ から構成されます。 Maygh クライアントは小サイズの JavaScript で実装されたスクリプトです。 RTMFP を用いるための小さな Flash オブジェクトも伴います。 coordinator は Maygh クライアントと各クライアントが持つコンテンツの対応関係を管理する client map と、 各コンテンツを持つオンライン状態のクライアントの情報を管理する content location map の二つのデータを持つサーバです。 Maygh の coordinator は性能がスケールできるよう複数台で動作できるよう設計されています。複数の coordinator を動作させる際は、それぞれの coordinator が content location map を持ち、自分にぶら下がっているクライアントの情報を管理するようになります。

Maygh による通信

Maygh によるクライアント間、そしてクライアントと coordinator 間の通信は下図の通りになっています。

f:id:syu_cream:20141214234254p:plain

図には含まれていませんが、クライアントは Web ページ初回アクセス時に coordinator にコネクションを張り、 Maygh の update メッセージで自身の持つコンテンツ情報を送ります。 各コンテンツの取得時に最初に lookup メッセージを送信し、それに対するレスポンス lookup-response をもって要求する他のクライアント(以降、ピア)の ID を取得します。 その後 coordinator に connect メッセージを送信し、コンテンツを所有するピアとの RTMFP/WebRTC セッションを確立します。 この際、多くの場合ピアの間には NAT デバイスが挟まっていることが想定されるので coordinator に STUN をしゃべってもらい、相手方ピアの IP アドレスとポート番号を教えてもらいます。 その後は RTMFP/WebRTC セッションを確立し、コンテンツの取得を行い、最後にコンテンツを取得完了した旨を update メッセージで coordinator に伝えます。

評価

実装

この論文では Maygh の評価を行う上で下記の実装を行ったとのことです。

また、 Maygh の実装は GitHub に公開されている ようです。

coordinator がスケールするかの検証

複数の coordinator プロセスを1台の検証用マシンで動作させた際と、複数のマシンで動作させた際の transaction/sec が検証されています。 検証の結果、複数マシンで動作させることにより coordinator 数に比例して捌けるトランザクション数が上昇しており、十分スケールするとのことです。

Maygh による帯域使用量削減効果の検証

Esty の 7 日間のアクセスログを用いた、 Maygh の効果のシミュレーション結果が提示されています。 この結果によると、 Maygh 導入により約 75% の帯域使用量削減効果が見られたようです。 また既存の専用プラグインを導入してクライアントサイドでコンテンツ交換を行う手法との比較として、「10% のユーザがそのプラグインを導入する」という想定での帯域使用量の削減効果も検証されていますが、こちらは約 7.8% と Maygh と比較して低い効果しか見られないとのことです。

余談: 最近の関連トレンド

この論文を読んでいて思い出したのですが、昨年に米 Yahoo! が PeerCDN という配信システムを持つ会社を買収した話 があったかと思います。 記事によると WebRTC で P2P 通信することでコンテンツ配信をするらしい話が記載されていることもあり、本論文に近い手法であるものかと推測されます。 PeerCDN のその後の話も気になりますね。 また最近ですと、あまり詳細な情報は出ていないようですが、 BitTorrent 社が BitTorrent を用いてコンテンツ共有を行う Web ブラウザ Maelstrom のアルファテストを開始したとのニュース があったかと思います。

P2P でクライアント間でコンテンツ配信負荷を負担し合ってサーバ側帯域使用量を減らす手法の今後の動向が気になるところです。

ISUCON4 オンライン予選に参加した所感など

ISUCON4 のオンライン予選に参加したので簡単に所感をまとめてみます。

チームは @AknEp くん, @suma90h くんと一緒に組みました。 チーム全体でやったことは @AknEpくんのブログ でまとめられているので、本記事では僕のやったことと反省点・感想などにフォーカスします。

自分がやったこと:

反省点:

  • BitBucket の使用に躓く
    • 最初の頃 git push できなくてちょっと時間食った
    • 過去に気付かないうちにBitBucketのアカウント二つ作っていて、別アカウントでpushしようとしていたらしい()
  • ちゃんとボトルネック解析しましょう
    • top などで見る程度はやっていた
    • プロファイリング能力が足りない?
  • 事前準備をもっとすべきだった
  • 最後の方にスコア稼げたのは @AknEp くんの活躍の依るものが多かったので、もう少し頑張って貢献すべきであった

色々と勉強になることが多く、刺激的でした。 同チームの @AknEp くん、 @suma90h くん、参加者の皆さんお疲れさまでした。 俺たちのISUCON4はこれからだ! -完-