へぼい日記
YAPC::Asia Tokyo 2011に参加してきました
- 2011/10/16 日曜日 19:36:39
- perl
YAPC::Asia Tokyo 2011に参加してきました。
ブログ書くまでがYAPCというわけで印象にのこったセッションを中心に参加報告を。
前夜祭
myfinderさんの「サービス運用者のための継続的監視」はさすが日本で1番目か2番目か3番目のSNSの運用をされてるだけあってさすがという感じでした。自分は小規模システムばかりやっていて開発者も運用についてかなりコミットしなきゃいけない状況で働いているのですが、ここまできちんとできてないなーと痛感。さっそく監視項目をどんどん増やしていこうと思いました。
会場外のプチ懇親会的なものでは、ほぼボッチでしたが夏菜子推しTを装備していたsugyanさんと初めて挨拶させていただくなど。
一日目
寝坊&体調不良で昼から参加。Jesse Vincentさんの「Perl 5.16 and beyond」とmalaさんの「Webアプリケーション高速化」が聞けなかったのが残念。動画とか公開されるのかな。
onishiさんの「新はてなダイアリーの裏側」では、はてなダイアリーが今秋Hatena Blogになることが発表されたりしていて、ユーザ毎サブドメイン運用でjavascript解禁なんて話があってセキュリティ対策とかどーなのかなーと興味深かったです。二日目のcho45さんの「ぼくがかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく 」でそこらへんの話も詳しくされたぽいのですが裏セッションを聞いてて見れなかったです。
徳丸さんの「Webアプリでパスワード保護はどこまでやればいいか」ではレインボーテーブルの原理を丁寧に説明されていて(徳丸本にも書いてあるのですが読み飛ばしてしまっていたので)、なるほどなーと思ったり、高速化するGPUの脅威に対抗するためにサービス側でもGPUを使ってハッシュ生成(ストレッチング回数を増やす)するという対策を示しておられたのが印象的でした。
makamakaさんの「Perl Mongerなりきりカードゲームの考案と実践」はとにかく面白すぎましたw会場のウケをとった回数だけならきっとベストスピーカー賞なんじゃないでしょうか。
懇親会ではほぼボッチでしたが、miyagawaさんに僕のビール持って行っちゃってませんかという(濡れ衣の)難癖をつけるなどしました。(わざとじゃありません。すみません)
二日目
若干遅刻気味だったので大岡山駅からダッシュで会場に向かい、ぎりぎりkazuhoさんの「続 Unix Programming with Perl」の開始に間に合いました。昨年の発表もそうでしたが正しくプログラミングするとはどういうことなのかということを徹底的に意識されている感じで非常に勉強になりました。
Ricardo Signes(rjbs)さんの「闇のEメール伝説」はEmail::モジュールの話をするのかなーと思って行ってみたら、SMTPやMIMEのRFCにまつわるメールのカオス状況をおもしろおかしく発表されるという感じでした。英語は正直ほぼ聞き取れてなかったのですがスライドを見るとだいたいは把握できたし、メールアドレスの正規表現をやってたときにRFCがupdateされて古いRFCがobsoleteになっても新しいRFC自体にobsなsyntaxが残ってたりしてカオスってるのを把握してたのでそうそうそうだよねーという感じで楽しく聞けました。
スイーツエリアで開催されたmotemenさんの「Teto でニコニコ音声ストリーミング 」は便利そうだし、技術的にも面白そうなので是非使ってみてコードも読みたいなーと思いました。
勝手に後夜祭では、ほぼボッチは回避しつついろんな方と話すことができました。途中YappoさんとEmail::Senderの非Moose化てどうなんでしょうねーという話をしていたらcharsbarさんに折角本人がいるんだから直接いいなよとrjbsさんの前に連れていかれcharsbarさんに通訳をしてもらいながらお話を聞くことができました。RoleがMooseとMouseで完全に共通化されてないからAny::Mooseは使えないよねーという話だと理解したのですが正直完全には理解できず。英語ェ…。周りに集まってきたPerlHackerの面々が直接英語で議論しているのを目の当たりにしてほんと英語どうにかしないと駄目だなと再度感じた次第。charsbarさんその節はありがとうございました。力不足で大して議論を深める役には立てませんでしたが貴重な経験になりました。
というわけで三日間非常に楽しめました。
牧さん櫛井さんをはじめJPAのみなさん、ボランティアスタッフのみなさん、スピーカーのみなさん、お疲れ様でした&ありがとうございました。
来年はスピーカーとして若干でも貢献したいとおもいます!
ISUCONに参加してきました
- 2011/8/30 火曜日 3:18:58
- perl
なんでもありのWebアプリケーション高速化バトル、#isuconに山形組として参加してきました。
結果はみなさんご存知の通り、藤原組さんの圧勝という感じになりました。
自分はというと、DBボトルネックの解消までは藤原組さんとほぼ同じ手法で解決して、4700req/minあたりのbest scoreを出した後には有効なチューニングが行えずにnginx導入の罠にひっかかって200req/minとかになってしまって泣きながらapacheに戻したりしつつ、最後はサイドバーのcacheをmmapにいれる作業をしていたらバグでfailするようになってしまってぎりぎりでDBのボトルネック解消直後にロールバックして、10000req/3minくらいがたしか最終スコアだったと思います。failしたチームを除けば下から数えたほうが早い感じになってかなり悔しい結果でした。
DBボトルネック解消直後にappサーバを一つにしぼったところたいして結果は変わらず、ああたかが10並列だしサーバ分散するほうが無駄なのかなとリバースプロキシでplackで直接80番ポートをlistenするとどうなるかなーと思ったりもしていたのですが、debianでdaemontools慣れしていた自分はceontosでsupervisordという構成にひるんでしまってそこまで踏み込めなかったので、帰ってきてからPSGI単体のアプリでどこまでチューニングできるかってのをやってみました。
で、できたのがhttps://gist.github.com/1178857これです。Feersumで動かしてあげると、自分の環境で96550req/minのベストスコアがでました。一応永続化もしているので(デーモン化の設定さえすれば)再起動後も有効な、ISUCONレギュレーション完全対応なPSGIアプリになっています。ISUCONアプリの全体像を簡単に見通したい方にもオヌヌメです。といってもこのやりかたはたかが10並列でたかが3分間のアクセス(とpost数)とわかっているからできる構成なので実際の運用にそのまま生かせるような内容にはなっていませんので、そこのところご注意くださいです。
こんなわくわくするイベントを開催してくださったlivedoorの担当者の皆様ありがとうございました!
追記: その後nginxとも組み合わせてやってみたところ(psgiもこんなかんじに修正して)

までいきました。nginxでは静的ファイルをserveして、keepalive,gzipオフ。
追記: nginx embeded perlで242686req/minでました。https://gist.github.com/1181564
nginx +proxy cacheでexpireしないようにして試すと、(当然FAILするけど)fetchesが30万前後だったのでまぁここらが自分的には限界
DBD::mysql 4.020がリリースされました
DBD::mysqlの4.020が昨日リリースされました。
このリリースにはmysql_server_prepare=1を使っている場合のバグの修正が5件ほど含まれています。(ChangeLog)
DBD::mysql で mysql_server_prepare=1 のとき TEXT 型の欄が自動 utf8::decode されなくなる
こちらのブログで指摘されていた件を直してパッチを送ろうと思っておもむろにmysql_server_prepare=1の状態でDBD::mysqlのテストを実行したら失敗しまくったため、もう駄目かもしれないと思ったのですが、何故かmysql_server_prepareと心中する腹をくくり一応すべてのテストを通すようにパッチを送りまくってみたところ取り込まれたという感じになりました。(リリース後に2つほどさらにpull reqしていますが…。)
TEXT型がdecodeされない件はユーザ側で回避できない話ではないんだと思いますが、LONGBLOBで4GBのメモリをアロケートしようとする件はDB構成によっては回避のしようもなく、mysql_server_prepare=1はほとんど使われてないんだなぁという印象を持ちました。
一応改めて整理しておくと、mysqlのサーバーサイドのPrepared Statementは以前はクエリキャッシュがされないというかなり致命的なデメリットがありましたがバージョン5.1.17以降でC API等から利用されるバイナリプロトコルではキャッシュされるようになり、また5.1.22以降からはテキストプロトコル上でのPREPARE, EXECUTEでもキャッシュされるようになっています。(詳細はクエリキャッシュの動作を参照してください。)
mysqlのPrepared Statementはbind値を展開した後のクエリの結果をキャッシュしてくれるいわゆるQueryCacheのみの対応となっています。パラメータ値に依存しない実行計画をキャッシュしてくれるわけでは無いのでメリットは薄いと思われる部分はあるとは思うのですが、通信データが大きい場合には速いというメリットも持っています。(今回のDBD::mysqlのバグはそのメリットを享受するべきLONGBLOBがほぼ動かないというひどいものではありましたが)
memory leakのような現象が起きるという中の人の指摘もあったりしますが、これはステートメントハンドルやコネクションの管理をクライアント側できちんと行えば問題ないと思っていたりもします。(大規模環境でどうなのかというわれるとちょっとどうなのかなと思わなくもないですが)
というわけで、やはりまあ積極的に利用を勧める理由も無いのですが、積極的に回避する理由も無いとも思ってますので是非使えるかたは使ってみてください。で、DBD::mysql的にもMySQL本体的にも枯れてくれるとうれしいなと思ってます。
Gearmanのはまりどころ
- 2011/1/22 土曜日 21:19:36
- perl
最近Gearmanに入門しているのですが、いろいろとはまったのでメモ。
$worker->workは”Do one job”ではなくDo job loop
$worker->work while 1;
みたいなサンプルが書いてあったり
Gearman::Job->work(%opts) Do one job and returns (no value returned). You can pass "on_start" "on_complete" and "on_fail" callbacks in %opts.
って書いてあるのですが(しかもこれは、Gearman::JobではなくてGearman::Workerだし、、、)
workはオプション無しで呼ばれた場合はwhile 1なんかなくてもloopします。
work_once的な動きにしたいのであれば
$worker->work(stop_if => sub { 1 });
とすればいいです。stop_ifをmax_requests_per_child的な動きにしたい場合はkazeburoさんのgearman-starter.plを参考にするといいです。
ちなみにこれは作者にメールでパッチも送ったりもしたのですがこのRTが同じ内容。1年半ぐらい放置みたいなので直る気配なし。
Gearman::Client->job_serversはArrayRefを受け取れるけど、Gearman::Worker->job_serversは受け取れない
結構はまりました。
my $clinet = Gearman::Clinet->new; $client->job_servers(['127.0.0.1']);
はokだけど
my $worker = Gearman::Worker->new; $worker->job_servers(['127.0.0.1']);
は駄目。正しくは
my $worker = Gearman::Worker->new;
$worker->job_servers('127.0.0.1');
としなければならない。これもRTにあがってますね。
Gearman::Workerはfork safeじゃないんでfork後生成
まぁDBIのdbhとかと一緒ですね。いくつかのネット上の例でParallel::Preforkなんかと組み合わせて使う時に
親プロセスで$worker作って共有している例注1があったのですが、ちゃんとやるなら子供で生成すること。
一見普通に動いちゃうのですが通信がまざって変になるかもしれないです。
まとめ
あたらしくCPANモジュールを使い出す時にはPODと共にRTも一緒に見ておくとよい。
注1
ここの11pとかここ(もう直ってる)とか。ちなみにkazuhoさんの書いたものだと去年のadvent calendarのWriting a prefork server / daemon using Parallel::Preforkは子供でworker生成してます。この記事は、graceful shutdownやSIGHUPによるconfig reloadへの示唆が含まれているので必見ですです
X-Content-Type-Options: nosniffのつけ方
- 2011/1/6 木曜日 12:49:29
- security
Apache
mod_headersでできます
Header set X-Content-Type-Options nosniff
Nginx
add_header X-Content-Type-Options nosniff;
但し、上記だとproxyなんかで既にX-Content-Type-Options: nosniff;が付いていると
X-Content-Type-Options: nosniff, nosniff
のようなヘッダになってしまう。問題ないかもしれないが気になる場合はNginxHttpHeadersMoreModuleを使って
more_set_headers 'X-Content-Type-Options: nosniff';
とすると良いのかも。
Plack
Plack::Middleware::Headerを使うと簡単です。
enable 'Header', set => ['X-Content-Type-Options' => 'nosniff'];
日本の休日をPerlから求める
- 2010/11/15 月曜日 18:11:18
- perl
日本の休日には「国民の祝日」と「振替休日」と「国民の休日」ってのがあるのですがそれをPerlから求めるにはどうしたらいいんだという話。
#perl-casualでたずねたところいろいろと方法を教えてもらいました。
定番ネタだし、それ三週目といわれたりしたのでまとめてみますたという流れ。
そもそも休日というのは法律で決められるものなので、改正もあり最近だと2005年に改正があったりしています。
また、「国民の祝日」の中には「春分の日」や「秋分の日」のように翌年分を2月に官報で発表なんてものもあったりします。
やっかいですね。
CPANモジュールを使う
Calendar::Japanese::Holiday
最終更新日が2007年なようですが
use Calendar::Japanese::Holiday; say isHoliday(2011, 3, 21); say isHoliday(2011, 9, 23);
こんな感じで未来の秋分・春分の日も計算で求められているのでそれなりに信頼感はあるかと思います。
ただし、「振替休日」に関しては下記のように第三引数に1をいれないと求めてくれないので注意。
use Calendar::Japanese::Holiday; say isHoliday(2009, 5, 6); # これだと駄目 say isHoliday(2009, 5, 6, 1); # これならOK
DateTime::Holiday::Japanese
CPANモジュールではないですが、coderepos上にfbisさん作のモジュールもあがっています。
use DateTime::Holiday::Japanese qw/is_holiday/; say is_holiday(year => 2011, month => 3, day => 21); say is_holiday(year => 2011, month => 9, day => 23);
Calendar::Japanese::Holidayと同様に更新は2007年からされていないようですが秋分春分の日は計算で出しています。
今日2009-2011のテストデータを追加してパスするのは確認しています。coderepos上にあるので法律変わったら誰かが更新してくれるんじゃないかという期待感あり。DateTime依存。
ネット経由で情報を定期的にとってくる
Google Calendar Data API
japanese@holiday.calendar.google.com
=> 「振替休日」「国民の休日」には非対応(「国民の祝日」カレンダーだからそれが正しいんだよ派)
outid3el0qkcrsuf89fltf7a4qbacgt9@import.calendar.google.com
=> 「振替休日」「国民の休日」にも対応。使えそう
https://www.mozilla.org/projects/calendar/holidays.htmlのJapan Holidaysと同じデータぽいのかな。
政府
「国民の祝日」についてが一番信頼できそうなネット上の情報な気もするが、別にこのページを維持すること自体を法律で定めているわけでもないし今年と来年のデータしかないのでそこまで使えるってわけでもない。「振替休日」と「国民の休日」については例だけなので将来的にどう表示されるのかも判然としない。
目視確認なら法律と官報を確認するに次いで信頼性はあるかと。
休日DBを独自に作成して運用者がメンテ
最強
まとめ
CPANモジュールの”その時点での法律計算”系は手軽さはあるが、今後の法改正を見越すと若干難ありか。
モジュール自体が毎年来年分のテストを追加してリリースされることが保障されていて、
使う側も毎年保守ができるのであれば特に問題はなさそう。
さらにモジュール自体もgithubなんかで複数人で保守されているといいなという話。
API系は信頼できるものを政府が出してくれるとうれしいなーというところ。
XslateはSyntaxを変えても基本的には実運用上の速度は変わらない
- 2010/8/13 金曜日 19:54:00
- perl
TTの158倍速いというxslateですが、このベンチマークはSyntax::Kolonを使っています。
TT互換なSyntaxであるところの、Syntax::TTerseを使うとどうなるのかなということでhttp://github.com/nihen/p5-Text-Xslate/tree/add_tterse_benchのbenchmark/x-rich-enc.plとbenchmark/x-poor-env.plにTTerseも追加してみました。
以下結果
%perl benchmark/x-rich-env.pl
Perl/5.12.1 i686-linux
Text::Xslate/0.1056
Text::MicroTemplate/0.15
Text::MicroTemplate::Extended/0.11
Template/2.22
Text::ClearSilver/0.10.5.4
HTML::Template::Pro/0.9502
1..5
ok 1 - TTerse: Text::Xslate::Syntax::TTerse
ok 2 - TT: Template-Toolkit
ok 3 - MT: Text::MicroTemplate
ok 4 - TCS: Text::ClearSilver
ok 5 - HTP: HTML::Template::Pro
Benchmarks with 'include' (datasize=100)
Rate TT MT TCS HTP Xslate TTerse
TT 78.6/s -- -69% -94% -95% -99% -99%
MT 257/s 227% -- -82% -84% -98% -98%
TCS 1412/s 1697% 450% -- -11% -89% -89%
HTP 1586/s 1918% 517% 12% -- -88% -88%
Xslate 13241/s 16752% 5054% 838% 735% -- -1%
TTerse 13397/s 16951% 5115% 849% 745% 1% --
%perl benchmark/x-poor-env.pl
Perl/5.12.1 i686-linux
Text::Xslate/0.1056
Template/2.22
HTML::Template/2.9
Text::MicroTemplate/0.15
Text::MicroTemplate::Extended/0.11
1..4
ok 1 - TTerse: Text::Xslate::Syntax::TTerse
ok 2 - TT: Template-Toolkit
ok 3 - MT: Text::MicroTemplate
ok 4 - HT: HTML::Template
Benchmarks with 'include' (datasize=100)
Rate TT TTerse Xslate HT MT
TT 49.5/s -- -27% -28% -61% -80%
TTerse 67.9/s 37% -- -1% -47% -73%
Xslate 68.5/s 38% 1% -- -46% -73%
HT 127/s 157% 88% 86% -- -50%
MT 253/s 411% 273% 269% 99% --
このように誤差の範囲ぐらいの差しか無く同様に速い。
これはなぜかというと、Xslateは様々なSyntaxで書かれたテンプレートを共通の中間コードにコンパイルし、それをキャッシュしているためその中間コードはほぼ同一のものになるからです。
一応そのコンパイル部分には差が現れるが、ファイルキャッシュもできない環境というのはほぼありえないので実運用上、速度の差は無いと言ってよいとおもわれる。というわけでTT使ってる人は安心してTTerseに移行してみるといいと思うです。(互換性がどの程度あるのかは使ってないから知らないけど!)
ちなみにコンパイル部分のみのベンチマーク
% perl author/bench_compile.pl
Parser: Kolon v.s. TTerse
Rate tterse kolon
tterse 80.1/s -- -42%
kolon 139/s 74% --
Path::AttrRouterにHTTPメソッド制限できる機能を追加してみた
- 2010/7/10 土曜日 23:53:26
- perl
Path::AttrRouterというtypesterさんが開発されているdispatcherがあって、Catalyst-likeなControllerのattributeを拾ってきてルーティングテーブルを作成してくれるのが便利で使っています。
で、HTTPメソッドを考慮したルーティングを行ってくれる機能が欲しかったので追加してみました。
method_supportブランチとしてforkしてgithubにあげてあります。
使い方はこんな感じです。
use Path::AttrRouter;
{
package MyController;
use base 'Path::AttrRouter::Controller';
sub index :Path { print "index\n" }
sub post :Path Method('POST') { print "post\n" }
}
my $router = Path::AttrRouter->new( search_path => 'MyController' );
my $m;
$m = $router->match('/', 'GET');
$m->dispatch; # index
$m = $router->match('/', 'POST');
$m->dispatch; # post
Methodが指定されなかったsubroutineはGET, HEADがデフォルトになるようになってます。
一応後方互換性は考慮してあり、$router->matchの第二引数が空の場合は
どのメソッドでもマッチするようになっています。
本家にとりこまれればうれしいけれど取り込まれなければ別distとして継承使って作り直すかもです。
ところで、諸事情により前職を退職していまして、ブログURLを移転しています。
RSSリーダーに登録されていた方等は再度登録お願い致しますです。
一応302飛ばすようにしてはあるんですが、RSSリーダーって自動的にそこらへん追跡してくれないんすかね。
追記(2010-07-11 17:17)
http://twitter.com/#!/typester/status/18255875606
とのことです。確かにPath::名前スペースなのでHTTPメソッドに依存するのは筋悪でした。
HTTP::AttrRouterとかで作ってみようかなーと考え中。
PlackにおけるCSRFとDNS-Rebinding対策
- 2009/12/20 日曜日 11:32:53
- perl
最近のwebセキュリティ界隈ではCSRFやDNS-Rebindingが話題ですが、Plackでアプリケーションサーバを立ち上げる際にこれらの対策をどのように行うかについてまとめてみました。
まず、CSRF対策ですが、拙作のPlack::Middleware::RefererCheckを使うことにより、RefererのチェックによるCSRF対策が行えます。CSRF対策としては、onetime token方式も存在しますが、個人的にはRefererチェックが導入が楽で好きではあります。Refererを送信しないクライアントを対象にしたサービスを運営される方は別途onetime token方式の対策をおこなってください。
Plack::Middleware::RefererCheckの使い方はこのようになります。(SYNOPSYSからの抜粋)
use Plack::Builder;
builder {
enable 'RefererCheck', host => 'www.example.com', same_scheme => 1, error_app => sub { [403, [], ['Forbidden']] };
$app;
};
# or more simply(host from $env->{HTTP_HOST} and same_scheme => 0)
# this is vulnerabilly for DNS Rebinding
builder {
enable 'RefererCheck';
$app;
};
さて、コード中にも書いてあるように後者のチェック用hostをHTTP_HOSTから取得する方法はDNS-Rebindingに脆弱です。しかし前者のように固定hostを設定することにより、DNS-Rebindingへの対策も同時にできることになります。尚、onetime token方式ではXHRのsame originポリシーの崩壊によりDNS-Rebindingへの対策を単体で行うことはできません。
このようにRefererCheckを固定hostで行うことによりCSRF対策においてはDNS-Rebindingに対応できますが、CSRFから保護されるページ以外についても当然DNS-Rebindingでのアクセスははじきたいところです。apache等においてはname base virtual hostを活用することにより、期待するホスト名以外のアクセスをはじくことができますが、PlackでもPlack::App::URLMap(mount)を使うことにより同様のことが可能です。
use Plack::Builder;
builder {
mount 'http://example.com/' => builder {
mount '/app' => $app;
mount '/admin' => $admin_app;
}
}
このようにすることにより、example.com以外のHOSTでのアクセスは404となります。mountは上記の例のように、hostの指定とpath_infoの指定を同時に行えるもので、apacheでいうとVirtualhostとLocationを一緒にしたような機能になります。なので、上記のコードは下記のコードと等価です。
use Plack::Builder;
builder {
mount 'http://example.com/app/' => $app;
mount 'http://example.com/admin/' => $admin_app;
}
もちろんホスト名を違うものをmountできますのでPlack単体でVirtualhostな運用もできます。URLMap便利ですね。
Plack::Middleware::Header
- 2009/12/3 木曜日 23:19:23
- perl
Plack::Middleware::Headerをgithubに上げました。
これは、Plack::Middlewareレイヤーでレスポンスヘッダを設定するもので、Apacheでいうところのmod_headersに相当します。
使い方はこんな感じです。
use Plack::Builder;
builder {
enable 'Header',
set => ['X-Plack-One' => '1'],
append => ['X-Plack-Two' => '2'],
unset => ['X-Plack-Three'];
$app;
};
自分はPlack::Middleware::Staticと併用してExpiresをつけたりするのに使うために作りました。IEがExpires: -1とかやっておかないとしばらくキャッシュしてIf-Modifled-Sinceなリクエストも投げてくれなくなっちゃうという弊害があったので。
あと、IE関連では、If-Modified-Sinceの値に”;length=***”という余計なものが付いてきてしまい(ここやここを参照)、Middleware::ConditionalGETを有効にしても304を吐けなかったりしていたので、それを取り除くためのMiddlewareも書いてみました。こちらは名前とかがきもいのでgistレベル。
追記(2009-12-13 21:27): cpanにアップしました。あと、If-Modified-SinceのIEバグの件はmiyagawaさんがConditionalGET側で対応してくれました
- 検索
- フィード
- メタ情報