SlideShare a Scribd company logo
ウェブアプリケーションの
パフォーマンスチューニング
2010/11/20 Kansai.pm#13
id:onishi / Hatena
自己紹介
大西康裕
id:onishi
@yasuhiro_onishi
株式会社はてな チーフエンジニア 
二児の父
自己紹介 - 最近つくったもの 
はてなキーワード リダイレクト機能
Devel::KYTProf
https://github.com/onishi/perl5-devel-kytprof
仮面ライダーオーズのお面
最近つくったもの 
最近つくったもの 
最近つくったもの 
Coming soon ...
ウェブアプリケーションのパフォーマンス
劣化しますよね…
PV増
機能追加
不具合
アプリケーション
ネットワーク
アジェンダ
今日する話
パフォーマンス計測
ボトルネック調査
実例など
今日しない話
SQL改善、キャッシュ、クライアント改善…
パフォーマンスチューニングフロー
大きなところから粒度を細かくして掘り下げていく
1. 自分のサイトは遅いのか
2. どのページがどんな条件で遅いのか
3. 遅い原因はどこにあるのか
アプリケーション?
ネットワーク?
外部原因? (APIなど)
4. 原因を取り除く / キャッシュを行う
ボトルネックをみつけるまでが大変><
レスポンスタイム計測
Apacheの場合
LogFormat %D でアクセスログに レスポンスタイム(マイクロ秒)を
表示できる
LogFormat "%h %t "%r" %D"
123.123.123.123 [20/Nov/2010:01:02:03 +0900]
"GET /path/to/hoge HTTP/1.1" 1021
レスポンスタイム計測 - HTTPヘッダ
ウェブアプリケーションから情報を出力する(はてなではWAFに実
装)
アプリケーションの処理速度
ディスパッチ結果
$ curl -I 'http://mono.hatena.ne.jp/' | grep 'X-'
X-Framework: Ridge/0.1 Plack/0.9937
X-Runtime: 423ms
X-Ridge-Dispatch: Hatena::Monolith::Engine::Index#default
レスポンスタイム計測 - HTTPヘッダ
LogFormat "%h %t "%r" "%{X-Ridge-Dispatch}o" %D"
123.123.123.123 [20/Nov/2010:01:02:03 +0900] "GET / HTTP/1.1"
"Hatena::Monolith::Engine::Index#default" 1021
%{レスポンスヘッダ名}o で reverse proxy のログにディスパッチ
結果をレスポンスタイムと共に記録
レスポンスタイム計測 - グラフ化#1
レスポンスタイム 分布
レスポンスタイム計測 - グラフ化#2
レスポンスタイム 推移 (日)
レスポンスタイム計測 - グラフ化#3
レスポンスタイム 推移 (時間)
グラフから読み取ること
サービスの応答速度
応答速度の変化 (劣化)
条件による応答速度の違い
URL / ディスパッチ先
リクエストメソッド
時間帯
遅い原因を調査する - run.pl
$ perl server.pl -p 3000
# Webサーバーとして動作する
$ perl run.pl http://d.hatena.ne.jp/onishi/
# 1リクエストだけ処理する
プロファイリングしやすい
-d オプションを入れてプロファイラを実行
cron で定時実行して継続プロファイル
Devel::NYTProf
http://search.cpan.org/dist/Devel-NYTProf/
$ perl -d:NYTProf run.pl http://d.hatena.ne.jp/onishi/
# nytprof.out というファイルができる
$ nytprofhtml
# nytprof というディレクトリができる
DEMO
Devel::NYTProf
よくある重い原因
正規表現
動的に生成しない。コンパイルオプション
$` $' を使わない
オブジェクト生成コスト (DateTime ...)
利用頻度の高いUtility関数
速い段階で抜けられないか
Devel::NYTProf - 実例
sub sanitize {
my $str = shift;
$str =~ s/&(?![#a-zA-Z0-9_]{2,6};)/&/g;
$str =~ s/</&lt;/g;
$str =~ s/>/&gt;/g;
$str =~ s/"/&quot;/g;
$str =~ s/'/&#39;/g;
$str =~ s//&#92;/g;
return $str;
}
Devel::NYTProf - 実例
Devel::NYTProf - 実例
sub sanitize {
my $str = shift;
$str =~ /[&<>"']/ or return $str;
$str =~ s/&(?![#a-zA-Z0-9_]{2,6};)/&amp;/g;
$str =~ s/</&lt;/g;
$str =~ s/>/&gt;/g;
$str =~ s/"/&quot;/g;
$str =~ s/'/&#39;/g;
$str =~ s//&#92;/g;
return $str;
}
Devel::NYTProf - 実例
Devel::NYTProf - tips
DB::disable_profile()
# モジュールのロード
DB::enable_profile()
# 計測したい処理
run.pl でのプロファイルは mod_perl などの永続環境でないため、
モジュールのロード(コンパイル, import) 処理が計測されてしまうの
でそれを抑制する
Devel::KYTProf
https://github.com/onishi/perl5-devel-kytprof
$ perl -d:KYTProf run.pl http://d.hatena.ne.jp/onishi/
ボトルネックの大半はネットワークIO!!
use するだけでネットワークIOの発生するメソッドの実行時間と呼
び出し元をwarnする
DBI
LWP
Cache::Memcached::Fast
…
DEMO
Devel::KYTProf - add_prof(s)
use Devel::KYTProf;
Devel::KYTProf->add_prof(
'Foo::Bar',
'baz',
sub { },
);
# Foo::Bar クラスの baz メソッドを計測対象に
Devel::KYTProf->add_profs(
'Foo::Bar',
[qw/baz piyo/]
);
Devel::KYTProf - options
Devel::KYTProf->namespace_regex('Hatena::Diary');
# caller を指定名前空間まで遡る
Devel::KYTProf->threshold(100); # (ms)
# n ms 以上かかった処理だけを出力する
Devel::KYTProf->logger(Some::Logger->new);
Devel::KYTProf->mute('DBI', 'connect');
Devel::KYTProf->unmute('DBI', 'connect');
Devel::KYTProf でわかること
ネットワークIOが何回発生しているか
コードのどこで発生しているか
どれだけ時間がかかっているか
処理の内容
よくある改善ポイント
重複している処理
インデックスの効いていないSQL
同期的なAPIのレスポンスが悪い
不要なネットワークIO
キャッシュにより逆に遅くなるケース
get/setの数が多いけどヒット率が低くて意味が無い…
継続プロファイリング
0 * * * * perl -d:KYTProf run.pl http://d.hatena.ne.
jp/onishi/ >> /var/log/profile.log 2>&1
毎時実行して記録を残す
日々のパフォーマンスの状況を残す
一時的な問題があった時に後から何があったか眺めたり
パフォーマンス改善の効果を確かめたり
まとめ
ウェブアプリのパフォーマンスを計測しよう
継続プロファイリングして劣化を気にしよう
大きな粒度から眺めてボトルネックを特定していこう
NYTProf超便利
ネットワークIOに特化したKYTProfも使ってね
はてなダイアリー速度改善
今やってます><
ご期待ください!!
ブックマークもやってます!!
ご清聴ありがとうございました

More Related Content

ウェブアプリケーションのパフォーマンスチューニング