YAPC::Asia Tokyo 2010スペシャルレポート

1日目レポート[随時更新]

この記事を読むのに必要な時間:およそ 9.5 分

malaさん「Studying HTTP with Perl」

本セッションは,malaさんによるHTTPプロトコルの処理全般に関するトークでした。まず,PerlのHTTPクライアントライブラリについて,同期と非同期のものをそれぞれ紹介されていました。PerlのHTTP接続といえばLWPがデファクトスタンダードではありますが,さらに高速な実装としてWWW::Curlをあげていました。

非同期なものに関してはAnyEvent::HTTPが有名ですが,malaさんが作られているもっと高速なAnyEvent::Curlが紹介されました。今までの通説ですと,LLのボトルネックはI/Oであり,コードの実行速度はさほど問題にはならないというのが通常の考え方でした。しかし,通信速度が0と仮定したときの速度(性能限界)を考えた時,LWPではCPU 1つあたり秒間200回しか実行できないことがわかり,これでは少し問題がありそうです。そこでWWW::Curlを利用することで,性能限界を秒間2500回まで向上させることができるそうです。もちろん,すべての場合にWWW::Curlを使うべきではなく,非同期アクセスが必要で,性能限界が間にあわないときに使用すべきだということです。

その後,今度はサーバの実装としてpreforkとイベント駆動との二つの方法の比較がありました。preforkのサーバは簡単に書くことができるのが利点ですが,DoS攻撃に弱いという問題点を指摘されていました。1リクエスト辺りの実行時間がはっきりとせず,必要なリクエスト数も不明な場合に,起動されるプロセスが想定よりも多くなって枯渇してしまう可能性があるためです。

話の最後には,テストコードにGoogleなどの外部URLを参照する場合の問題点を取り上げ,Test::TCPなどのモジュールを使ってローカルサーバを立ち上げ,簡単なPSGIアプリケーションを作ることでWEBクライアントのテストはローカル環境だけで可能であることを解説していました。

画像

画像

Jiro Nishiguchiさん「Write Good Parser in Perl」

Jiro NishiguchiさんによるPerlでのパーサモジュールの紹介と、その実装方法についての解説でした。

まずはパーサとはなにかというところから始まりました。パーサとはなんらかの意味をもったテキストを、その後の処理に適した形にするためのものです。 そんなパーサのPerlでの実装例として、HTML::Parser、XML::LibXML、JSON, JSON::XS、HTTP::Parser::XS、Template-Toolkitといった定番モジュールの紹介がありました。またCache::Memcachedモジュールも紹介されていて、こちらはパーサモジュールではないが、内部でmemcachedプロトコルを解析するためにパース処理を行っており、その点でパーサ実装例として挙げられていました。

これらのモジュールの実装はXSを使ったものが多いようです。特に1文字ずつ処理していくようなタイプの処理はPerlで書くよりもCで書いたほうが高速に動作することが多いのがその理由のようです。とはいえPerlの正規表現でもかなり高速に動作するので、書き捨てのパーサなどを作る場合には正規表現は有効な手段として紹介されていました。また正規表現を最適化してくれるRegexp::Assembleについての紹介もありました。

続いて実装パートではRagelの紹介がありました。Ragelとは正規表現に似た文法を用いて比較的わかりやすく宣言的に書けるのが特徴のパーサジェネレータです。ただし、perlはサポートしていないため、利用するにはCで書いてXSで呼び出すなどひと工夫する必要があるそうです。XSといってもデータ構造を作って返すだけで複雑な処理は必要ないので恐れることはないとのことでした。実際にログ解析プログラムを書いたところ、正規表現と比べて5倍程度高速な物ができたそうです。ログ解析のようにフォーマットがあまり変わらなそうなところについては、パーサジェネレータとXSで高速化するのもお勧めとのことでした。

画像

画像

Seiji Haradaさん「mixi チェックインの裏側」

mixiチェックインの裏側に関するトークです。スポット絞り込み検索機能を実現するための方法と、高速化するために行っている工夫について発表されました。

mixiチェックインでは現在の位置情報からスポットを検索する際に、geohashという手法を用いているそうです。geohashとは経度緯度の範囲を文字列で表現したもので、先頭からたどっていくと範囲が絞り込めるように表現されています。その性質により一定長さの文字列で前方一致検索をすることにより、高速に現在位置周辺の検索が実現できるそうです。実際のサービスではGeo::Hash::XSを使用されていて、とても高速に動作するそうです。ベンチマークをとったところ、Geo::Hashと比較して140〜200倍程度高速だったとのことです。

また高速化の手法としてmysqlまわりにも触れられていました。スポットの情報はそれほど頻繁には更新されないので、6文字のgeohashをキーにしてmemcachedにキャッシュしているそうです。ただし全ての地域についてキャッシュしてしまうとキャッシュ容量的に無駄が多くなってしまうため、特にスポットの多い関東、関西地区に限定している人のことでした。また検索範囲に関しては半径250mを規準にしているそうですが、これは厳密に指針があるわけではなく、実際に外にでて実機で検証したところGPSの最大誤差が250m程度だったので、それを規準にしたそうです。デバイス周りの開発ではコードの検証だけではなく、現実の世界での検証が重要だということを認識させられる一例だと思いました。

最後に位置情報サービスは難しくないので楽しみましょうと締めくくられていました。

画像

画像

伊藤直也さん「Perl/PHPと大規模Web開発」

最近PerlからPHPへシフトをしたことでPerlプログラマからもPHPプログラマからも注目されている伊藤直也さんのセッションは,大規模Web開発をテーマにした内容でした。

まずLLのWeb Application Frameworkについて最近の流行として,どの言語でも「作り込まれたWAF」⁠シンプルなWAF」⁠実行環境」の3要素が存在していることを取り上げました。Rubyにおいてこの三者はそれぞれ,Rails,Sinatra,Rackとなります。Perlですと,Catalyst,Mojolicious::Lite,Plack/PSGIが該当します。PHPにおいては,最初の二者はCakePHPとLimonadeを挙げることができますが,実行環境に関してはまだデファクトスタンダードはないそうです。これは,ニーズが少ないためではないかと伊藤さんは分析していました。

また,大規模Web開発について「収益に数年かかかる」とし,数人で作った昔のアーキテクチャを十数人規模で使い続けるということが必ず発生すると指摘をしました。ただ,Webシステムの開発についていえば,プロトコルは十分に枯れているHTTPであり,LLは後方互換を重視していることが多いため,一般的にいう「レガシー」とはちょっと事情が違うとしました。アーキテクチャの刷新方法としては,新案件に新しいアーキテクチャを導入したり,継続的な改善で新しいアーキテクチャを目指したり,システムをWEB APIで分断してから新アーキテクチャ化を進める方法等を紹介していました。

最後に,PHPへの移行について,⁠言語よりも基幹技術が重要であり,移行はそんなに難しくない」と移行の簡単さをアピールしつつも,⁠ツールにはPerlを使っている」とPerlも日常的に利用していることにも言及していました。

画像

画像

keroyonnさん「非同期タスクの通知処理 with Tatsumaki」

Hokkaido.pmのkeroyonnさんによる非同期タスクを通知する手法に関しての発表となりました。

まずは簡単な通知の方法として、CGIベースによるブロッキング&ストリーミングの解説がありました。perlだと$|=1を設定して少しづつprint文などでコンテンツを出力していく手法です。この方法は手軽なのですがブラウザがずっと読み込み中になってしまいます。

続いてクライアント側を非同期化するためにmultipart/mixedを使った通知方法の紹介がありました。ブラウザ側ではXMLHttpRequestで接続を維持したまま、CGI側ではboundaryをつけつつコンテンツを出力します。クライアント側の実装ではDUI.jsで処理すると簡単なようです。ここまでで単一の処理を非同期化する上では十分ですが、サーバ側がブロッキングする実装のままではC10K問題の影響を大きく受けてしまいます。それを回避する方法としてPSGI/Plackストリーミングの紹介がありました。サーバ側をノンブロッキングにすることで1プロセスで多数の処理をこなせるようになり、C10K問題を回避できます。

しかしノンブロッキングなサーバには、同期IOを使えないため処理が複雑になる、CPUを占有するような処理も好ましくないといった欠点があります。それらを解決する手段としてTatsumaki, Gearman, WebService::Asyncの3モジュールが紹介されました。まずTatsumakiを使うと、ノンブロッキングなストリーミング処理を簡潔に記述することができます。続いてGearmanはノンブロッキングなサーバが苦手とするCPU負荷が高い処理を補うジョブキューサーバで、ストリーミングしているプロセスから処理を移譲するために使います。ジョブを登録するときにブロックしては意味が無いので、クライアントから呼び出すときはAnyEvent::Gearman::Clientを使うとよいそうです。最後にkeroyonnさんが作成されているWebService::Asyncが紹介されました。TatsumakiにはHTTPClientというモジュールも付いていますが、結果のパースなどは自分で実装しないといけません。WebService::Asyncを使うと非同期でWebサービスを呼び出して結果のパースまでをシンプルに行えるとのことです。

セッション中は「笑いあり、涙あり、萌えあり、ポロりありの20分間」という副題の通り、ジョークで会場の笑いを誘いつつのなごやかな雰囲気でした。

画像

画像

吉見 圭司(walf443)さん「Webサービスのページング処理について」

吉見 圭司(walf443)さんによるページング処理のトークです。Webサービスでよく行われるページング処理について、いろいろな手法の紹介トークとなりました。

まずは一般的な方法の説明で、mysqldでのlimit offsetを使って1ページ分の結果を取得する処理と、limit句をつけないcount(*)文を発行してトータルの件数を取得する処理の二つを行ってページングを実現する手法を紹介されました。この手法は大抵の場合うまくいきますが、count処理が重いなど非効率な面もあります。

続いてmysqlの機能であるCALC_FOUND_ROWSを使う方法が紹介されました。これを使うと結果取得SQLの直後にselect FoundRows()を実行することでトータル件数を取得することができます。count処理を別に行うより効率的ですが、DBに依存してしまう欠点があります。次のページがあるかどうかだけが分かればいいというケースでは、1件余分に取得して次ページがあるかどうかを判定するという方法も紹介されました。

吉見さんはこれらのページングロジックを必要に応じて切り替えられるようにDBIx::Skinny::Pagerというモジュールを開発されているそうです。

質疑応答では、ページング処理中にデータが増えた場合表示位置がずれる可能性があるがどう対処するかという質問がありました。それに対してページング処理をタイムスタンプなどを規準に行えばよいのではないかと回答されていました。

画像

画像

著者プロフィール

本間雅洋(ほんままさひろ)

北海道苫小牧市出身のプログラマー。好きな言語はPerlやPython,Java,Objective-C,Haskellなど。在学中には数学を専攻しており,余暇の楽しみは圏論や論理学を学ぶこと。現在はオンライン不動産株式会社にて自社システムの開発に従事している。

共訳書に「実用Git」(オライリー・ジャパン)、共著書に「FFmpegで作る動画共有サイト」(毎日コミュニケーションズ)がある。

blog:http://d.hatena.ne.jp/hiratara/


臼井洋文(うすいひろふみ)

WEBアプリケーションエンジニア。京都府京都市出身。仕事ではPerlでサーバサイドプログラムを書きつつ,Objective-CでiPhoneアプリケーションの開発を行っている。最近の興味は統計,機械学習など。

twitter:usuihiro
blog:http://d.hatena.ne.jp/usuihiro1978/