Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

0 views

Published on

Published in: Internet

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

  1. 1. Webアプリケーションの パフォーマンス向上のコツ 実践編 ISUCON夏期講習 2014/8/20 Masahiro Nagano
  2. 2. 午前3時ぐらいまで 挑戦してみました
  3. 3. 最終スコア 9246
  4. 4. やってみたことを 紹介します
  5. 5. 初期スコア 1664
  6. 6. (1) 環境整備
  7. 7. 静的コンテンツを Reverse Proxy で配信 Reverse Proxy: クライアントからの接続を 受け、Applicationサーバに処理を中継す る。画像,js,css などの静的コンテンツを返す 役割もある Application Server: ユーザからのリクエス トを受けて適切なページを構築・レスポン スを行う
  8. 8. $ 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
  9. 9. スコア 1664 => 1719
  10. 10. Nginx 化 • オープンソースのWebサーバ。高速に動 作し、メモリ使用量がすくないなどの 特徴があります
  11. 11. Apache vs. Nginx worker worker worker worker worker worker worker worker worker リクエスト コンテキストスイッチが 大量発生 リクエスト worker 1個のプロセスで 効率よく通信を処理
  12. 12. $ sudo yum install nginx $ sudo service httpd stop [program:nginx] directory=/ command=/usr/sbin/nginx -c /home/isu-user/isucon/ nginx.conf autostart = true command run.ini nginx.confはのちほど公開します
  13. 13. スコア 1719 => 1764
  14. 14. (2) Perl にします ワタシハパールチョットデキル
  15. 15. 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.ini TCPではなくUNIXdomain socketを使う プロセスを長生きさせる プロセスはあげすぎない
  16. 16. TCPの接続は高コスト Reverse Proxy App Server リクエスト毎に threewayhandshake
  17. 17. スコア 1764 => 1891
  18. 18. (3) アプリをみよう
  19. 19. “/” “/recent/xxx” “/memo/xxxx” “/mypage”
  20. 20. “/” “/recent/xxx” “/memo/xxxx” “/mypage” DBへの問い合わせが重い markdownの変換に プロセス起動 DBへの問い合わせが 若干重い
  21. 21. (4) 外部プロセス起動
  22. 22. +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”
  23. 23. スコア 1891 => 2233
  24. 24. (5) N+1 クエリ
  25. 25. 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回ルーーーープ “/”
  26. 26. use the join, luke
  27. 27. id user_id id name memosテーブル usersテーブル id user_id name memos JOIN users ON memos.user_id = user.id
  28. 28. 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”
  29. 29. スコア 2233 => 2398
  30. 30. (6) インデックス
  31. 31. SELECT * FROM memos WHERE is_private=0 ORDER BY created_at DESC LIMIT 100 id is_priv ate ... 0 0 1 0 1 memosテーブル id is_priv ate ... 0 0 0 SORT webapp/perl/lib/Isucon3/Web.pm indexがないと
  32. 32. indexをつくる cat <<'EOF' | mysql -u isucon isucon ALTER TABLE memos ADD INDEX (is_private,created_at); EOF init.sh
  33. 33. B-Tree 0 1is_private created_at older newer older newer
  34. 34. B-Tree 0 1is_private created_at older newer older newer
  35. 35. B-Tree 0 1is_private created_at older newer older newer
  36. 36. B-Tree 0 1is_private created_at older newer older newer
  37. 37. スコア 2398 => 2668
  38. 38.  (7) タイトル生成
  39. 39. これ
  40. 40. mysql> show create table memosG *************************** 1. row *************************** Table: memos Create 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=utf8 1 row in set (0.00 sec) mysql titleカラムが存在しない!
  41. 41. <: $memo.content.split('r?n').first() :> webapp/perl/views/index.tx splitでCPU使用contentの転送で通信
  42. 42. cat <<'EOF' | mysql -u isucon isucon ALTER TABLE memos ADD COLUMN title text; UPDATE memos SET title = substring_index(content,"n",1); EOF init.sh titleカラムの追加
  43. 43. 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
  44. 44. 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を 取ってしまう
  45. 45. スコア 2668 => 3060
  46. 46. そして戦いは続く
  47. 47. Next Conan's HINT
  48. 48. “/mypage”の インデックス
  49. 49. 以上。

×