PHP因子30从Linux到Windows的性能差异

Fge*_*Fge 37 php linux windows wordpress performance

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

但是,在Windows Server 2008 RC2上部署此设置后,我们发现与其他服务器相比,性能差异显着:页面生成时间从平均值上升.使用PHP生成的页面为400ms到4000-5000ms.对于Apache提供的静态资源,速度与linux上的速度大致相同.

所以我们采取了一些措施来缩小问题范围:

  1. 确保没有运行的防病毒软件或其他Windows域内容干扰
  2. 收集分析数据以在脚本执行期间识别时间杀手
  3. 测试不同的服务器和硬件设置
  4. 仔细检查Apache和PHP配置是否存在明显的配置错误

经过一些分析后,我们很快发现我们的Windows机器上正则表达式的评估速度非常慢.评估10.000正则表达式(preg_match)在Linux上大约需要90ms,在Windows上需要3000ms.

下面提供了分析,系统测试和配置细节.我们不想优化这个脚本(我们知道该怎么做).我们希望脚本在Windows上以与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)
Run Code Online (Sandbox Code Playgroud)

更新2:某些原因我不记得我们回到激活PHP作为我们服务器上的Apache模块(同样会导致性能不佳).但今天他们跑得非常快(约1秒/请求).添加Opcache可以将其降低到~400ms/req.Apache/PHP/Windows保持不变.

1)分析结果

在所有机器上使用XDebug进行分析.通常我们只收集了一些运行 - 这些足以显示大部分时间(50%以上)花费的位置:[get_browser][1]WordPress插件的方法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
  }
Run Code Online (Sandbox Code Playgroud)

此功能类似于PHP,可get_browser检测浏览器的功能和操作系统.大多数脚本执行时间都花在这个foreach循环中,评估所有这些preg_match(每页请求大约8000 - 10000).这在Linux上大约需要90ms,在Windows上需要3000ms.所有测试设置的结果都相同(图片显示了两次执行的数据):

IIS8上的wp_slimstat :: _ get_browser分析结果

当然,加载两个巨大的阵列需要一些时间.也评估正则表达式.但我们希望它们在Linux和Windows上花费大致相同的时间.这是linux vm上的分析结果(仅限一页请求).差异非常明显:

在此输入图像描述

另一个时间杀手实际上是Object-Cache 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;
}
Run Code Online (Sandbox Code Playgroud)

时间花在这个函数本身(3个脚本执行):

在此输入图像描述

在linux上:

在此输入图像描述

最后一个真正的大时代杀手是翻译.从内存加载的每个翻译在WordPress中从0.2ms到4ms不等: 在此输入图像描述

在linux上:

在此输入图像描述

2)经过测试的系统

为了确保虚拟化或Apache确实影响了这一点,我们在几个设置上对此进行了测试.所有设置都禁用了Antivir:

  • 关于最新稳定版本的Linux Debian,Apache 2和PHP.对于在其虚拟机中运行的开发人员和分段/实时服务器,这是相同的.充当期望性能的参考系统.要么在我们的办公室运行,要么在某些托管服务(共享空间)运行.Windows系统有4GB到8GB的RAM,随时内存使用率低于50%.虚拟化从不同时运行Windows和Apache.
  • 生命服务器,在VMWare Player上运行在T-Systems(托管虚拟化服务器)上
    • 赢得2008 R2.Apache 2.2.25 + PHP 5.4.26 NTS,VC9作为fastcgi模块
    • 赢得2008 R2.Apache 2.2.25 + PHP 5.5.1 NTS,VC11作为fastcgi模块
    • 赢得2008 R2.Apache 2.2.25 + PHP 5.5.1 NTS,VC11作为apache模块
    • Win 2008 R2,Apache 2.2.25 + PHP 5.5.11 TS,VC11作为apache模块(这是我在更新2中提到的快速模块)
  • 在本地计算机上,Host:OpenSuse,Virtualization:VMWare player,与@ T-Systems相同.为了避免他们的基础设施影响我们:
    • 赢得2008 R2.Apache 2.2.25 + PHP 5.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.Apache 2.2.25 + PHP 5.4.26 NTS,VC9作为fastcgi模块

如上所述的分析结果在不同系统上是相同的(~10%推导).Windows总是比Linux慢的重要因素.

使用全新安装的WordPress和Slimstats导致约.相同的结果.这里不能重写代码.

更新:同时我们发现另外两个Windows系统(Windows 2008 R2,VM和Phys),这个完整的堆栈运行速度非常快.但是配置相同.

更新2:在Life-Servers上运行PHP作为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) 
Run Code Online (Sandbox Code Playgroud)

这发生在随机脚本位置.显然,Zend内存管理器无法分配更多内存,尽管允许脚本这样做.当事件发生时,服务器有大约50%的空闲RAM(2GB +).所以服务器实际上没有用完ram.重启Apache/PHP现在解决了这个问题.

不确定此问题是否与此处的性能问题有关.然而,由于这两个问题似乎都与记忆有关,因此将其纳入此处.特别是我们将尝试重现提供良好性能的Windows-Tests的设置.

3)Apache和PHP配置

...可能没有任何常见的陷阱.输出缓冲启用(默认),禁用多重覆盖,...如果有任何选项感兴趣,我们将很乐意提供它们.

输出 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"
Run Code Online (Sandbox Code Playgroud)

mpm_winnt_module 组态:

<IfModule mpm_winnt_module>
    ThreadsPerChild 150
    ThreadStackSize 8388608 
    MaxConnectionsPerChild 0
</IfModule>
Run Code Online (Sandbox Code Playgroud)

php.ini的摘录:

realpath_cache_size = 12M
pcre.recursion_limit = 100000
Run Code Online (Sandbox Code Playgroud)

4)目前可疑的原因

旧假设:

这三个例子都很大程度上依赖于大数组和字符串操作.某种似乎是常见的工厂.由于Linux上的实现工作正常,我们怀疑这是Windows上的内存问题.鉴于在指针位置没有数据库交互,我们不怀疑数据库或服务器< - > PHP集成是问题.不知何故,PHP的内存交互似乎很慢.也许有人干扰Windows上的内存使访问速度显着降低?

旧假设2:

由于同一堆栈在其他Windows机器上运行良好,我们认为问题出在Windows配置中.

新假设3:

其实我没有假设.为什么运行PHP会像fastcgi那样慢得多,因为apache模块>

有关如何验证这个或在这里找到真正问题的任何想法?任何有关解决此问题的帮助或指示都非常受欢迎.

Tol*_*oly 9

Windows在许多情况下都有许多限制,防止,保护,控制和使用计算机的服务/策略.

一位优秀的Microsoft认证专家将能够在几分钟内解决您的问题,因为他们将有经验确切地说明要检查和禁用/启用/更改设置的设置/服务/策略,以便更快地执行PHP脚本.

出于我的记忆,我只建议你检查所有涉及RAM,硬盘访问,环境变量,限制和安全性(如防火墙)的内容.所有可能影响php脚本执行的东西,从一些远程过程调用策略开始,到操作堆栈内存结束.

逻辑是,php.exe调用一些外部.dll文件来执行某些操作,可能会检查操作系统完成的方式,这将减慢通过此类.dll发送请求的速度,并从中接收响应.如果.dll使用硬盘驱动器访问某些内容 - 硬盘驱动器访问策略进入场景.此外,所有内容如何位于内存中 - 在RAM的RAM或硬盘驱动器缓存中.应用政策.线程策略.限制可用于应用程序的最大百分比.

我并不是说基于Windows的主机很糟糕,只是为普通管理员设置它们要困难得多.如果您手头有Microsoft专家,他可以将您的服务器调整为与基于Linux的服务器一样快.