50
Webアプリケーションの パフォーマンス向上のコツ 実践編 ISUCON夏期講習 2014/8/20 Masahiro Nagano

Webアプリケーションの パフォーマンス向上のコツ 実践編

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Webアプリケーションの パフォーマンス向上のコツ 実践編

Webアプリケーションのパフォーマンス向上のコツ

実践編ISUCON夏期講習

2014/8/20Masahiro Nagano

Page 2: Webアプリケーションの パフォーマンス向上のコツ 実践編

午前3時ぐらいまで挑戦してみました

Page 3: Webアプリケーションの パフォーマンス向上のコツ 実践編

最終スコア

9246

Page 4: Webアプリケーションの パフォーマンス向上のコツ 実践編

やってみたことを紹介します

Page 5: Webアプリケーションの パフォーマンス向上のコツ 実践編

初期スコア

1664

Page 6: Webアプリケーションの パフォーマンス向上のコツ 実践編

(1) 環境整備

Page 7: Webアプリケーションの パフォーマンス向上のコツ 実践編

静的コンテンツをReverse Proxy で配信

Reverse Proxy: クライアントからの接続を受け、Applicationサーバに処理を中継する。画像,js,css などの静的コンテンツを返す役割もある

Application Server: ユーザからのリクエストを受けて適切なページを構築・レスポンスを行う

Page 8: Webアプリケーションの パフォーマンス向上のコツ 実践編

$ cat /etc/httpd/conf.d/isucon.conf <VirtualHost *:80> DocumentRoot /home/isu-user/isucon/webapp/public RewriteEngine on RewriteCond REQUEST_URI !^/favicon\.ico$ RewriteCond REQUEST_URI !^/(img|css|js)/ RewriteRule /(.*)$ http://localhost:5000/$1 [P]</VirtualHost>

command

Page 9: Webアプリケーションの パフォーマンス向上のコツ 実践編

スコア

1664 => 1719

Page 10: Webアプリケーションの パフォーマンス向上のコツ 実践編

Nginx 化

• オープンソースのWebサーバ。高速に動作し、メモリ使用量がすくないなどの特徴があります

Page 11: Webアプリケーションの パフォーマンス向上のコツ 実践編

Apache vs. Nginx

worker worker worker

worker worker worker

worker worker worker

リクエスト

コンテキストスイッチが大量発生

リクエスト

worker

1個のプロセスで効率よく通信を処理

Page 12: Webアプリケーションの パフォーマンス向上のコツ 実践編

$ sudo yum install nginx$ sudo service httpd stop

[program:nginx]directory=/command=/usr/sbin/nginx -c /home/isu-user/isucon/nginx.confautostart = true

command

run.ini

nginx.confはのちほど公開します

Page 13: Webアプリケーションの パフォーマンス向上のコツ 実践編

スコア

1719 => 1764

Page 14: Webアプリケーションの パフォーマンス向上のコツ 実践編

(2) Perl にしますワタシハパールチョットデキル

Page 15: Webアプリケーションの パフォーマンス向上のコツ 実践編

Perl の起動方法

command=/home/../isucon/env.sh carton exec --\ start_server --path /tmp/app.sock -- \ plackup -s Starlet \ --max-workers 4 \ --max-reqs-per-child 50000 \ -E production -a app.psgi

run.iniTCPではなくUNIX domain

socketを使う

プロセスを長生きさせる

プロセスはあげすぎない

Page 16: Webアプリケーションの パフォーマンス向上のコツ 実践編

TCPの接続は高コスト

ReverseProxy

AppServer

リクエスト毎にthree way handshake

Page 17: Webアプリケーションの パフォーマンス向上のコツ 実践編

スコア

1764 => 1891

Page 18: Webアプリケーションの パフォーマンス向上のコツ 実践編

(3) アプリをみよう

Page 19: Webアプリケーションの パフォーマンス向上のコツ 実践編

“/” “/recent/xxx”

“/memo/xxxx” “/mypage”

Page 20: Webアプリケーションの パフォーマンス向上のコツ 実践編

“/” “/recent/xxx”

“/memo/xxxx” “/mypage”

DBへの問い合わせが重い

markdown の変換にプロセス起動

DBへの問い合わせが若干重い

Page 21: Webアプリケーションの パフォーマンス向上のコツ 実践編

(4) 外部プロセス起動

Page 22: Webアプリケーションの パフォーマンス向上のコツ 実践編

+use Text::Markdown::Hoedown qw//;

sub markdown { my $content = shift;- my ($fh, $filename) = tempfile();- $fh->print(encode_utf8($content));- $fh->close;- my $html = qx{ ../bin/markdown $filename };- unlink $filename;- return $html;+ Text::Markdown::Hoedown::markdown($content) }

webapp/perl/lib/Isucon3/Web.pm

ここがmarkdownコマンドを起動している

“/memo/xxxx”

Page 23: Webアプリケーションの パフォーマンス向上のコツ 実践編

スコア

1891 => 2233

Page 24: Webアプリケーションの パフォーマンス向上のコツ 実践編

(5) N+1 クエリ

Page 25: Webアプリケーションの パフォーマンス向上のコツ 実践編

my $memos = $self->dbh->select_all( 'SELECT * FROM memos WHERE is_private=0 ORDER BY created_at DESC, id DESC LIMIT 100');

for my $memo (@$memos) { $memo->{username} = $self->dbh->select_one( 'SELECT username FROM users WHERE id=?', $memo->{user}, );}

webapp/perl/lib/Isucon3/Web.pm

100回ルーーーープ

“/”

Page 26: Webアプリケーションの パフォーマンス向上のコツ 実践編

use the join, luke

Page 27: Webアプリケーションの パフォーマンス向上のコツ 実践編

id user_id id name

memosテーブル usersテーブル

id user_id name

memos JOIN users ON memos.user_id = user.id

Page 28: Webアプリケーションの パフォーマンス向上のコツ 実践編

my $memos = $self->dbh->select_all( 'SELECT memos.*,users.username FROM memos JOIN users ON memos.user = users.id WHERE memos.is_private=0 ORDER BY memos.created_at DESC, memos.id DESC LIMIT 100');

webapp/perl/lib/Isucon3/Web.pm

“/”, “/recent”

Page 29: Webアプリケーションの パフォーマンス向上のコツ 実践編

スコア

2233 => 2398

Page 30: Webアプリケーションの パフォーマンス向上のコツ 実践編

(6) インデックス

Page 31: Webアプリケーションの パフォーマンス向上のコツ 実践編

SELECT * FROM memos WHERE is_private=0 ORDER BY created_at DESC LIMIT 100

id is_private

...

0

0

1

0

1

memosテーブル

id is_private

...

0

0

0

SORT

webapp/perl/lib/Isucon3/Web.pm

indexがないと

Page 32: Webアプリケーションの パフォーマンス向上のコツ 実践編

indexをつくる

cat <<'EOF' | mysql -u isucon isuconALTER TABLE memos ADD INDEX (is_private,created_at);EOF

init.sh

Page 33: Webアプリケーションの パフォーマンス向上のコツ 実践編

B-Tree

0 1is_private

created_at

older newer older newer

Page 34: Webアプリケーションの パフォーマンス向上のコツ 実践編

B-Tree

0 1is_private

created_at

older newer older newer

Page 35: Webアプリケーションの パフォーマンス向上のコツ 実践編

B-Tree

0 1is_private

created_at

older newer older newer

Page 36: Webアプリケーションの パフォーマンス向上のコツ 実践編

B-Tree

0 1is_private

created_at

older newer older newer

Page 37: Webアプリケーションの パフォーマンス向上のコツ 実践編

スコア

2398 => 2668

Page 38: Webアプリケーションの パフォーマンス向上のコツ 実践編

 (7) タイトル生成

Page 39: Webアプリケーションの パフォーマンス向上のコツ 実践編

これ

Page 40: Webアプリケーションの パフォーマンス向上のコツ 実践編
Page 41: Webアプリケーションの パフォーマンス向上のコツ 実践編

mysql> show create table memos\G*************************** 1. row *************************** Table: memosCreate Table: CREATE TABLE `memos` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user` int(11) NOT NULL, `content` text, `is_private` tinyint(4) NOT NULL DEFAULT '0', `created_at` datetime NOT NULL, `updated_at` timestamp NOT NULL DEFAULT, PRIMARY KEY (`id`),) ENGINE=InnoDB AUTO_INCREMENT=41311 DEFAULT CHARSET=utf81 row in set (0.00 sec)

mysql

titleカラムが存在しない!

Page 42: Webアプリケーションの パフォーマンス向上のコツ 実践編

<: $memo.content.split('\r?\n').first() :>webapp/perl/views/index.tx

splitでCPU使用contentの転送で通信

Page 43: Webアプリケーションの パフォーマンス向上のコツ 実践編

cat <<'EOF' | mysql -u isucon isuconALTER TABLE memos ADD COLUMN title text;UPDATE memos SET title = substring_index(content,"\n",1);EOF

init.sh

titleカラムの追加

Page 44: Webアプリケーションの パフォーマンス向上のコツ 実践編

POST時に保存$self->dbh->query(  'INSERT INTO memos

(user, title, content, is_private, created_at) VALUES (?, ?, ?, ?, now()) ', $user_id, (split /\r?\n/, $content)[0], $content, $is_private,);

webapp/perl/lib/Isucon3/Web.pm

Page 45: Webアプリケーションの パフォーマンス向上のコツ 実践編

my $memos = $self->dbh->select_all( 'SELECT memos.id, memos.title, memos.is_private, memos.created_at, users.username FROM memos JOIN users ON memos.user = users.id WHERE memos.is_private=0 ORDER BY memos.created_at DESC, memos.id DESC LIMIT 100');

webapp/perl/lib/Isucon3/Web.pm

“/”, “/recent”memos.* だと contentを取ってしまう

Page 46: Webアプリケーションの パフォーマンス向上のコツ 実践編

スコア

2668 => 3060

Page 47: Webアプリケーションの パフォーマンス向上のコツ 実践編

そして戦いは続く

Page 49: Webアプリケーションの パフォーマンス向上のコツ 実践編

“/mypage” のインデックス

Page 50: Webアプリケーションの パフォーマンス向上のコツ 実践編

以上。