web-dev-qa-db-ja.com

PHP LinuxからWindowsへのファクター30のパフォーマンスの違い

私たちのチームは、WordPressプラグインを開発し、独立したいくつかのサーバーでホストされたインスタンスを提供しています。WordPressインストールはGitによって管理され、すべてのサーバーはsource&WordPressセットアップが展開され、ドメインとデータベース内の実際のデータのみが異なります。インストールごとに、MySqlは同じホストで実行されます。WordPressは排他的に実行されます各サーバー上。

ただし、このセットアップをWindows Server 2008 RC2に展開した後、他のサーバーと比較してパフォーマンスが大幅に異なることに気付きました。ページ生成時間は平均よりも長くなります。 PHPで生成されたページの場合、400ミリ秒から4000-5000ミリ秒。 Apacheのみが提供する静的リソースの場合、速度はLinuxとほぼ同じです。

そこで、問題を絞り込むためにいくつかの手順を実行しました。

  1. 実行中のantivir-softwareや他のWindowsドメインが干渉していないことを確認してください
  2. スクリプト実行中にタイムキラーを特定するためのプロファイリングデータを収集する
  3. さまざまなサーバーとハードウェアのセットアップをテストする
  4. 明らかな構成エラーについては、ApacheとPHPの両方の構成を再確認してください

プロファイリングをいくつか行った後、Windowsマシンでは正規表現の評価がひどく遅いことがすぐにわかりました。 10.000正規表現(preg_match)の評価には、Linuxで約90ミリ秒、Windowsで3000ミリ秒かかります。

プロファイリング、システムテスト、および構成の詳細を以下に示します。 このスクリプトを最適化したくありません(方法は知っています)。Linuxとほぼ同じ速度でスクリプトを実行するようにしたい(opcacheに関して同じ設定を与えた/ ...)。スクリプトのメモリフットプリントも最適化する必要はありません。

更新:しばらくすると、システムがメモリ不足になり、メモリ不足の例外とランダム割り当てがトリガーされるようです。詳細については、以下を参照してください。 Apache/PHPを再起動すると、今のところ問題が修正されました。

_get_browserへのトレースは次のとおりです。

File (called from)
require wp-blog-header.php (index.php:17)
wp (wp-blog-header.php:14)
WP->main (functions.php:808)
php::do_action_ref_array (class-wp.php:616)
php::call_user_func_array (wp-includes/plugin:507)
wp_slimstat::slimtrack  (php::internal (507))
wp_slimstat::_get_browser (wp-slimstat.php:385)

更新2:何らかの理由で、サーバー上のApacheモジュールとしてPHPを有効にしたことを思い出せません(パフォーマンスが低下するのと同じです)。 Opcacheを追加すると、これは約400ms/reqになりますが、Apache/PHP/Windowsは同じままです。

1)プロファイリング結果

プロファイリングは、すべてのマシンでXDebugを使用して行われました。通常、数回の実行のみを収集しました-ほとんどの時間(50%+)が費やされた場所を明らかにするのに十分でした:WordPress plugin [get_browser][1]のメソッドwp-slimstats

protected static function _get_browser(){
    // Load cache
    @include_once(plugin_dir_path( __FILE__ ).'databases/browscap.php');
    // browscap.php contains $slimstat_patterns and $slimstat_browsers

    $browser = array('browser' => 'Default Browser', 'version' => '1', 'platform' => 'unknown', 'css_version' => 1, 'type' => 1);
    if (empty($slimstat_patterns) || !is_array($slimstat_patterns)) return $browser;

    $user_agent = isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:'';
    $search = array();
    foreach ($slimstat_patterns as $key => $pattern){
        if (preg_match($pattern . 'i', $user_agent)){
            $search = $value = $search + $slimstat_browsers[$key];
            while (array_key_exists(3, $value) && $value[3]) {
                $value = $slimstat_browsers[$value[3]];
                $search += $value;
            }
            break;
        }
    }

    // Lots of other lines to relevant to the profiling results
  }

この関数は、PHPのget_browserと同様に、ブラウザーの機能とOSを検出します。スクリプトの実行時間のほとんどは、このforeachループに費やされ、それらのpreg_match(ページリクエストごとに約8000-10000)をすべて評価します。これには、Linuxでは約90ms、Windowsでは3000msかかります。テストしたすべてのセットアップで結果は同じでした(写真は2回の実行のデータを示しています)。

wp_slimstat::_get_browser profiling results on IIS8

確かに、2つの巨大な配列の読み込みには時間がかかります。正規表現も評価します。しかし、LinuxとWindowsではほぼ同じ時間がかかると予想されます。これは、Linux VMでのプロファイリング結果です(1ページのリクエストのみ)。違いはかなり明白です:

enter image description here

別のタイムキラーは、実際にはオブジェクトキャッシュでしたWordPress使用:

function get( $key, $group = 'default', $force = false, &$found = null ) {
    if ( empty( $group ) )
        $group = 'default';

    if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
        $key = $this->blog_prefix . $key;

    if ( $this->_exists( $key, $group ) ) {
        $found = true;
        $this->cache_hits += 1;
        if ( is_object($this->cache[$group][$key]) )
            return clone $this->cache[$group][$key];
        else
            return $this->cache[$group][$key];
    }

    $found = false;
    $this->cache_misses += 1;
    return false;
}

この関数自体の中で時間がかかります(3スクリプト実行):

enter image description here

Linuxの場合:

enter image description here

最後の本当の大きな時間のキラーは翻訳でした。メモリからロードされた各翻訳には、WordPressで0.2msから4msまでの時間がかかります。 enter image description here

Linuxの場合:

enter image description here

2)テスト済みシステム

仮想化またはApacheがこれに影響することを確認するために、いくつかのセットアップでこれをテストしました。 Antivirはすべてのセットアップで無効にされました。

  • Linux Debian、Apache 2&PHP最新の安定リリース。これは、仮想マシンで実行している開発者にとって、ステージング/ライブサーバーと同じです。望ましいパフォーマンスの参照システムとして機能します。私たちのオフィスまたはホスティングプロバイダー(共有スペース)で実行します。Windowsシステムには4GB〜8GBのRAMがあり、常にメモリ使用量は50%以下でした。仮想化はWindowsとApacheを同時に実行することはありません。
  • VM-Player 上のT-Systems(管理された仮想化サーバー)で実行されているLife-Servers
    • 2008 R2に勝ちます。 Apache 2.2.25 + PHP 5.4.26 fastcgiモジュールとしてのNTS、VC9
    • 2008 R2に勝ちます。 Apache 2.2.25 + PHP 5.5.1 NTS、fastcgiモジュールとしてのVC11
    • 2008 R2に勝ちます。 Apache 2.2.25 + PHP 5.5.1 NTS、VC11 as Apache module
    • Win 2008 R2、Apache 2.2.25 + PHP 5.5.11 TS、VC11をApacheモジュールとして(アップデート2で言及した高速なものです))
  • ローカルマシンでは、ホスト:OpenSuse、仮想化:VMWareプレーヤー、@ T-Systemsと同じ。インフラストラクチャが私たちに影響を与えないようにするには:
    • 2008 R2に勝ちます。 Apache 2.2.25 + PHP 5.4.26 fastcgiモジュールとしてのNTS、VC9
    • 2008 R2に勝ちます。 IIS7 + PHP 5.4.26 NTS、fastcgiモジュールとしてのVC9(wincacheの有無にかかわらず)
    • Win 2012。IIS * + PHP 5.5.10 NTS、VC11をfastcgiモジュールとして(wincacheの有無にかかわらず)
  • 仮想化なしのローカルマシン
    • 2008 R2に勝ちます。 Apache 2.2.25 + PHP 5.4.26 fastcgiモジュールとしてのNTS、VC9

上記のプロファイリング結果は、異なるシステムで同じでした(最大10%の導出)。 Windowsは常にLinuxよりも遅い重要な要素でした。

WordPress&Slimstatsの新規インストールを使用すると、ほぼ同じ結果が得られました。コードの書き換えは、ここではオプションではありません。

更新:一方、この完全なスタックが非常に高速に実行される他の2つのWindowsシステム(Windows 2008 R2、VM&Physの両方))が見つかりました。

更新2:実行中PHP Life-Servers上のApacheモジュールはfastcgiメソッドよりもわずかに高速だったため、最大2秒まで、50%減少しました。

メモリ不足

しばらくすると、Live-Serverはまったく動作しなくなり、これらのメモリ不足例外が発生します。

PHP Fatal error:  Out of memory (allocated 4456448) (tried to allocate 136 bytes)
PHP Fatal error:  Out of memory (allocated 8650752) (tried to allocate 45 bytes) 
PHP Fatal error:  Out of memory (allocated 6815744) (tried to allocate 24 bytes) 

これは、ランダムなスクリプトの場所で発生します。 Zend Memory Managerは、これ以上のメモリを割り当てることはできませんが、スクリプトはそうすることを許可されます。インシデントが発生した時点で、サーバーには約50%の空きRAM(2GB +)がありました。したがって、サーバーは実際にRAMを使い果たしません。

この問題がパフォーマンスの問題に関連しているかどうかはわかりません。しかし、両方の問題はメモリに関連しているように見えるため、ここに含まれています。特に、適切なパフォーマンスを提供するWindowsテストの設定を再現しようとします。

)Apache&PHP設定

...おそらく一般的な落とし穴はありません。 Output-Bufferingは有効(デフォルト)、multibyeオーバーライドは無効、...興味のあるオプションがあれば、喜んで提供します。

httpd.exe -Vの出力

Server version: Apache/2.4.7 (Win32)
Apache Lounge VC10 Server built:   Nov 26 2013 15:46:56
Server's Module Magic Number: 20120211:27
Server loaded:  APR 1.5.0, APR-UTIL 1.5.3
Compiled using: APR 1.5.0, APR-UTIL 1.5.3
Architecture:   32-bit
Server MPM:     WinNT
  threaded:     yes (fixed thread count)
    forked:     no
Server compiled with....
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses disabled)
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=256
 -D HTTPD_ROOT="/Apache"
 -D SUEXEC_BIN="/Apache/bin/suexec"
 -D DEFAULT_PIDLOG="logs/httpd.pid"
 -D DEFAULT_SCOREBOARD="logs/Apache_runtime_status"
 -D DEFAULT_ERRORLOG="logs/error.log"
 -D AP_TYPES_CONFIG_FILE="conf/mime.types"
 -D SERVER_CONFIG_FILE="conf/httpd.conf"

mpm_winnt_module設定:

<IfModule mpm_winnt_module>
    ThreadsPerChild 150
    ThreadStackSize 8388608 
    MaxConnectionsPerChild 0
</IfModule>

Php.iniの抜粋:

realpath_cache_size = 12M
pcre.recursion_limit = 100000

4)現在の疑わしい理由

古い仮定:

3つの例はすべて、大きな配列と文字列操作に大きく依存しています。ある種は一般的な工場のようです。 Linuxでの実装は問題なく動作するため、これはWindowsのメモリの問題であると思われます。ピンポイントの場所でデータベースとのやり取りがない場合、データベースまたはサーバー<-> PHP統合が問題であるとは思われません。どういうわけかPHPのメモリのやり取りが遅いようです。 Windowsのメモリに干渉してアクセスを劇的に遅くしている可能性がありますか?

古い仮定2:

同じスタックが他のWindowsマシンでも問題なく動作するため、問題はWindows構成のどこかにあると想定しています。

新しい仮定3:

実際、私は仮定から外れています。なぜPHP Apacheモジュールよりfastcgiのようにはるかに遅い>

これを検証する方法、またはここで実際の問題を見つける方法についてのアイデアはありますか?この問題を解決するためのヘルプまたは指示は大歓迎です。

36
Fge

Windowsには、あらゆる状況でコンピューターの使用を制限、防止、保護、制御などする多くのサービス/ポリシーがあります。

優れたマイクロソフト認定スペシャリストは、数分以内にあなたの質問を解決することができます。彼らは、どの設定/サービス/ポリシーを確認し、設定を無効化/有効化/変更するかを正確に伝える経験があるため、PHPスクリプトはより速く実行されます。

私の記憶では、RAM、ハードドライブアクセス、環境変数、制限、セキュリティ(ファイアウォールなど)を扱うすべてのものをチェックすることをお勧めします。 PHPスクリプトの実行に影響を与える可能性のあるすべてのもの。いくつかのリモートプロシージャコールポリシーから始まり、動作中のスタックメモリで終わります。

ロジックは、php.exeが何らかの外部の.dllファイルを呼び出して何らかの操作を実行するというものです。OSによって行われる方法にチェックがあり、そのような.dllを介した要求の送信と応答の受信の両方が遅くなります。 .dllがハードドライブを使用して何かにアクセスする場合-ハードドライブアクセスポリシーがシーンに入ります。また、すべてがメモリ内に配置される方法-RAMまたはRAMのハードドライブキャッシュ。アプリケーションポリシー。スレッドポリシー。アプリケーションで使用可能な最大パーセンテージの制限。

Windowsベースのホストが悪いと言っているのではなく、一般的な管理者にとって適切にセットアップするのがはるかに難しいというだけです。マイクロソフトのスペシャリストがいる場合、彼はあなたのサーバーをLinuxベースのサーバーと同じ速度に調整することができます。

9
Toly
  • pHP5.4を使用する場合、APCを有効にします

    • aPCがオンのときに速度の向上に気付かない場合は、何かが誤って設定されています

      _[APC] extension=php_apc.dll apc.enabled=1 apc.shm_segments=1 apc.shm_size=128M apc.num_files_hint=7000 apc.user_entries_hint=4096 apc.ttl=7200 apc.user_ttl=7200_

  • オンのときにZend Opcodeを有効にするPHP 5.5

    _[Zend] zend_extension=ext/php_zend.dll zend_optimizerplus.enable=1 zend_optimizerplus.use_cwd=1 zend_optimizerplus.validate_timestamp=0 zend_optimizerplus.revalidate_freq=2
    zend_optimizerplus.revalidate_path=0 zend_optimizerplus.dups_fix=0 zend_optimizerplus.log_verbosity_level=1 zend_optimizerplus.memory_consumption=128 zend_optimizerplus.interned_strings_buffer=16 zend_optimizerplus.max_accelerated_files=2000 zend_optimizerplus.max_wasted_percentage=25 zend_optimizerplus.consistency_checks=0 zend_optimizerplus.force_restart_timeout=60 zend_optimizerplus.blacklist_filename= zend_optimizerplus.fast_shutdown=0 zend_optimizerplus.optimization_level=0xfffffbbf zend_optimizerplus.enable_slow_optimizations=1 opcache.memory_consumption=128 opcache.interned_strings_buffer=8 opcache.max_accelerated_files=10000 opcache.revalidate_freq=60 opcache.fast_shutdown=1 opcache.enable_cli=1
    _

  • disable Wordpress拡張機能を段階的に使用して、メモリ使用量のモンスターを見つける

  • wordpress:define('WP_MEMORY_LIMIT', '128M');を設定します(十分な画像変換プラグインを使用しない場合)
  • php.iniに無制限のメモリを設定しますini_set('memory_limit', -1);
  • xdebugを実行せずにプロファイルを作成すると、これはおかしく聞こえますが、デバッガー自体の影響は大きいです
  • _memory_get_usage_を使用し、システム全体に呼び出しを広げて、メモリリークが発生するコード位置を見つけます。
  • _zend.enable_gc=1_を試してください。スクリプトは遅くなりますが、使用するメモリは少なくなります
  • たぶん、SlimStats設定でユーザーブラウザのチェックを無効にするだけです。
  • それが不可能な場合は、SlimStats getBrowser()関数を faster getBrowser()代替 でオーバーライドしてください。
  • ユーザーエージェントフェッチャーの速度比較については、 https://github.com/quentin389/ua-speed-tests を参照してください
  • https://github.com/garetjax/phpbrowscap
4
Jens A. Koch

Githubでそのプラグインを見てみました:

https://github.com/wp-plugins/wp-slimstat

また、含まれている問題のあるファイルは、ある程度縮小されたファイルであり、実際にはデータ(コードではない)であり、それぞれ約400KBの5つのバリエーションがあります

400KBのmaxmind.datファイルもありますが、両方を使用するかどうかはわかりません。

プラグインの古いバージョンであるバージョン3.2.3を使用しており、問題を解決できる可能性のある新しいバージョンがあります。

作成者またはgit履歴を順番に保持していない人がいるので、違いを比較するのは難しいので、ファイルを手動で比較する必要がありました。 _get_browserに関連する変更のほとんどは、キャッシュを追加しているようです。

そのファイルの読み込みは解析が遅い可能性がありますが、PHP IOキャッシュが機能していることを条件に両方のプラットフォームで両方のファイルを同じレートで読み込むと期待します。

[〜#〜] edit [〜#〜]問題を解決できないかもしれない、もう少し詳しく見てみましょう。これらのファイルは基本的に大きな正規表現のルックアップテーブルです。 LinuxシステムにAPCキャッシュがありましたが、これにはありませんか? APCキャッシュは、おそらくPHPファイルデータをキャッシュします(ただし、コンパイル済みの正規表現パターンではありません))

2
Kristopher Ives

PHPではなくUNIXソケットを介して(TCPソケットではない)にNGINXおよびFCGIを使用します。

http://wiki.nginx.org/PHPFcgiExample

アクセラレータがなくても、すぐに速度が向上します。さらに、上記のセットアップでは、メモリ使用量がはるかに少なくなります。

1
mikikg

この種の問題をトラブルシューティングするには、次のことを行う必要があります。

  • システムログ、つまりエラーログを使用する:エラーレベルで並べ替える
    および/または日付で問題の日付を特定します。
  • いずれかのシステムで使用中のWindows更新プログラムを比較してください。そのうちの1つに問題がある可能性があります。
  • いずれかのシステムで使用中のソフトウェアを比較すると、これらのいずれかのセットアップに問題がある可能性があります。

その場合は、Windowsの更新プログラムや問題の原因となっているソフトウェアをアンインストールし、サーバーを完全にシャットダウンしてから、更新プログラムまたはソフトウェアを再インストールします(セットアップ中に安定した状態を確保するため)。

この問題のトラブルシューティングに役立つツールには、Sysinternals Suiteが含まれます。 http://technet.Microsoft.com/en-us/sysinternals/bb842062.aspx

もっと簡単に言うと、オープンソースのVBSスクリプトを使用して、システム上の更新とアプリケーションの比較可能なリストを作成します。

0
Mauro Colella