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.
本当に恐い
パフォーマンスが悪い実装
Masakazu Nagaya
2013年09月14日(土曜日)
Overview
• 大規模サイトでパフォーマンスを著しく劣
化させる非効率な実装例や、その改善例
を紹介します。
2
アジェンダ
• はじめに
• パフォーマンスが悪い実装の紹介
• 失敗を繰り返さないために
• まとめ
3
はじめに
4
誰でも失敗する
• プログラムを書く全ての人間がスーパー
プログラマーではない
• 常に完璧で失敗をしない人間はいない
• 失敗は必ず発生する
5
大切なこと
• 失敗から目をそむけない
• 失敗を隠さない(共有する)
• 失敗を繰り返さない
6
パフォーマンスが悪い実装の紹介
7
その1
• リソースの確保と解放のタイミングと回数
に要注意
8
問題の実装
9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
class BlackListDB {
const DBPATH = "/tmp/db.gdbm";
public function...
問題点
10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
class BlackListDB {
const DBPATH = "/tmp/db.gdbm";
public function ...
改善した実装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
class BlackListDB {
const DBPATH = "/tmp/db.gdbm";
p...
ポイント
• isBlock()の数だけopenされると遅くなる
• openの処理コストも内部でシステムコー
ル(open/mmap)を呼ぶので大きい
• 無駄な処理を減らす
12
検証方法
• テストコードをサーバ上に配置
ツールによる負荷テストを実施
13
1
2
3
4
5
6
7
8
<?php
$num = isset($_REQUEST["num"]) ? intval($_REQUEST["num"]) : ...
比較
14
更なる改善
• リクエスト毎に毎回Open/Closeするのは
もったいない
15
更に改善した実装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
class BlackListDB {
const DBPATH = "/tmp/db.gdbm";
private $_d...
Persistent Resources とは
• プロセス単位でオープンしたリソースを永
続的に保持し、次回のリクエストで再利用
する
• Persistent Resourcesの例
sqlite_popen(), pfsockopen()...
Life Cycle
18
MINIT
RINIT
Script Execution
RSHUTDOWN
RINIT
Script Execution
RSHUTDOWN
RINIT
Script Execution
RSHUTDOWN
MSH...
その2
• 大量のdefineによる問題
19
問題の実装
1
2
3
4
5
128
129
130
<?php
define(“XXXXX_ERR", 0);
define("XXXXX_OK", 1);
define("XXXXX_WANT_MORE_TEXT", 2);
define...
問題点
21
• defineは処理コストが大きく、リクエスト毎
にdefineが実行される
MINIT
RINIT
Script Execution
RSHUTDOWN
RINIT
Script Execution
RSHUTDOWN
RIN...
改善した実装
234
235
236
237
238
239
240
241
242
243
348
349
350
351
PHP_MINIT_FUNCTION(xxxxx)
{
/* If you have INI entries, unc...
ポイント
23
• エクステンションで利用する定数はエクス
テンションの起動時(MINIT)で定義する
MINIT
RINIT
Script Execution
RSHUTDOWN
RINIT
Script Execution
RSHUTDOW...
比較
24
その他の改善方法
• hidefを活用するのが良い
25
hidefとは
• iniファイルから定数を一括定義する
• MINITの処理で定数を定義する
• リクエスト毎に処理しないので効率的
26
その3
• ホスト名取得(exec)による問題
27
問題の実装
28
1
2
3
<?php
$hostname = exec("hostname");
printf("%s¥ n", $hostname);
問題点
• 激おこぷんぷんまるレベル
29
問題点
• プロセスの生成コストは非常に大きい
• Preforkの設計努力も台無し
• セキュリティ的な観点からも外部コマンド
が実行はすべきでない
30
改善した実装
31
1
2
3
<?php
$hostname = gethostname();
printf("%s¥ n", $hostname);
ポイント
32
• PHP5.3以降でサポートされた標準の
gethostname()を使用する
• 外部コマンドは絶対に使わない
比較
33
失敗を繰り返さないために
34
継続的なテストの実行の必要性
• 良い習慣はツールの支援なしに継続する
ことは難しい
• どんな賢人であっても魔が差すとテストを
省くときがある
35
ツールの支援で解決する
• Yahoo! JAPANで標準的に使われている
36
例えばパフォーマンステストを自動化
し結果を可視化する
37
大切なこと
• コミット、ビルド、テスト、リリースのプロセ
スを自動化するためにツールを活用し、
人に依存する過ちを減らすこと
38
まとめ
39
まとめ
• 実行回数が多くなる処理に注意しよう
• どんな達人でも必ずミスをするし
• どんな賢人でも魔が差すとテストを省く
• ツールの支援による継続的なテストは課
題解決のための良い方法の1つです
40
41
Upcoming SlideShare
Loading in …5
×

本当に怖いパフォーマンスが悪い実装 #phpcon2013

34,346 views

Published on

(PHPカンファレンス2013での発表内容です) Yahoo! JAPANほどの大規模サイトにおいては、小さなコードでも圧倒的に使われることで大量のコストを生み出します。実例を交えて非効率な実装と、その改善例を紹介します。

Published in: Technology
  • Be the first to comment

本当に怖いパフォーマンスが悪い実装 #phpcon2013

  1. 1. 本当に恐い パフォーマンスが悪い実装 Masakazu Nagaya 2013年09月14日(土曜日)
  2. 2. Overview • 大規模サイトでパフォーマンスを著しく劣 化させる非効率な実装例や、その改善例 を紹介します。 2
  3. 3. アジェンダ • はじめに • パフォーマンスが悪い実装の紹介 • 失敗を繰り返さないために • まとめ 3
  4. 4. はじめに 4
  5. 5. 誰でも失敗する • プログラムを書く全ての人間がスーパー プログラマーではない • 常に完璧で失敗をしない人間はいない • 失敗は必ず発生する 5
  6. 6. 大切なこと • 失敗から目をそむけない • 失敗を隠さない(共有する) • 失敗を繰り返さない 6
  7. 7. パフォーマンスが悪い実装の紹介 7
  8. 8. その1 • リソースの確保と解放のタイミングと回数 に要注意 8
  9. 9. 問題の実装 9 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php class BlackListDB { const DBPATH = "/tmp/db.gdbm"; public function isBlock($id) { $dbh = dba_open(self::DBPATH, "r", "gdbm"); if ($dbh === false) { return null; } $ret = dba_exists($id, $dbh); dba_close($dbh); return $ret; } }
  10. 10. 問題点 10 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php class BlackListDB { const DBPATH = "/tmp/db.gdbm"; public function isBlock($id) { $dbh = dba_open(self::DBPATH, "r", "gdbm"); if ($dbh === false) { return null; } $ret = dba_exists($id, $dbh); dba_close($dbh); return $ret; } }
  11. 11. 改善した実装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php class BlackListDB { const DBPATH = "/tmp/db.gdbm"; private $_dbh = null; function __construct() { $this->_dbh = dba_open(self::DBPATH, "r", "gdbm"); } public function isBlock($id) { if ($this->_dbh === false) { return null; } return dba_exists($id, $this->_dbh); } function __destruct() { dba_close($this->_dbh); } } 11
  12. 12. ポイント • isBlock()の数だけopenされると遅くなる • openの処理コストも内部でシステムコー ル(open/mmap)を呼ぶので大きい • 無駄な処理を減らす 12
  13. 13. 検証方法 • テストコードをサーバ上に配置 ツールによる負荷テストを実施 13 1 2 3 4 5 6 7 8 <?php $num = isset($_REQUEST["num"]) ? intval($_REQUEST["num"]) : 128; $obj = new BlackListDB(); for($i = 0;$i < $num; $i++) { $id = "dummy_id_".$i; printf("%s => %d¥ n", $id, $obj->isBlock($id)); }
  14. 14. 比較 14
  15. 15. 更なる改善 • リクエスト毎に毎回Open/Closeするのは もったいない 15
  16. 16. 更に改善した実装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php class BlackListDB { const DBPATH = "/tmp/db.gdbm"; private $_dbh = null; function __construct() { $this->_dbh = dba_popen(self::DBPATH, "r", "gdbm"); } public function isBlock($id) { if ($this->_dbh === false) { return null; } return dba_exists($id, $this->_dbh); } } 16
  17. 17. Persistent Resources とは • プロセス単位でオープンしたリソースを永 続的に保持し、次回のリクエストで再利用 する • Persistent Resourcesの例 sqlite_popen(), pfsockopen(), oci_pconnect(), mysql_pconnect() など 17 (PHP5.5ではmysql_pconnectは廃止されます。代替の関数を利用すべきです)
  18. 18. Life Cycle 18 MINIT RINIT Script Execution RSHUTDOWN RINIT Script Execution RSHUTDOWN RINIT Script Execution RSHUTDOWN MSHUTDOWN Apache Child Process リソース確保 再利用 再利用 リソース解放
  19. 19. その2 • 大量のdefineによる問題 19
  20. 20. 問題の実装 1 2 3 4 5 128 129 130 <?php define(“XXXXX_ERR", 0); define("XXXXX_OK", 1); define("XXXXX_WANT_MORE_TEXT", 2); define("XXXXX_NO_MORE_TEXT", 3); // snip define("XXXXX_YURAGI", 0x0002); define("XXXXX_DOGIGO", 0x0004); define("XXXXX_USRDEF", 0x0040); 20
  21. 21. 問題点 21 • defineは処理コストが大きく、リクエスト毎 にdefineが実行される MINIT RINIT Script Execution RSHUTDOWN RINIT Script Execution RSHUTDOWN RINIT Script Execution RSHUTDOWN MSHUTDOWN 定義処理 定義処理 定義処理
  22. 22. 改善した実装 234 235 236 237 238 239 240 241 242 243 348 349 350 351 PHP_MINIT_FUNCTION(xxxxx) { /* If you have INI entries, uncomment these lines ZEND_INIT_MODULE_GLOBALS(xxxxx, xxxxx_init_globals, NULL); REGISTER_INI_ENTRIES(); */ REGISTER_LONG_CONSTANT( "XXXXX_ERR", 0, CONST_CS|CONST_PERSISTENT ); REGISTER_LONG_CONSTANT( "XXXXX_OK", 1, CONST_CS|CONST_PERSISTENT ); REGISTER_LONG_CONSTANT( "XXXXX_WANT_MORE_TEXT", 2, CONST_CS|CONST_PERSISTENT ); REGISTER_LONG_CONSTANT( "XXXXX_NO_MORE_TEXT", 3, CONST_CS|CONST_PERSISTENT ); // snip REGISTER_LONG_CONSTANT( "XXXXX_KUGIRI", 0x0001, CONST_CS|CONST_PERSISTENT ); REGISTER_LONG_CONSTANT( "XXXXX_YURAGI", 0x0002, CONST_CS|CONST_PERSISTENT ); REGISTER_LONG_CONSTANT( "XXXXX_DOGIGO", 0x0004, CONST_CS|CONST_PERSISTENT ); REGISTER_LONG_CONSTANT( "XXXXX_USRDEF", 0x0040, CONST_CS|CONST_PERSISTENT ); 22
  23. 23. ポイント 23 • エクステンションで利用する定数はエクス テンションの起動時(MINIT)で定義する MINIT RINIT Script Execution RSHUTDOWN RINIT Script Execution RSHUTDOWN MSHUTDOWN 定義処理
  24. 24. 比較 24
  25. 25. その他の改善方法 • hidefを活用するのが良い 25
  26. 26. hidefとは • iniファイルから定数を一括定義する • MINITの処理で定数を定義する • リクエスト毎に処理しないので効率的 26
  27. 27. その3 • ホスト名取得(exec)による問題 27
  28. 28. 問題の実装 28 1 2 3 <?php $hostname = exec("hostname"); printf("%s¥ n", $hostname);
  29. 29. 問題点 • 激おこぷんぷんまるレベル 29
  30. 30. 問題点 • プロセスの生成コストは非常に大きい • Preforkの設計努力も台無し • セキュリティ的な観点からも外部コマンド が実行はすべきでない 30
  31. 31. 改善した実装 31 1 2 3 <?php $hostname = gethostname(); printf("%s¥ n", $hostname);
  32. 32. ポイント 32 • PHP5.3以降でサポートされた標準の gethostname()を使用する • 外部コマンドは絶対に使わない
  33. 33. 比較 33
  34. 34. 失敗を繰り返さないために 34
  35. 35. 継続的なテストの実行の必要性 • 良い習慣はツールの支援なしに継続する ことは難しい • どんな賢人であっても魔が差すとテストを 省くときがある 35
  36. 36. ツールの支援で解決する • Yahoo! JAPANで標準的に使われている 36
  37. 37. 例えばパフォーマンステストを自動化 し結果を可視化する 37
  38. 38. 大切なこと • コミット、ビルド、テスト、リリースのプロセ スを自動化するためにツールを活用し、 人に依存する過ちを減らすこと 38
  39. 39. まとめ 39
  40. 40. まとめ • 実行回数が多くなる処理に注意しよう • どんな達人でも必ずミスをするし • どんな賢人でも魔が差すとテストを省く • ツールの支援による継続的なテストは課 題解決のための良い方法の1つです 40
  41. 41. 41

×