PHP factor 30 Linux与Windows的性能差异

PHP factor 30 Linux与Windows的性能差异,php,linux,windows,wordpress,performance,Php,Linux,Windows,Wordpress,Performance,我们的团队正在开发WordPress插件,并在两个独立的服务器上提供托管实例。我们的WordPress安装由Git管理,所有服务器都部署了相同的源和WordPress安装程序,只有数据库中的域和实际数据不同。对于每个安装,MySql都在同一台主机上运行。WordPress只在每台服务器上运行 然而,在Windows Server 2008 RC2上部署此设置后,我们注意到与其他服务器相比,性能有很大的差异:使用PHP生成的页面的生成时间从平均400ms增加到4000-5000ms。对于仅由Apa

我们的团队正在开发WordPress插件,并在两个独立的服务器上提供托管实例。我们的WordPress安装由Git管理,所有服务器都部署了相同的源和WordPress安装程序,只有数据库中的域和实际数据不同。对于每个安装,MySql都在同一台主机上运行。WordPress只在每台服务器上运行

然而,在Windows Server 2008 RC2上部署此设置后,我们注意到与其他服务器相比,性能有很大的差异:使用PHP生成的页面的生成时间从平均400ms增加到4000-5000ms。对于仅由Apache提供的静态资源,速度与linux上的大致相同

因此,我们采取了一些措施来缩小问题的范围:

  • 确保没有运行抗病毒软件或其他windows域内容
  • 在脚本执行期间收集分析数据以识别计时器
  • 测试不同的服务器和硬件设置
  • 仔细检查Apache和PHP配置是否存在明显的配置错误
  • 经过一些分析之后,我们很快注意到正则表达式的计算在我们的windows机器上非常慢。在Linux上评估10.000个正则表达式(
    preg_match
    )大约需要90毫秒,在Windows上需要3000毫秒

    下面提供了分析、系统测试和配置详细信息我们不想优化这个脚本(我们确实知道怎么做)。我们希望让脚本在windows上运行的速度与在Linux上运行的速度大致相同(假定opcache/的设置相同)。也不需要优化脚本的内存占用

    更新:一段时间后,系统似乎内存不足,引发内存不足异常和随机分配。有关更多详细信息,请参见下文。重新启动Apache/PHP暂时解决了这个问题

    \u get\u浏览器的跟踪是:

    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:出于某种原因,我不记得我们在服务器上重新激活PHP作为Apache模块(同样的模块会带来糟糕的性能)。但今天,它们运行速度极快(~1秒/请求)。添加Opcache可将其降低到约400ms/req。Apache/PHP/Windows保持不变

    1)分析结果

    在所有机器上都使用XDebug进行了分析。通常我们只收集了几次运行—这些运行足以显示大部分时间(50%+)的位置:WordPress插件的方法
    [get_browser][1]

    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
    检测浏览器的功能和操作系统。大部分脚本执行时间都花在这个
    foreach
    循环中,用于评估所有那些
    preg\u match
    (每页请求大约8000-10000)。在Linux上大约需要90毫秒,在Windows上需要3000毫秒。所有测试设置的结果相同(图中显示了两次执行的数据):

    当然,加载两个巨大的阵列需要一些时间。也计算正则表达式。但我们希望它们在Linux和Windows上所用的时间大致相同。这是linux vm上的评测结果(仅一页请求)。差别非常明显:

    另一个时间杀手实际上是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次脚本执行):

    在linux上:

    最后一个真正的杀手是翻译。在WordPress中,从内存加载的每个翻译需要0.2ms到4ms的时间:

    在linux上:

    2)经过测试的系统

    为了确保虚拟化或Apache确实会影响这一点,我们在几个设置上对此进行了测试。已在所有设置上禁用了抗病毒:

    • Linux Debian、Apache2和PHP的最新稳定版本。对于在虚拟机中运行的开发人员来说,这与对于临时/实时服务器来说是一样的。作为期望性能的参考系统。要么在我们的办公室里运行,要么在一些托管提供的地方运行(共享空间)。Windows系统有4GB到8GB的RAM,内存使用率一直低于50%。虚拟化永远不会同时运行Windows和Apache
    • 在VMWare Player上的T-Systems(托管虚拟化服务器)上运行的Life服务器
      • 赢得2008 R2。Apache2.2.25+PHP5.4.26 NTS,VC9作为fastcgi模块
      • 赢得2008 R2。Apache2.2.25+PHP5.5.1NTS,VC11作为fastcgi模块
      • 赢得2008 R2。Apache 2.2.25+PHP5.5.1 NTS,VC11作为Apache模块
      • Win2008R2、Apache2.2.25+PHP5.5.11TS、VC11作为Apache模块(这是我在更新2中提到的快速模块)
    • 在本地计算机上,主机:OpenSuse,虚拟化:VMWare player,与@T-Systems相同。为避免其基础设施影响我们:
      • 赢得2008 R2。Apache2.2.25+PHP5.4.26 NTS,VC9作为fastcgi模块
      • 赢得2008 R2。IIS7+PHP 5.4.26 NTS,VC9作为fastcgi模块(带或不带wincache)
      • 赢得2012年。IIS*+PHP 5.5.10 NTS,VC11作为fastcgi模块(带或不带wincache)
    • 在没有虚拟化的本地计算机上
      • 赢得2008 R2。Apache2.2.25+PHP5.4.26 NTS,VC9作为fastcgi模块
    上述分析结果在不同的系统上是相同的(约10%的偏差)。Windows总是比Linux慢的一个重要因素

    使用新安装的WordPress&Slimstats获得了大致相同的结果。在这里,重写代码不是一个选项

    更新:与此同时,我们发现了另外两个Windows系统(都是Windows 2008 R2、VM和Phys),整个堆栈运行速度非常快。但配置相同

    更新2:在Life服务器上以apache模块的形式运行PHP比fastcgi方法稍微快一点:低至2秒,减少50%

    内存不足

    几分钟后
    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) 
    
    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"
    
    <IfModule mpm_winnt_module>
        ThreadsPerChild 150
        ThreadStackSize 8388608 
        MaxConnectionsPerChild 0
    </IfModule>
    
    realpath_cache_size = 12M
    pcre.recursion_limit = 100000