本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回は面白法人カヤックでWebアプリケーションの運用、
パフォーマンスチューニングとは
カヤックではWebアプリケーションはもちろん、
「Webアプリケーションのパフォーマンスチューニング」
チューニングイベントの結果から
2011年からWebアプリケーションのチューニングイベントとして、
この2つのイベントの結果をまとめると、
イベント名 | 初期スコア | 優勝スコア | 改善率 |
---|---|---|---|
チューニンガソン#1 | 約120秒 | 約22秒 | 約6倍 |
チューニンガソン#2 | 約0. | 約3. | 約5倍 |
チューニンガソン#3 | 約21 | 約60 | 約3倍 |
チューニンガソン#4 | 約2. | 約1,351. | 約500倍 |
ISUCON | 約800 クエリ/分 | 約90,700 クエリ/分 | 約100倍 |
大きな効果を上げるために
チューニンガソン#1~#3の改善率を見ると、
つまりチューニングでは、
ボトルネックの発見と解消が大事
システム全体の処理時間についてパレートの法則
そのボトルネックはシステムによってまちまちです。データベースの設定であったり、
以降では、
システムの現状を知る
パフォーマンスチューニングが必要な場合、
『ハイパフォーマンスWebサイト』
エンドユーザーの応答時間のうち、
HTML文書のダウンロードにかかる時間は10%から20%にすぎない。残りの80%から90%はページ内のすべてのコンポーネントをダウンロードするのに消費される。
── Steve Souders著/
『ハイパフォーマンスWebサイト―高速サイトを実現する14のルール』
オライリー・
Google ChromeのPageSpeed拡張などを利用し、
各種メトリクスの収集
フロントエンド側ではなく、
チューニングを行う場合の鉄則ですが、
プロダクション環境では普通に行われていることと思いますが、
- CPU使用率
- メモリ使用率
- ネットワーク帯域・
パケット数 - ディスクI/
O - HTTPリクエスト数
- データベース、
KVS (Key-Value Store) などに対する発行クエリ数
レスポンスタイムの計測
Webアプリケーションへのリクエストに対してレスポンスタイムを計測して可視化することで、
- 突発的な現象で、
短時間だけレスポンスタイムが悪化した - 日時が経つにつれて徐々に性能が劣化している
- ある時点のデプロイ後、
障害になるほどではないが性能劣化が認められる
死活監視として、
チューニングする際の指標となるデータとして、
nginxの設定例
Webサーバがnginxの場合、$request_
をログに記録できます。$request_
はnginxがリクエストを受け取りはじめてからレスポンスをクライアントに返しきるまでの時間$upstream_
がリバースプロキシとして動作する場合に、
それに加えてリスト1のように$upstream_
も同時に記録することで、
log_format main
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$request_time" "$upstream_response_time" '
'"$upstream_addr"';
Apacheの設定例
WebサーバがApacheの場合、LogFormat
の書式に%Dを使用することで処理にかかった時間
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %D" combined_time
Apacheをリバースプロキシとして動作させた場合には、$upstream_
相当の処理時間を記録する方法がありません。代替として、X-Runtime: 1.
などと出力してログに記録する方法があります$upstream_
と完全に等価ではありません。
PSGIで動作するアプリケーションでは、X-Runtime
ヘッダを出力できます。
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %D %{X-Runtime}o" combined_runtime
レスポンスタイムの可視化
ログファイルに記録しただけでは状態を一目で把握できないため、
多数のホストに記録されたログファイルを収集、
Fluentd でアクセスログをパースし、
リスト1の設定でnginxから出力したアクセスログをパースし、$request_
をZabbixへ送信する例はリスト4のようになります。
<source>
type tail
path /var/log/nginx/access.log
tag access_log
format /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) [(?<time>[^]]
*)] "(?<method>S+)(?: +(?<path>[^ ]*) +S*)?" (?<code>[^ ]*)
(?<size>[^ ]*) "(?<referer>[^"]*)" "(?<agent>[^"]*)"
"(?<request_time>[^"]*)"/ 実際は1 行
time_format %d/%b/%Y:%H:%M:%S %z
</source>
<match access_log>
type numeric_counter
unit minute
tag numcount.response_time
count_key request_time
pattern1 0_10ms 0 0.01
pattern2 10_100ms 0.01 0.1
pattern3 100_500ms 0.1 0.5
pattern4 500_1000ms 0.5 1
pattern5 1_2s 1 3
pattern6 3_5s 3 6
pattern7 6_9s 6 10
pattern8 over_10s 10
</match>
<match numcount.**>
type zabbix
zabbix_server localhost
host www.example.com
name_key_pattern .*m?s_percentage
</match>
この例では、

<続きの